From 19500916dad1c35f0c3970605bf2813f0a4e97f1 Mon Sep 17 00:00:00 2001
From: "lee.5151" <lee.5151@osu.edu>
Date: Tue, 29 Nov 2022 12:03:52 -0500
Subject: [PATCH] Upgrading drupal/paragraphs (1.12.0 => 1.15.0)

---
 composer.json                                 |    2 +-
 composer.lock                                 |   53 +-
 vendor/composer/installed.json                |   65 +-
 vendor/composer/installed.php                 |   22 +-
 .../Compiler/DecoratorServicePass.php         |    2 +-
 .../Compiler/ServiceLocatorTagPass.php        |    4 +
 .../Factory/PsrHttpFactory.php                |    2 +-
 web/modules/paragraphs/README.txt             |   15 +-
 web/modules/paragraphs/composer.json          |   11 +-
 web/modules/paragraphs/css/README.md          |   40 +-
 web/modules/paragraphs/css/gulp-tasks.js      |    6 +-
 web/modules/paragraphs/css/package-lock.json  | 7185 +++++++++++++++++
 web/modules/paragraphs/css/package.json       |    2 +-
 .../paragraphs/css/paragraphs.modal.css       |    2 +-
 .../paragraphs/css/paragraphs.modal.scss      |    2 +-
 .../paragraphs/css/paragraphs.seven.css       |    4 +
 .../paragraphs/css/paragraphs.seven.scss      |    9 +
 .../paragraphs/css/paragraphs.widget.css      |   30 +-
 .../paragraphs/css/paragraphs.widget.scss     |   39 +-
 .../paragraphs/js/paragraphs.actions.js       |    6 +-
 .../js/paragraphs.add_above_button.js         |   50 +-
 web/modules/paragraphs/js/paragraphs.admin.js |   21 +-
 web/modules/paragraphs/js/paragraphs.modal.js |   10 +-
 .../migrations/d7_field_collection.yml        |   21 +
 .../d7_field_collection_revisions.yml         |   30 +
 .../migrations/d7_field_collection_type.yml   |    1 +
 .../paragraphs/migrations/d7_paragraphs.yml   |   21 +
 .../migrations/d7_paragraphs_revisions.yml    |   30 +
 .../migrations/d7_paragraphs_type.yml         |    1 +
 ....node.paragraphed_content_demo.default.yml |    5 -
 .../paragraphs_demo/paragraphs_demo.info.yml  |    8 +-
 .../src/Functional/ParagraphsDemoTest.php     |   20 +-
 ...y_item.paragraphs_library_item.summary.yml |    2 +-
 .../paragraphs_library.info.yml               |    8 +-
 .../paragraphs_library.module                 |    2 +-
 .../src/Controller/LibraryItemController.php  |    1 +
 .../src/Entity/LibraryItem.php                |    5 +
 .../src/Form/LibraryItemForm.php              |    4 +-
 .../Form/LibraryItemRevisionRevertForm.php    |    2 +-
 .../src/Form/LibraryItemSettingsForm.php      |    2 +-
 .../LibraryItemSummaryFormatter.php           |   48 +
 .../src/Routing/LibraryItemRouteProvider.php  |    7 +-
 .../Functional/MultilingualBehaviorTest.php   |  161 +-
 .../Functional/ParagraphsLibraryItemTest.php  |   40 +-
 .../ParagraphsLibraryItemTranslationTest.php  |   31 +-
 .../src/Functional/ParagraphsLibraryTest.php  |  144 +-
 .../ParagraphsContentModerationTest.php       |   72 +-
 ...ParagraphsLibraryItemEntityBrowserTest.php |   10 +-
 .../paragraphs_type_permissions.info.yml      |    8 +-
 .../ParagraphsTypePermissionsTest.php         |   27 +-
 web/modules/paragraphs/paragraphs.info.yml    |    8 +-
 .../paragraphs/paragraphs.libraries.yml       |   19 +-
 web/modules/paragraphs/paragraphs.module      |  125 +-
 .../paragraphs/paragraphs.post_update.php     |    2 +-
 .../paragraphs/paragraphs.services.yml        |    1 +
 .../paragraphs/src/Entity/Paragraph.php       |   10 +-
 .../paragraphs/src/Entity/ParagraphsType.php  |   15 +-
 .../src/Form/ParagraphsTypeDeleteConfirm.php  |    2 +
 .../src/Form/ParagraphsTypeForm.php           |    9 +-
 .../src/MigrationPluginsAlterer.php           |  150 +
 .../paragraphs/src/ParagraphInterface.php     |    2 +-
 .../src/ParagraphsBehaviorInterface.php       |    3 -
 .../src/ParagraphsServiceProvider.php         |    8 +
 .../src/ParagraphsTypeIconUuidLookup.php      |    1 +
 .../src/ParagraphsTypeInterface.php           |    4 +-
 .../ParagraphSelection.php                    |    2 +-
 .../FieldWidget/InlineParagraphsWidget.php    |   40 +-
 .../Field/FieldWidget/ParagraphsWidget.php    |   99 +-
 .../migrate/D7FieldCollectionItemDeriver.php  |  105 +
 .../migrate/D7ParagraphsItemDeriver.php       |   98 +
 .../Plugin/migrate/field/FieldCollection.php  |   59 +-
 .../src/Plugin/migrate/field/Paragraphs.php   |   73 +-
 .../FieldCollectionFieldInstanceSettings.php  |    2 +-
 .../migrate/process/ParagraphsLookup.php      |  235 +
 .../process/ParagraphsProcessOnValue.php      |    8 +-
 .../migrate/source/d7/FieldCollectionItem.php |    9 +-
 .../source/d7/FieldCollectionItemRevision.php |    4 +-
 .../migrate/source/d7/ParagraphsItem.php      |   59 +-
 .../source/d7/ParagraphsItemRevision.php      |   11 +-
 .../paragraphs-dropbutton-wrapper.html.twig   |    4 +-
 .../templates/paragraphs-summary.html.twig    |    4 +-
 .../fixtures/sites/default/files/Babylon5.txt |    1 +
 .../fixtures/sites/default/files/cube.jpeg    |    1 +
 .../fixtures/sites/default/files/ds9.txt      |   79 +
 .../paragraphs_test/paragraphs_test.info.yml  |    9 +-
 .../paragraphs_test/paragraphs_test.module    |    6 +-
 .../src/Form/TestEmbeddedEntityForm.php       |  104 +
 ...agraphsExperimentalReplicateEnableTest.php |   17 -
 .../Migrate/MigrateUiParagraphsTest.php       |   51 +
 .../Migrate/MigrateUiParagraphsTestBase.php   |  569 ++
 ...rsTest.php => ParagraphsBehaviorsTest.php} |   12 +-
 ...imentalUiTest.php => ParagraphsUiTest.php} |   41 +-
 .../Functional/ParagraphsUninstallTest.php    |   31 +-
 ...st.php => ParagraphsWidgetButtonsTest.php} |   21 +-
 .../ParagraphsAccessTest.php                  |   40 +-
 .../ParagraphsAddModesTest.php                |   16 +-
 .../ParagraphsAdministrationTest.php          |  234 +-
 .../ParagraphsConfigTest.php                  |   46 +-
 .../ParagraphsContactTest.php                 |    8 +-
 .../ParagraphsEditModesTest.php               |   35 +-
 ...anslationWithNonTranslatableParagraphs.php |   32 +-
 .../ParagraphsFieldGroupTest.php              |   17 +-
 .../ParagraphsInlineEntityFormTest.php        |   24 +-
 ...gacyContentModerationTranslationsTest.php} |   16 +-
 .../ParagraphsPreviewTest.php                 |   18 +-
 .../ParagraphsSummaryFormatterTest.php        |   19 +-
 .../ParagraphsTestBase.php                    |   38 +-
 .../ParagraphsTranslationTest.php             |  233 +-
 .../ParagraphsTypesTest.php                   |   22 +-
 .../ParagraphsUiTest.php                      |   20 +-
 .../ParagraphsWidgetButtonsTest.php           |   39 +-
 .../ParagraphsAccessTest.php}                 |   71 +-
 .../ParagraphsAddModesTest.php}               |   20 +-
 .../ParagraphsAdministrationTest.php}         |  217 +-
 .../ParagraphsAlterByTypeTest.php}            |    8 +-
 .../ParagraphsBehaviorsTest.php}              |   89 +-
 .../ParagraphsConfigTest.php}                 |   52 +-
 .../ParagraphsContactTest.php}                |   10 +-
 ...aphsContentModerationTranslationsTest.php} |   21 +-
 .../ParagraphsDragAndDropModeTest.php}        |   60 +-
 .../ParagraphsDuplicateFeatureTest.php}       |   60 +-
 .../ParagraphsEditModesTest.php}              |   94 +-
 ...nslationWithNonTranslatableParagraphs.php} |   34 +-
 .../ParagraphsFieldGroupTest.php}             |   19 +-
 .../ParagraphsHeaderActionsTest.php}          |   84 +-
 .../ParagraphsInlineEntityFormTest.php}       |   26 +-
 .../ParagraphsPreviewTest.php}                |   20 +-
 .../ParagraphsReplicateEnableTest.php         |   17 +
 .../ParagraphsSummaryFormatterTest.php}       |   21 +-
 .../ParagraphsTestBase.php}                   |    8 +-
 .../ParagraphsTranslationTest.php}            |  263 +-
 .../ParagraphsTranslationsTest.php}           |   19 +-
 .../ParagraphsTypesTest.php}                  |   34 +-
 .../ParagraphsUiTest.php}                     |   30 +-
 .../ParagraphsWidgetButtonsTest.php}          |   65 +-
 .../FunctionalJavascript/LoginAdminTrait.php  |    1 +
 ...etTest.php => ParagraphsAddWidgetTest.php} |   47 +-
 ...hp => ParagraphsClientsideButtonsTest.php} |   45 +-
 ...aragraphsStableEditPerspectivesUiTest.php} |   20 +-
 .../ParagraphsTestBaseTrait.php               |   14 +-
 ...t.php => ParagraphsWidgetElementsTest.php} |    9 +-
 .../tests/src/Kernel/ParagraphsAccessTest.php |    2 +-
 .../Kernel/ParagraphsBehaviorPluginsTest.php  |   15 +-
 .../Kernel/ParagraphsCollapsedSummaryTest.php |    5 +-
 .../ParagraphsCompositeRelationshipTest.php   |    4 +-
 .../Kernel/ParagraphsEntityMethodsTest.php    |    4 +-
 .../src/Kernel/ParagraphsIsChangedTest.php    |    4 +-
 .../Kernel/ParagraphsLangcodeChangeTest.php   |  384 +
 .../src/Kernel/ParagraphsReplicateTest.php    |    4 +-
 ...graphsTypeHasEnabledBehaviorPluginTest.php |    4 +-
 .../FieldCollectionItemRevisionSourceTest.php |    2 +-
 .../migrate/FieldCollectionItemSourceTest.php |    2 +-
 .../migrate/FieldCollectionTypeSourceTest.php |    2 +-
 .../migrate/ParagraphContentMigrationTest.php |  112 +
 .../migrate/ParagraphsFieldMigrationTest.php  |    5 +-
 .../ParagraphsItemRevisionSourceTest.php      |    4 +-
 .../migrate/ParagraphsItemSourceTest.php      |    6 +-
 .../migrate/ParagraphsMigrationTestBase.php   |   16 +-
 .../migrate/ParagraphsTypeMigrationTest.php   |    8 -
 .../migrate/ParagraphsTypeSourceTest.php      |    2 +-
 .../ParagraphsCoreVersionUiTestTrait.php      |   26 +-
 .../Traits/ParagraphsLastEntityQueryTrait.php |    1 +
 ...ParagraphsNodeMigrationAssertionsTrait.php |  136 +
 .../tests/src/Traits/ParagraphsSourceData.php |   26 +-
 .../FieldCollectionFieldSettingsTest.php      |    6 +-
 ...ldCollectionsFieldInstanceSettingsTest.php |    4 +-
 .../migrate/MigrationPluginsAltererTest.php   |  197 +
 .../ParagraphsFieldInstanceSettingsTest.php   |    4 +-
 .../migrate/ParagraphsFieldSettingsTest.php   |    6 +-
 .../migrate/ParagraphsProcessOnValueTest.php  |    2 +-
 .../src/Unit/migrate/ProcessTestCase.php      |    2 +-
 171 files changed, 11969 insertions(+), 1767 deletions(-)
 create mode 100644 web/modules/paragraphs/css/package-lock.json
 create mode 100644 web/modules/paragraphs/css/paragraphs.seven.css
 create mode 100644 web/modules/paragraphs/css/paragraphs.seven.scss
 create mode 100644 web/modules/paragraphs/migrations/d7_field_collection.yml
 create mode 100644 web/modules/paragraphs/migrations/d7_field_collection_revisions.yml
 create mode 100644 web/modules/paragraphs/migrations/d7_paragraphs.yml
 create mode 100644 web/modules/paragraphs/migrations/d7_paragraphs_revisions.yml
 create mode 100644 web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Field/FieldFormatter/LibraryItemSummaryFormatter.php
 create mode 100644 web/modules/paragraphs/src/MigrationPluginsAlterer.php
 create mode 100644 web/modules/paragraphs/src/Plugin/migrate/D7FieldCollectionItemDeriver.php
 create mode 100644 web/modules/paragraphs/src/Plugin/migrate/D7ParagraphsItemDeriver.php
 create mode 100644 web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsLookup.php
 create mode 100644 web/modules/paragraphs/tests/fixtures/sites/default/files/Babylon5.txt
 create mode 100644 web/modules/paragraphs/tests/fixtures/sites/default/files/cube.jpeg
 create mode 100644 web/modules/paragraphs/tests/fixtures/sites/default/files/ds9.txt
 create mode 100644 web/modules/paragraphs/tests/modules/paragraphs_test/src/Form/TestEmbeddedEntityForm.php
 delete mode 100644 web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
 create mode 100644 web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTest.php
 create mode 100644 web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTestBase.php
 rename web/modules/paragraphs/tests/src/Functional/{ParagraphsExperimentalBehaviorsTest.php => ParagraphsBehaviorsTest.php} (90%)
 rename web/modules/paragraphs/tests/src/Functional/{ParagraphsExperimentalUiTest.php => ParagraphsUiTest.php} (78%)
 rename web/modules/paragraphs/tests/src/Functional/{ParagraphsExperimentalWidgetButtonsTest.php => ParagraphsWidgetButtonsTest.php} (96%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsAccessTest.php (85%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsAddModesTest.php (95%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsAdministrationTest.php (72%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsConfigTest.php (85%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsContactTest.php (83%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsEditModesTest.php (76%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php (74%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsFieldGroupTest.php (74%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsInlineEntityFormTest.php (85%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic/ParagraphsClassicContentModerationTranslationsTest.php => WidgetLegacy/ParagraphsLegacyContentModerationTranslationsTest.php} (97%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsPreviewTest.php (87%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsSummaryFormatterTest.php (81%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsTestBase.php (82%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsTranslationTest.php (84%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsTypesTest.php (91%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsUiTest.php (87%)
 rename web/modules/paragraphs/tests/src/Functional/{Classic => WidgetLegacy}/ParagraphsWidgetButtonsTest.php (78%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalAccessTest.php => WidgetStable/ParagraphsAccessTest.php} (83%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalAddModesTest.php => WidgetStable/ParagraphsAddModesTest.php} (94%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalAdministrationTest.php => WidgetStable/ParagraphsAdministrationTest.php} (74%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalAlterByTypeTest.php => WidgetStable/ParagraphsAlterByTypeTest.php} (81%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalBehaviorsTest.php => WidgetStable/ParagraphsBehaviorsTest.php} (83%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalConfigTest.php => WidgetStable/ParagraphsConfigTest.php} (85%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalContactTest.php => WidgetStable/ParagraphsContactTest.php} (80%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php => WidgetStable/ParagraphsContentModerationTranslationsTest.php} (97%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalDragAndDropModeTest.php => WidgetStable/ParagraphsDragAndDropModeTest.php} (95%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalDuplicateFeatureTest.php => WidgetStable/ParagraphsDuplicateFeatureTest.php} (80%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalEditModesTest.php => WidgetStable/ParagraphsEditModesTest.php} (74%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php => WidgetStable/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php} (71%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalFieldGroupTest.php => WidgetStable/ParagraphsFieldGroupTest.php} (70%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalHeaderActionsTest.php => WidgetStable/ParagraphsHeaderActionsTest.php} (80%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalInlineEntityFormTest.php => WidgetStable/ParagraphsInlineEntityFormTest.php} (83%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalPreviewTest.php => WidgetStable/ParagraphsPreviewTest.php} (85%)
 create mode 100644 web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsReplicateEnableTest.php
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalSummaryFormatterTest.php => WidgetStable/ParagraphsSummaryFormatterTest.php} (77%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalTestBase.php => WidgetStable/ParagraphsTestBase.php} (81%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalTranslationTest.php => WidgetStable/ParagraphsTranslationTest.php} (83%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalTranslationsTest.php => WidgetStable/ParagraphsTranslationsTest.php} (95%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalTypesTest.php => WidgetStable/ParagraphsTypesTest.php} (78%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalUiTest.php => WidgetStable/ParagraphsUiTest.php} (82%)
 rename web/modules/paragraphs/tests/src/Functional/{Experimental/ParagraphsExperimentalWidgetButtonsTest.php => WidgetStable/ParagraphsWidgetButtonsTest.php} (84%)
 rename web/modules/paragraphs/tests/src/FunctionalJavascript/{ParagraphsExperimentalAddWidgetTest.php => ParagraphsAddWidgetTest.php} (94%)
 rename web/modules/paragraphs/tests/src/FunctionalJavascript/{ParagraphsExperimentalClientsideButtonsTest.php => ParagraphsClientsideButtonsTest.php} (89%)
 rename web/modules/paragraphs/tests/src/FunctionalJavascript/{ParagraphsExperimentalEditPerspectivesUiTest.php => ParagraphsStableEditPerspectivesUiTest.php} (95%)
 rename web/modules/paragraphs/tests/src/FunctionalJavascript/{ParagraphsExperimentalWidgetElementsTest.php => ParagraphsWidgetElementsTest.php} (91%)
 create mode 100644 web/modules/paragraphs/tests/src/Kernel/ParagraphsLangcodeChangeTest.php
 create mode 100644 web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphContentMigrationTest.php
 create mode 100644 web/modules/paragraphs/tests/src/Traits/ParagraphsNodeMigrationAssertionsTrait.php
 create mode 100644 web/modules/paragraphs/tests/src/Unit/migrate/MigrationPluginsAltererTest.php

diff --git a/composer.json b/composer.json
index a79cf4cb0c..faa78c64dd 100644
--- a/composer.json
+++ b/composer.json
@@ -146,7 +146,7 @@
         "drupal/module_filter": "3.2",
         "drupal/multiple_fields_remove_button": "^1.0@alpha",
         "drupal/pantheon_advanced_page_cache": "1.2",
-        "drupal/paragraphs": "1.12",
+        "drupal/paragraphs": "1.15",
         "drupal/pathauto": "1.11",
         "drupal/queue_mail": "^1.4",
         "drupal/realname": "^2.0@beta",
diff --git a/composer.lock b/composer.lock
index af6ea30619..c1ba16def0 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": "00b3339b124e176f69a985ebf27eaa8c",
+    "content-hash": "66825c008c7e0270cc8e1f922cb9b8d6",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -6194,33 +6194,32 @@
         },
         {
             "name": "drupal/paragraphs",
-            "version": "1.12.0",
+            "version": "1.15.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/paragraphs.git",
-                "reference": "8.x-1.12"
+                "reference": "8.x-1.15"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.12.zip",
-                "reference": "8.x-1.12",
-                "shasum": "3b67d8af1160af42d93a4610be1e02869e428965"
+                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.15.zip",
+                "reference": "8.x-1.15",
+                "shasum": "2ed2d3199553010fa1c500181bbebe676e9e60c1"
             },
             "require": {
-                "drupal/core": "^8.8 || ^9",
+                "drupal/core": "^9.3 || ^10",
                 "drupal/entity_reference_revisions": "~1.3"
             },
             "require-dev": {
-                "drupal/block_field": "~1.0",
-                "drupal/ctools": "3.x-dev",
-                "drupal/diff": "~1.0",
+                "drupal/block_field": "1.x-dev",
+                "drupal/diff": "1.x-dev",
                 "drupal/entity_browser": "2.x-dev",
                 "drupal/entity_usage": "2.x-dev",
                 "drupal/field_group": "3.x-dev",
-                "drupal/inline_entity_form": "~1.0",
+                "drupal/inline_entity_form": "1.x-dev",
                 "drupal/paragraphs-paragraphs_library": "*",
-                "drupal/replicate": "~1.0",
-                "drupal/search_api": "~1.0",
+                "drupal/replicate": "1.x-dev",
+                "drupal/search_api": "1.x-dev",
                 "drupal/search_api_db": "*"
             },
             "suggest": {
@@ -6229,8 +6228,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.12",
-                    "datestamp": "1590140081",
+                    "version": "8.x-1.15",
+                    "datestamp": "1661440897",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -13181,16 +13180,16 @@
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v4.4.44",
+            "version": "v4.4.49",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "25502a57182ba1e15da0afd64c975cae4d0a1471"
+                "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/25502a57182ba1e15da0afd64c975cae4d0a1471",
-                "reference": "25502a57182ba1e15da0afd64c975cae4d0a1471",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734",
+                "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734",
                 "shasum": ""
             },
             "require": {
@@ -13247,7 +13246,7 @@
             "description": "Allows you to standardize and centralize the way objects are constructed in your application",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/dependency-injection/tree/v4.4.44"
+                "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49"
             },
             "funding": [
                 {
@@ -13263,7 +13262,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-07-20T09:59:04+00:00"
+            "time": "2022-11-16T16:18:09+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",
@@ -15041,16 +15040,16 @@
         },
         {
             "name": "symfony/psr-http-message-bridge",
-            "version": "v2.1.3",
+            "version": "v2.1.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/psr-http-message-bridge.git",
-                "reference": "d444f85dddf65c7e57c58d8e5b3a4dbb593b1840"
+                "reference": "a125b93ef378c492e274f217874906fb9babdebb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/d444f85dddf65c7e57c58d8e5b3a4dbb593b1840",
-                "reference": "d444f85dddf65c7e57c58d8e5b3a4dbb593b1840",
+                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/a125b93ef378c492e274f217874906fb9babdebb",
+                "reference": "a125b93ef378c492e274f217874906fb9babdebb",
                 "shasum": ""
             },
             "require": {
@@ -15109,7 +15108,7 @@
             ],
             "support": {
                 "issues": "https://github.com/symfony/psr-http-message-bridge/issues",
-                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.3"
+                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.4"
             },
             "funding": [
                 {
@@ -15125,7 +15124,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-09-05T10:34:54+00:00"
+            "time": "2022-11-28T22:46:34+00:00"
         },
         {
             "name": "symfony/routing",
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index f5e3806242..ae4eebf790 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -6412,34 +6412,33 @@
         },
         {
             "name": "drupal/paragraphs",
-            "version": "1.12.0",
-            "version_normalized": "1.12.0.0",
+            "version": "1.15.0",
+            "version_normalized": "1.15.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/paragraphs.git",
-                "reference": "8.x-1.12"
+                "reference": "8.x-1.15"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.12.zip",
-                "reference": "8.x-1.12",
-                "shasum": "3b67d8af1160af42d93a4610be1e02869e428965"
+                "url": "https://ftp.drupal.org/files/projects/paragraphs-8.x-1.15.zip",
+                "reference": "8.x-1.15",
+                "shasum": "2ed2d3199553010fa1c500181bbebe676e9e60c1"
             },
             "require": {
-                "drupal/core": "^8.8 || ^9",
+                "drupal/core": "^9.3 || ^10",
                 "drupal/entity_reference_revisions": "~1.3"
             },
             "require-dev": {
-                "drupal/block_field": "~1.0",
-                "drupal/ctools": "3.x-dev",
-                "drupal/diff": "~1.0",
+                "drupal/block_field": "1.x-dev",
+                "drupal/diff": "1.x-dev",
                 "drupal/entity_browser": "2.x-dev",
                 "drupal/entity_usage": "2.x-dev",
                 "drupal/field_group": "3.x-dev",
-                "drupal/inline_entity_form": "~1.0",
+                "drupal/inline_entity_form": "1.x-dev",
                 "drupal/paragraphs-paragraphs_library": "*",
-                "drupal/replicate": "~1.0",
-                "drupal/search_api": "~1.0",
+                "drupal/replicate": "1.x-dev",
+                "drupal/search_api": "1.x-dev",
                 "drupal/search_api_db": "*"
             },
             "suggest": {
@@ -6448,8 +6447,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.12",
-                    "datestamp": "1590140081",
+                    "version": "8.x-1.15",
+                    "datestamp": "1661440897",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -6470,10 +6469,6 @@
                     "name": "Frans",
                     "homepage": "https://www.drupal.org/user/514222"
                 },
-                {
-                    "name": "Primsi",
-                    "homepage": "https://www.drupal.org/user/282629"
-                },
                 {
                     "name": "jeroen.b",
                     "homepage": "https://www.drupal.org/user/1853532"
@@ -6485,6 +6480,10 @@
                 {
                     "name": "miro_dietiker",
                     "homepage": "https://www.drupal.org/user/227761"
+                },
+                {
+                    "name": "Primsi",
+                    "homepage": "https://www.drupal.org/user/282629"
                 }
             ],
             "description": "Enables the creation of Paragraphs entities.",
@@ -13698,17 +13697,17 @@
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v4.4.44",
-            "version_normalized": "4.4.44.0",
+            "version": "v4.4.49",
+            "version_normalized": "4.4.49.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "25502a57182ba1e15da0afd64c975cae4d0a1471"
+                "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/25502a57182ba1e15da0afd64c975cae4d0a1471",
-                "reference": "25502a57182ba1e15da0afd64c975cae4d0a1471",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/9065fe97dbd38a897e95ea254eb5ddfe1310f734",
+                "reference": "9065fe97dbd38a897e95ea254eb5ddfe1310f734",
                 "shasum": ""
             },
             "require": {
@@ -13739,7 +13738,7 @@
                 "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
                 "symfony/yaml": ""
             },
-            "time": "2022-07-20T09:59:04+00:00",
+            "time": "2022-11-16T16:18:09+00:00",
             "type": "library",
             "installation-source": "dist",
             "autoload": {
@@ -13767,7 +13766,7 @@
             "description": "Allows you to standardize and centralize the way objects are constructed in your application",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/dependency-injection/tree/v4.4.44"
+                "source": "https://github.com/symfony/dependency-injection/tree/v4.4.49"
             },
             "funding": [
                 {
@@ -15627,17 +15626,17 @@
         },
         {
             "name": "symfony/psr-http-message-bridge",
-            "version": "v2.1.3",
-            "version_normalized": "2.1.3.0",
+            "version": "v2.1.4",
+            "version_normalized": "2.1.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/psr-http-message-bridge.git",
-                "reference": "d444f85dddf65c7e57c58d8e5b3a4dbb593b1840"
+                "reference": "a125b93ef378c492e274f217874906fb9babdebb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/d444f85dddf65c7e57c58d8e5b3a4dbb593b1840",
-                "reference": "d444f85dddf65c7e57c58d8e5b3a4dbb593b1840",
+                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/a125b93ef378c492e274f217874906fb9babdebb",
+                "reference": "a125b93ef378c492e274f217874906fb9babdebb",
                 "shasum": ""
             },
             "require": {
@@ -15658,7 +15657,7 @@
             "suggest": {
                 "nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
             },
-            "time": "2022-09-05T10:34:54+00:00",
+            "time": "2022-11-28T22:46:34+00:00",
             "type": "symfony-bridge",
             "extra": {
                 "branch-alias": {
@@ -15698,7 +15697,7 @@
             ],
             "support": {
                 "issues": "https://github.com/symfony/psr-http-message-bridge/issues",
-                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.3"
+                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.4"
             },
             "funding": [
                 {
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index 1299061afa..40b2bf6daf 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' => 'ba6af3568d179c683bcb49150597c4f6eb32e14e',
+        'reference' => '7b38d41b8b6ae95e9b0320d434f2220a4367f2d9',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -1064,9 +1064,9 @@
             'dev_requirement' => false,
         ),
         'drupal/paragraphs' => array(
-            'pretty_version' => '1.12.0',
-            'version' => '1.12.0.0',
-            'reference' => '8.x-1.12',
+            'pretty_version' => '1.15.0',
+            'version' => '1.15.0.0',
+            'reference' => '8.x-1.15',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/paragraphs',
             'aliases' => array(),
@@ -1594,7 +1594,7 @@
         'osu-asc-webservices/d8-upstream' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => 'ba6af3568d179c683bcb49150597c4f6eb32e14e',
+            'reference' => '7b38d41b8b6ae95e9b0320d434f2220a4367f2d9',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -2190,9 +2190,9 @@
             'dev_requirement' => false,
         ),
         'symfony/dependency-injection' => array(
-            'pretty_version' => 'v4.4.44',
-            'version' => '4.4.44.0',
-            'reference' => '25502a57182ba1e15da0afd64c975cae4d0a1471',
+            'pretty_version' => 'v4.4.49',
+            'version' => '4.4.49.0',
+            'reference' => '9065fe97dbd38a897e95ea254eb5ddfe1310f734',
             'type' => 'library',
             'install_path' => __DIR__ . '/../symfony/dependency-injection',
             'aliases' => array(),
@@ -2403,9 +2403,9 @@
             'dev_requirement' => false,
         ),
         'symfony/psr-http-message-bridge' => array(
-            'pretty_version' => 'v2.1.3',
-            'version' => '2.1.3.0',
-            'reference' => 'd444f85dddf65c7e57c58d8e5b3a4dbb593b1840',
+            'pretty_version' => 'v2.1.4',
+            'version' => '2.1.4.0',
+            'reference' => 'a125b93ef378c492e274f217874906fb9babdebb',
             'type' => 'symfony-bridge',
             'install_path' => __DIR__ . '/../symfony/psr-http-message-bridge',
             'aliases' => array(),
diff --git a/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php b/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
index 3b8086d093..185a097ebe 100644
--- a/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
+++ b/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php
@@ -42,7 +42,7 @@ public function process(ContainerBuilder $container)
 
         $tagsToKeep = $container->hasParameter('container.behavior_describing_tags')
             ? $container->getParameter('container.behavior_describing_tags')
-            : ['container.do_not_inline', 'container.service_locator', 'container.service_subscriber'];
+            : ['container.do_not_inline', 'container.service_locator', 'container.service_subscriber', 'container.service_subscriber.locator'];
 
         foreach ($definitions as [$id, $definition]) {
             $decoratedService = $definition->getDecoratedService();
diff --git a/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php b/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
index 5fdbe5686d..72b093043b 100644
--- a/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
+++ b/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php
@@ -39,6 +39,10 @@ protected function processValue($value, $isRoot = false)
             return self::register($this->container, $value->getValues());
         }
 
+        if ($value instanceof Definition) {
+            $value->setBindings(parent::processValue($value->getBindings()));
+        }
+
         if (!$value instanceof Definition || !$value->hasTag('container.service_locator')) {
             return parent::processValue($value, $isRoot);
         }
diff --git a/vendor/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php b/vendor/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php
index 61650df9f6..b1b6f9ae26 100644
--- a/vendor/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php
+++ b/vendor/symfony/psr-http-message-bridge/Factory/PsrHttpFactory.php
@@ -142,7 +142,7 @@ public function createResponse(Response $symfonyResponse)
                     $stream->write($buffer);
 
                     return '';
-                });
+                }, 1);
 
                 $symfonyResponse->sendContent();
                 ob_end_clean();
diff --git a/web/modules/paragraphs/README.txt b/web/modules/paragraphs/README.txt
index c4e36a8079..e2eff04187 100644
--- a/web/modules/paragraphs/README.txt
+++ b/web/modules/paragraphs/README.txt
@@ -18,18 +18,19 @@ WIDGETS
 
 Paragraphs currently provides two different widgets that can be used.
 
- * Classic: a stable UI with limited features that will not be changed or
-   updated.
+ * Legacy (formerly Classic): a stable UI with limited features that will not be
+   changed or updated.
 
- * Experimental: This widget provides additional features like duplicating
-   paragraphs and a drag & drop mode (see below) as well a improved user
-   experience. It is just as well tested as the classic UI but major changes
-   between versions are to be expected.
+ * Stable (formerly Experimental): This widget provides additional features like
+   duplicating paragraphs and a drag & drop mode (see below) as well a improved
+   user experience. It is now the default and recommended widget, but changes
+   between versions are to be expected and customizations might need to be
+   updated.
 
 Drag & drop
 -------------
 
-The experimental widget offers a separate mode that allows to re-sort paragraphs
+The stable widget offers a separate mode that allows to re-sort paragraphs
 not just within the same level but it is also possible to change the hierarchy
 and move paragraphs including their children around and into other paragraphs.
 
diff --git a/web/modules/paragraphs/composer.json b/web/modules/paragraphs/composer.json
index c65f9072b6..6bf7b1847a 100644
--- a/web/modules/paragraphs/composer.json
+++ b/web/modules/paragraphs/composer.json
@@ -10,14 +10,13 @@
     "drupal/entity_browser": "Recommended for an improved user experience when using the Paragraphs library module"
   },
   "require-dev": {
-    "drupal/diff": "~1.0",
-    "drupal/replicate": "~1.0",
-    "drupal/inline_entity_form": "~1.0",
+    "drupal/diff": "1.x-dev",
+    "drupal/replicate": "1.x-dev",
+    "drupal/inline_entity_form": "1.x-dev",
     "drupal/field_group": "3.x-dev",
-    "drupal/block_field": "~1.0",
-    "drupal/ctools": "3.x-dev",
+    "drupal/block_field": "1.x-dev",
     "drupal/entity_browser": "2.x-dev",
     "drupal/entity_usage": "2.x-dev",
-    "drupal/search_api": "~1.0"
+    "drupal/search_api": "1.x-dev"
   }
 }
diff --git a/web/modules/paragraphs/css/README.md b/web/modules/paragraphs/css/README.md
index a5da7f7683..88748a206f 100644
--- a/web/modules/paragraphs/css/README.md
+++ b/web/modules/paragraphs/css/README.md
@@ -5,10 +5,10 @@ development. For the people that wants to contribute to paragraphs CSS code you
 have two options:
 
 1. If you want to propose CSS improvement but do not want to use our Gulp/SASS
-   toolchain then just change compiled CSS and create a issue with a patch from
-   it. When patch is accepted we will then transfer your changes to SASS and
+   toolchain then just change the compiled CSS and create an issue with a patch from
+   it. When the patch is accepted we will then transfer your changes to SASS and
    recompile CSS files.
-2. Instead of manually changing CSS files, recommended way is to reuse our
+2. Instead of manually changing CSS files, the recommended way is to reuse our
    Gulp/SASS process and do changes in appropriate SASS files and then recompile
    it to CSS.
 
@@ -16,13 +16,13 @@ have two options:
 ## Preparing your development environment for Gulp/SASS toolchain
 
 If you want to do __step 2.__ but do not have needed Gulp/SASS experience do not
-worry, process is not that difficult and is explained in next steps:
+worry, the process is not that difficult and is explained in next steps:
 
 - First thing you need to have is nodejs server on your machine. Please check
-  https://nodejs.org/en/download/package-manager/ and follow steps of nodejs
+  https://nodejs.org/en/download/package-manager/ and follow the steps of nodejs
   server installation for your operating system.
 
-- Then change directory to paragraphs CSS folder
+- Then change the directory to paragraphs CSS folder
 
   `$ cd paragraphs/css`
 
@@ -37,35 +37,35 @@ worry, process is not that difficult and is explained in next steps:
 - You are now able to compile paragraphs CSS from our SASS source files. In the
   same folder execute
 
-  `$ gulp`
+  `$ npx gulp`
 
-If you did not get any error your local machine is now ready and with last
+If you did not get any errors your local machine is now ready and with last
 command you already compiled paragraphs SASS files to CSS.
 
-For closer look at our Gulp configuration and tasks check
+For a closer look at our Gulp configuration and tasks check
 paragraphs/css/gulpfile.js.
 
 
 ## Doing changes in CSS over SASS
 
-Now you are ready to do necessary changes to paragraphs CSS. First locate the
-CSS selector rule you want to change in CSS and then locate this rule in
-appropriate SASS file. Do the change in SASS file, save it and just execute
-again `$ gulp` from your console.
+Now you are ready to do the necessary changes to paragraphs CSS. First locate the
+CSS selector rule you want to change in CSS and then locate this rule in the
+appropriate SASS file. Do the change in the SASS file, save it and just execute
+again `$ npx gulp` from your console.
 
-When you are satisfied with result in CSS files, create Drupal paragraphs issue
-and a patch in standard way.
+When you are satisfied with the result in CSS files, create a Drupal paragraphs 
+issue and a patch in standard way.
 
 
 ## Making sure that your changes are aligned with CSS code standards
 
-If you are getting warning when executing `$ gulp` that are coming from
+If you are getting any warnings when executing `$ npx gulp` that are coming from
 stylelint do not worry.
-This warnings are coming from stylelint postcss plugin which is doing statical
+These warnings are coming from stylelint postcss plugin which is doing statical
 checking of generated CSS files and this simply means that generated CSS code is
 not compatible with paragraphs CSS coding standards.
 
-Generally before accepting SASS/CSS change you need to be sure that all warnings
+Generally before accepting any SASS/CSS changes you need to be sure that all warnings
 are fixed.
 But in some cases warnings can not be avoided, in that case please use turning
 rules off from SASS like explained in https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#turning-rules-off-from-within-your-css. Note that you can use also `//`
@@ -73,11 +73,11 @@ comment syntax instead of `/* ... */`
 
 You can also just run gulp sass lint task: 
 
-`$ gulp sass:lint`
+`$ npx gulp sass:lint`
 
 
 ## Resources
 
-SASS is a very powerful tool and its always good option to know your tools
+SASS is a very powerful tool and its always a good option to know your tools
 better. Please check http://sass-lang.com/guide for more information on SASS
 syntax and it features.
diff --git a/web/modules/paragraphs/css/gulp-tasks.js b/web/modules/paragraphs/css/gulp-tasks.js
index 05245943e6..76b50e00c7 100644
--- a/web/modules/paragraphs/css/gulp-tasks.js
+++ b/web/modules/paragraphs/css/gulp-tasks.js
@@ -18,7 +18,7 @@ module.exports = function(gulp, plugins, options) {
   // Defining gulp tasks.
 
   gulp.task('sass', function() {
-    return gulp.src(options.scssSrc + '/*.scss')
+    return gulp.src(options.scssSrc + '*.scss')
       .pipe(plugins.sass({
         outputStyle: 'expanded',
         includePaths: options.sassIncludePaths
@@ -28,10 +28,10 @@ module.exports = function(gulp, plugins, options) {
   });
 
   gulp.task('sass:lint', function () {
-    return gulp.src(options.scssSrc + '/*.scss')
+    return gulp.src(options.scssSrc + '*.scss')
       .pipe(plugins.postcss(options.processors, {syntax: plugins.syntax_scss}))
   });
 
   // Default task to run everything in correct order.
-  gulp.task('default', ['sass:lint', 'sass']);
+  gulp.task('default', gulp.series(gulp.parallel('sass:lint', 'sass')));
 };
diff --git a/web/modules/paragraphs/css/package-lock.json b/web/modules/paragraphs/css/package-lock.json
new file mode 100644
index 0000000000..73778a6b1a
--- /dev/null
+++ b/web/modules/paragraphs/css/package-lock.json
@@ -0,0 +1,7185 @@
+{
+  "name": "paragraphs",
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+      "dev": true
+    },
+    "ajv": {
+      "version": "6.12.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
+      "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ajv-keywords": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.0.tgz",
+      "integrity": "sha512-eyoaac3btgU8eJlvh01En8OCKzRqlLe2G5jDsCr3RiE2uLGMEEB1aaGwVVpwR8M95956tGH6R+9edC++OvzaVw==",
+      "dev": true
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true
+    },
+    "ansi-colors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+      "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "^0.1.0"
+      }
+    },
+    "ansi-cyan": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
+      "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-gray": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+      "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-red": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
+      "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "ansi-wrap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+      "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
+      "dev": true
+    },
+    "anymatch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+      "dev": true,
+      "requires": {
+        "micromatch": "^3.1.4",
+        "normalize-path": "^2.1.1"
+      }
+    },
+    "append-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+      "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
+      "dev": true,
+      "requires": {
+        "buffer-equal": "^1.0.0"
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+      "dev": true
+    },
+    "archy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+      "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
+      "dev": true
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "dev": true,
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true
+    },
+    "arr-filter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
+      "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
+      "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true
+    },
+    "array-differ": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+      "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
+      "dev": true
+    },
+    "array-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+      "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+      "dev": true
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+      "dev": true
+    },
+    "array-initial": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
+      "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=",
+      "dev": true,
+      "requires": {
+        "array-slice": "^1.0.0",
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-last": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
+      "dev": true,
+      "requires": {
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-slice": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+      "dev": true
+    },
+    "array-sort": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
+      "dev": true,
+      "requires": {
+        "default-compare": "^1.0.0",
+        "get-value": "^2.0.6",
+        "kind-of": "^5.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true,
+      "requires": {
+        "array-uniq": "^1.0.1"
+      }
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true
+    },
+    "async-done": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz",
+      "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.2",
+        "process-nextick-args": "^2.0.0",
+        "stream-exhaust": "^1.0.1"
+      }
+    },
+    "async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true
+    },
+    "async-foreach": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
+      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
+      "dev": true
+    },
+    "async-settle": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
+      "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
+      "dev": true,
+      "requires": {
+        "async-done": "^1.2.2"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "autoprefixer": {
+      "version": "7.2.6",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz",
+      "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==",
+      "dev": true,
+      "requires": {
+        "browserslist": "^2.11.3",
+        "caniuse-lite": "^1.0.30000805",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "postcss": "^6.0.17",
+        "postcss-value-parser": "^3.2.3"
+      }
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true
+    },
+    "aws4": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
+      "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==",
+      "dev": true
+    },
+    "bach": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+      "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
+      "dev": true,
+      "requires": {
+        "arr-filter": "^1.1.1",
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "array-each": "^1.0.0",
+        "array-initial": "^1.0.0",
+        "array-last": "^1.1.1",
+        "async-done": "^1.2.2",
+        "async-settle": "^1.0.0",
+        "now-and-later": "^2.0.0"
+      }
+    },
+    "bail": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+      "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "dev": true,
+      "requires": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "beeper": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
+      "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
+      "dev": true
+    },
+    "binary-extensions": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+      "dev": true
+    },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+      "dev": true,
+      "requires": {
+        "inherits": "~2.0.0"
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "browserslist": {
+      "version": "2.11.3",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz",
+      "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==",
+      "dev": true,
+      "requires": {
+        "caniuse-lite": "^1.0.30000792",
+        "electron-to-chromium": "^1.3.30"
+      }
+    },
+    "buffer-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
+      "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
+      "dev": true
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "camelcase": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+      "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^2.0.0",
+        "map-obj": "^1.0.0"
+      }
+    },
+    "caniuse-lite": {
+      "version": "1.0.30001090",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001090.tgz",
+      "integrity": "sha512-QzPRKDCyp7RhjczTPZaqK3CjPA5Ht2UnXhZhCI4f7QiB5JK6KEuZBxIzyWnB3wO4hgAj4GMRxAhuiacfw0Psjg==",
+      "dev": true
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true
+    },
+    "ccount": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+      "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
+      "dev": true
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "character-entities": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+      "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+      "dev": true
+    },
+    "character-entities-html4": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+      "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+      "dev": true
+    },
+    "character-entities-legacy": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+      "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+      "dev": true
+    },
+    "character-reference-invalid": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+      "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+      "dev": true
+    },
+    "chokidar": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+      "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-each": "^1.0.1",
+        "braces": "^2.3.2",
+        "fsevents": "^1.2.7",
+        "glob-parent": "^3.1.0",
+        "inherits": "^2.0.3",
+        "is-binary-path": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "normalize-path": "^3.0.0",
+        "path-is-absolute": "^1.0.0",
+        "readdirp": "^2.2.1",
+        "upath": "^1.1.1"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          },
+          "dependencies": {
+            "is-glob": {
+              "version": "3.1.0",
+              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+              "dev": true,
+              "requires": {
+                "is-extglob": "^2.1.0"
+              }
+            }
+          }
+        },
+        "normalize-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+          "dev": true
+        }
+      }
+    },
+    "circular-json": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
+      "dev": true
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+      "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^3.1.0",
+        "strip-ansi": "^5.2.0",
+        "wrap-ansi": "^5.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+      "dev": true
+    },
+    "clone-buffer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+      "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
+      "dev": true
+    },
+    "clone-regexp": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.1.tgz",
+      "integrity": "sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw==",
+      "dev": true,
+      "requires": {
+        "is-regexp": "^1.0.0",
+        "is-supported-regexp-flag": "^1.0.0"
+      }
+    },
+    "clone-stats": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+      "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
+      "dev": true
+    },
+    "cloneable-readable": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+      "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "process-nextick-args": "^2.0.0",
+        "readable-stream": "^2.3.5"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+      "dev": true
+    },
+    "collapse-white-space": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+      "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+      "dev": true
+    },
+    "collection-map": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+      "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
+      "dev": true,
+      "requires": {
+        "arr-map": "^2.0.2",
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "copy-props": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz",
+      "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==",
+      "dev": true,
+      "requires": {
+        "each-props": "^1.3.0",
+        "is-plain-object": "^2.0.1"
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cosmiconfig": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+      "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+      "dev": true,
+      "requires": {
+        "is-directory": "^0.3.1",
+        "js-yaml": "^3.4.3",
+        "minimist": "^1.2.0",
+        "object-assign": "^4.1.0",
+        "os-homedir": "^1.0.1",
+        "parse-json": "^2.2.0",
+        "require-from-string": "^1.1.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "cross-spawn": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^4.0.1",
+        "which": "^1.2.9"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "4.1.5",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+          "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+          "dev": true,
+          "requires": {
+            "pseudomap": "^1.0.2",
+            "yallist": "^2.1.2"
+          }
+        }
+      }
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+      "dev": true,
+      "requires": {
+        "array-find-index": "^1.0.1"
+      }
+    },
+    "d": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+      "dev": true,
+      "requires": {
+        "es5-ext": "^0.10.50",
+        "type": "^1.0.1"
+      }
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "dateformat": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
+      "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=",
+      "dev": true
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decamelize-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
+      "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+      "dev": true,
+      "requires": {
+        "decamelize": "^1.1.0",
+        "map-obj": "^1.0.0"
+      }
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "default-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^5.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "default-resolution": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
+      "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
+      "requires": {
+        "object-keys": "^1.0.12"
+      }
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+      "dev": true
+    },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+      "dev": true
+    },
+    "dir-glob": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+      "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+      "dev": true,
+      "requires": {
+        "path-type": "^3.0.0"
+      },
+      "dependencies": {
+        "path-type": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+          "dev": true,
+          "requires": {
+            "pify": "^3.0.0"
+          }
+        },
+        "pify": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+          "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+          "dev": true
+        }
+      }
+    },
+    "dom-serializer": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.0.1",
+        "entities": "^2.0.0"
+      },
+      "dependencies": {
+        "domelementtype": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
+          "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==",
+          "dev": true
+        },
+        "entities": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+          "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
+          "dev": true
+        }
+      }
+    },
+    "domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+      "dev": true
+    },
+    "domhandler": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "1"
+      }
+    },
+    "domutils": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
+      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
+    "dot-prop": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
+      "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
+      "dev": true,
+      "requires": {
+        "is-obj": "^2.0.0"
+      }
+    },
+    "duplexer2": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
+      "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "~1.1.9"
+      }
+    },
+    "duplexify": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0",
+        "stream-shift": "^1.0.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "each-props": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+      "dev": true,
+      "requires": {
+        "is-plain-object": "^2.0.1",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "dev": true,
+      "requires": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "electron-to-chromium": {
+      "version": "1.3.483",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz",
+      "integrity": "sha512-+05RF8S9rk8S0G8eBCqBRBaRq7+UN3lDs2DAvnG8SBSgQO3hjy0+qt4CmRk5eiuGbTcaicgXfPmBi31a+BD3lg==",
+      "dev": true
+    },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      },
+      "dependencies": {
+        "once": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+          "dev": true,
+          "requires": {
+            "wrappy": "1"
+          }
+        }
+      }
+    },
+    "entities": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.53",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
+      "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "~2.0.3",
+        "es6-symbol": "~3.1.3",
+        "next-tick": "~1.0.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+      "dev": true,
+      "requires": {
+        "d": "^1.0.1",
+        "ext": "^1.1.2"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.46",
+        "es6-iterator": "^2.0.3",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
+    "execall": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/execall/-/execall-1.0.0.tgz",
+      "integrity": "sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M=",
+      "dev": true,
+      "requires": {
+        "clone-regexp": "^1.0.0"
+      }
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "dev": true,
+      "requires": {
+        "fill-range": "^2.1.0"
+      },
+      "dependencies": {
+        "fill-range": {
+          "version": "2.2.4",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+          "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+          "dev": true,
+          "requires": {
+            "is-number": "^2.1.0",
+            "isobject": "^2.0.0",
+            "randomatic": "^3.0.0",
+            "repeat-element": "^1.1.2",
+            "repeat-string": "^1.5.2"
+          }
+        },
+        "is-number": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+          "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          }
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "isobject": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+          "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+          "dev": true,
+          "requires": {
+            "isarray": "1.0.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "ext": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
+      "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
+      "dev": true,
+      "requires": {
+        "type": "^2.0.0"
+      },
+      "dependencies": {
+        "type": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz",
+          "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==",
+          "dev": true
+        }
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true
+    },
+    "fancy-log": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+      "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+      "dev": true,
+      "requires": {
+        "ansi-gray": "^0.1.1",
+        "color-support": "^1.1.3",
+        "parse-node-version": "^1.0.0",
+        "time-stamp": "^1.0.0"
+      }
+    },
+    "fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^1.2.1",
+        "object-assign": "^4.0.1"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "dev": true,
+      "optional": true
+    },
+    "filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "dev": true,
+      "requires": {
+        "path-exists": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "findup-sync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+      "dev": true,
+      "requires": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      }
+    },
+    "fined": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "is-plain-object": "^2.0.3",
+        "object.defaults": "^1.1.0",
+        "object.pick": "^1.2.0",
+        "parse-filepath": "^1.0.1"
+      }
+    },
+    "flagged-respawn": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
+      "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
+      "dev": true,
+      "requires": {
+        "circular-json": "^0.3.1",
+        "graceful-fs": "^4.1.2",
+        "rimraf": "~2.6.2",
+        "write": "^0.2.1"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "rimraf": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
+    "flush-write-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "for-own": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+      "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.1"
+      }
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true
+    },
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "dev": true,
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs-mkdirp-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+      "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "through2": "^2.0.3"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+      "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "bindings": "^1.5.0",
+        "nan": "^2.12.1"
+      }
+    },
+    "fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      },
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        }
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "dev": true,
+      "requires": {
+        "glob-parent": "^2.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "dev": true,
+      "requires": {
+        "is-glob": "^2.0.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
+    "glob-stream": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+      "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "glob": "^7.1.1",
+        "glob-parent": "^3.1.0",
+        "is-negated-glob": "^1.0.0",
+        "ordered-read-streams": "^1.0.0",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.1.5",
+        "remove-trailing-separator": "^1.0.1",
+        "to-absolute-glob": "^2.0.0",
+        "unique-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+          "dev": true,
+          "requires": {
+            "is-glob": "^3.1.0",
+            "path-dirname": "^1.0.0"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "glob-watcher": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
+      "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-done": "^1.2.0",
+        "chokidar": "^2.0.0",
+        "is-negated-glob": "^1.0.0",
+        "just-debounce": "^1.0.0",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      }
+    },
+    "globby": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
+      "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
+      "dev": true,
+      "requires": {
+        "array-union": "^1.0.1",
+        "dir-glob": "^2.0.0",
+        "glob": "^7.1.2",
+        "ignore": "^3.3.5",
+        "pify": "^3.0.0",
+        "slash": "^1.0.0"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "pify": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+          "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+          "dev": true
+        }
+      }
+    },
+    "globjoin": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
+      "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
+      "dev": true
+    },
+    "glogg": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
+      "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
+      "dev": true,
+      "requires": {
+        "sparkles": "^1.0.0"
+      }
+    },
+    "gonzales-pe": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz",
+      "integrity": "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+      "dev": true
+    },
+    "gulp": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
+      "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==",
+      "dev": true,
+      "requires": {
+        "glob-watcher": "^5.0.3",
+        "gulp-cli": "^2.2.0",
+        "undertaker": "^1.2.1",
+        "vinyl-fs": "^3.0.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+          "dev": true
+        },
+        "cliui": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+          "dev": true,
+          "requires": {
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1",
+            "wrap-ansi": "^2.0.0"
+          }
+        },
+        "get-caller-file": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+          "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+          "dev": true
+        },
+        "gulp-cli": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz",
+          "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==",
+          "dev": true,
+          "requires": {
+            "ansi-colors": "^1.0.1",
+            "archy": "^1.0.0",
+            "array-sort": "^1.0.0",
+            "color-support": "^1.1.3",
+            "concat-stream": "^1.6.0",
+            "copy-props": "^2.0.1",
+            "fancy-log": "^1.3.2",
+            "gulplog": "^1.0.0",
+            "interpret": "^1.4.0",
+            "isobject": "^3.0.1",
+            "liftoff": "^3.1.0",
+            "matchdep": "^2.0.0",
+            "mute-stdout": "^1.0.0",
+            "pretty-hrtime": "^1.0.0",
+            "replace-homedir": "^1.0.0",
+            "semver-greatest-satisfied-range": "^1.1.0",
+            "v8flags": "^3.2.0",
+            "yargs": "^7.1.0"
+          }
+        },
+        "require-main-filename": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+          "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+          "dev": true
+        },
+        "which-module": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+          "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+          "dev": true
+        },
+        "wrap-ansi": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+          "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+          "dev": true,
+          "requires": {
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1"
+          }
+        },
+        "y18n": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+          "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+          "dev": true
+        },
+        "yargs": {
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz",
+          "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0",
+            "cliui": "^3.2.0",
+            "decamelize": "^1.1.1",
+            "get-caller-file": "^1.0.1",
+            "os-locale": "^1.4.0",
+            "read-pkg-up": "^1.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^1.0.1",
+            "set-blocking": "^2.0.0",
+            "string-width": "^1.0.2",
+            "which-module": "^1.0.0",
+            "y18n": "^3.2.1",
+            "yargs-parser": "5.0.0-security.0"
+          }
+        },
+        "yargs-parser": {
+          "version": "5.0.0-security.0",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz",
+          "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==",
+          "dev": true,
+          "requires": {
+            "camelcase": "^3.0.0",
+            "object.assign": "^4.1.0"
+          }
+        }
+      }
+    },
+    "gulp-load-plugins": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/gulp-load-plugins/-/gulp-load-plugins-1.6.0.tgz",
+      "integrity": "sha512-HlCODki0WHJvQIgAsJYOTkyo0c7TsDCetvfhrdGz9JYPL6A4mFRMGmKfoi6JmXjA/vvzg+fkT91c9FBh7rnkyg==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.2.1",
+        "fancy-log": "^1.2.0",
+        "findup-sync": "^3.0.0",
+        "gulplog": "^1.0.0",
+        "has-gulplog": "^0.1.0",
+        "micromatch": "^3.1.10",
+        "resolve": "^1.1.7"
+      },
+      "dependencies": {
+        "array-unique": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+          "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+          "dev": true
+        },
+        "findup-sync": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+          "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+          "dev": true,
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^4.0.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        },
+        "is-glob": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.1"
+          }
+        }
+      }
+    },
+    "gulp-postcss": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-7.0.1.tgz",
+      "integrity": "sha1-Pxw22xGXFAw5nCUt3/M5EpY445U=",
+      "dev": true,
+      "requires": {
+        "fancy-log": "^1.3.2",
+        "plugin-error": "^0.1.2",
+        "postcss": "^6.0.0",
+        "postcss-load-config": "^1.2.0",
+        "vinyl-sourcemaps-apply": "^0.2.1"
+      }
+    },
+    "gulp-sass": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-3.2.1.tgz",
+      "integrity": "sha512-UATbRpSDsyXCnpYSPBUEvdvtSEzksJs7/oQ0CujIpzKqKrO6vlnYwhX2UTsGrf4rNLwqlSSaM271It0uHYvJ3Q==",
+      "dev": true,
+      "requires": {
+        "gulp-util": "^3.0",
+        "lodash.clonedeep": "^4.3.2",
+        "node-sass": "^4.8.3",
+        "through2": "^2.0.0",
+        "vinyl-sourcemaps-apply": "^0.2.0"
+      }
+    },
+    "gulp-util": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+      "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
+      "dev": true,
+      "requires": {
+        "array-differ": "^1.0.0",
+        "array-uniq": "^1.0.2",
+        "beeper": "^1.0.0",
+        "chalk": "^1.0.0",
+        "dateformat": "^2.0.0",
+        "fancy-log": "^1.1.0",
+        "gulplog": "^1.0.0",
+        "has-gulplog": "^0.1.0",
+        "lodash._reescape": "^3.0.0",
+        "lodash._reevaluate": "^3.0.0",
+        "lodash._reinterpolate": "^3.0.0",
+        "lodash.template": "^3.0.0",
+        "minimist": "^1.1.0",
+        "multipipe": "^0.1.2",
+        "object-assign": "^3.0.0",
+        "replace-ext": "0.0.1",
+        "through2": "^2.0.0",
+        "vinyl": "^0.5.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "gulplog": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+      "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+      "dev": true,
+      "requires": {
+        "glogg": "^1.0.0"
+      }
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true
+    },
+    "har-validator": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.5.5",
+        "har-schema": "^2.0.0"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-gulplog": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+      "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
+      "dev": true,
+      "requires": {
+        "sparkles": "^1.0.0"
+      }
+    },
+    "has-symbols": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+      "dev": true
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
+    "hosted-git-info": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+      "dev": true
+    },
+    "html-tags": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
+      "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
+      "dev": true
+    },
+    "htmlparser2": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^1.3.1",
+        "domhandler": "^2.3.0",
+        "domutils": "^1.5.1",
+        "entities": "^1.1.1",
+        "inherits": "^2.0.1",
+        "readable-stream": "^3.1.1"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+          "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.2.0"
+          }
+        }
+      }
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      }
+    },
+    "ignore": {
+      "version": "3.3.10",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "in-publish": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
+      "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
+      "dev": true
+    },
+    "indent-string": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+      "dev": true,
+      "requires": {
+        "repeating": "^2.0.0"
+      }
+    },
+    "indexes-of": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+      "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true
+    },
+    "interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+      "dev": true
+    },
+    "is-absolute": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+      "dev": true,
+      "requires": {
+        "is-relative": "^1.0.0",
+        "is-windows": "^1.0.1"
+      }
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-alphabetical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+      "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+      "dev": true
+    },
+    "is-alphanumeric": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+      "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+      "dev": true
+    },
+    "is-alphanumerical": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+      "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+      "dev": true,
+      "requires": {
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^1.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-decimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+      "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+      "dev": true
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "is-directory": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+      "dev": true
+    },
+    "is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+      "dev": true
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+      "dev": true,
+      "requires": {
+        "is-primitive": "^2.0.0"
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-finite": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+      "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-hexadecimal": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+      "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+      "dev": true
+    },
+    "is-negated-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+      "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
+      "dev": true
+    },
+    "is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-obj": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+      "dev": true
+    },
+    "is-plain-obj": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+      "dev": true
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+      "dev": true
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+      "dev": true
+    },
+    "is-regexp": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+      "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+      "dev": true
+    },
+    "is-relative": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+      "dev": true,
+      "requires": {
+        "is-unc-path": "^1.0.0"
+      }
+    },
+    "is-supported-regexp-flag": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz",
+      "integrity": "sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ==",
+      "dev": true
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true
+    },
+    "is-unc-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+      "dev": true,
+      "requires": {
+        "unc-path-regex": "^0.1.2"
+      }
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "is-valid-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+      "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
+      "dev": true
+    },
+    "is-whitespace-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+      "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "is-word-character": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+      "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "js-base64": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.2.tgz",
+      "integrity": "sha512-1hgLrLIrmCgZG+ID3VoLNLOSwjGnoZa8tyrUdEteMeIzsT6PH7PMLyUvbDwzNE56P3PNxyvuIOx4Uh2E5rzQIw==",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+      "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      }
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "just-debounce": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
+      "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true
+    },
+    "known-css-properties": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.5.0.tgz",
+      "integrity": "sha512-LOS0CoS8zcZnB1EjLw4LLqDXw8nvt3AGH5dXLQP3D9O1nLLA+9GC5GnPl5mmF+JiQAtSX4VyZC7KvEtcA4kUtA==",
+      "dev": true
+    },
+    "last-run": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
+      "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
+      "dev": true,
+      "requires": {
+        "default-resolution": "^2.0.0",
+        "es6-weak-map": "^2.0.1"
+      }
+    },
+    "lazystream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.5"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+      "dev": true,
+      "requires": {
+        "invert-kv": "^1.0.0"
+      }
+    },
+    "lead": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+      "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
+      "dev": true,
+      "requires": {
+        "flush-write-stream": "^1.0.2"
+      }
+    },
+    "liftoff": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "findup-sync": "^3.0.0",
+        "fined": "^1.0.1",
+        "flagged-respawn": "^1.0.0",
+        "is-plain-object": "^2.0.4",
+        "object.map": "^1.0.0",
+        "rechoir": "^0.6.2",
+        "resolve": "^1.1.7"
+      }
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      },
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+          "dev": true,
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        }
+      }
+    },
+    "locate-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+      "dev": true,
+      "requires": {
+        "p-locate": "^3.0.0",
+        "path-exists": "^3.0.0"
+      },
+      "dependencies": {
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        }
+      }
+    },
+    "lodash._basecopy": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+      "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
+      "dev": true
+    },
+    "lodash._basetostring": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
+      "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=",
+      "dev": true
+    },
+    "lodash._basevalues": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
+      "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=",
+      "dev": true
+    },
+    "lodash._getnative": {
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
+      "dev": true
+    },
+    "lodash._isiterateecall": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+      "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
+      "dev": true
+    },
+    "lodash._reescape": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
+      "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=",
+      "dev": true
+    },
+    "lodash._reevaluate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
+      "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=",
+      "dev": true
+    },
+    "lodash._reinterpolate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+      "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
+      "dev": true
+    },
+    "lodash._root": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
+      "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
+      "dev": true
+    },
+    "lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+      "dev": true
+    },
+    "lodash.escape": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
+      "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
+      "dev": true,
+      "requires": {
+        "lodash._root": "^3.0.0"
+      }
+    },
+    "lodash.isarguments": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+      "dev": true
+    },
+    "lodash.isarray": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+      "dev": true
+    },
+    "lodash.keys": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+      "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
+      "dev": true,
+      "requires": {
+        "lodash._getnative": "^3.0.0",
+        "lodash.isarguments": "^3.0.0",
+        "lodash.isarray": "^3.0.0"
+      }
+    },
+    "lodash.restparam": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
+      "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
+      "dev": true
+    },
+    "lodash.template": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
+      "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
+      "dev": true,
+      "requires": {
+        "lodash._basecopy": "^3.0.0",
+        "lodash._basetostring": "^3.0.0",
+        "lodash._basevalues": "^3.0.0",
+        "lodash._isiterateecall": "^3.0.0",
+        "lodash._reinterpolate": "^3.0.0",
+        "lodash.escape": "^3.0.0",
+        "lodash.keys": "^3.0.0",
+        "lodash.restparam": "^3.0.0",
+        "lodash.templatesettings": "^3.0.0"
+      }
+    },
+    "lodash.templatesettings": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
+      "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
+      "dev": true,
+      "requires": {
+        "lodash._reinterpolate": "^3.0.0",
+        "lodash.escape": "^3.0.0"
+      }
+    },
+    "log-symbols": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+      "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.1"
+      }
+    },
+    "longest-streak": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+      "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+      "dev": true
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+      "dev": true,
+      "requires": {
+        "currently-unhandled": "^0.4.1",
+        "signal-exit": "^3.0.0"
+      }
+    },
+    "make-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "markdown-escapes": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+      "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+      "dev": true
+    },
+    "markdown-table": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz",
+      "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==",
+      "dev": true
+    },
+    "matchdep": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
+      "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
+      "dev": true,
+      "requires": {
+        "findup-sync": "^2.0.0",
+        "micromatch": "^3.0.4",
+        "resolve": "^1.4.0",
+        "stack-trace": "0.0.10"
+      },
+      "dependencies": {
+        "findup-sync": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+          "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+          "dev": true,
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^3.1.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        }
+      }
+    },
+    "math-random": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+      "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+      "dev": true
+    },
+    "mathml-tag-names": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
+      "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==",
+      "dev": true
+    },
+    "mdast-util-compact": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz",
+      "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==",
+      "dev": true,
+      "requires": {
+        "unist-util-visit": "^1.1.0"
+      }
+    },
+    "meow": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+      "dev": true,
+      "requires": {
+        "camelcase-keys": "^2.0.0",
+        "decamelize": "^1.1.2",
+        "loud-rejection": "^1.0.0",
+        "map-obj": "^1.0.1",
+        "minimist": "^1.1.3",
+        "normalize-package-data": "^2.3.4",
+        "object-assign": "^4.0.1",
+        "read-pkg-up": "^1.0.1",
+        "redent": "^1.0.0",
+        "trim-newlines": "^1.0.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      }
+    },
+    "mime-db": {
+      "version": "1.44.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.27",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+      "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+      "dev": true,
+      "requires": {
+        "mime-db": "1.44.0"
+      }
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+      "dev": true
+    },
+    "minimist-options": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz",
+      "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==",
+      "dev": true,
+      "requires": {
+        "arrify": "^1.0.1",
+        "is-plain-obj": "^1.1.0"
+      }
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.5"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "multipipe": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
+      "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
+      "dev": true,
+      "requires": {
+        "duplexer2": "0.0.2"
+      }
+    },
+    "mute-stdout": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.14.1",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
+      "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
+      "dev": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "next-tick": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+      "dev": true
+    },
+    "node-gyp": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
+      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
+      "dev": true,
+      "requires": {
+        "fstream": "^1.0.0",
+        "glob": "^7.0.3",
+        "graceful-fs": "^4.1.2",
+        "mkdirp": "^0.5.0",
+        "nopt": "2 || 3",
+        "npmlog": "0 || 1 || 2 || 3 || 4",
+        "osenv": "0",
+        "request": "^2.87.0",
+        "rimraf": "2",
+        "semver": "~5.3.0",
+        "tar": "^2.0.0",
+        "which": "1"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "semver": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+          "dev": true
+        }
+      }
+    },
+    "node-sass": {
+      "version": "4.14.1",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz",
+      "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==",
+      "dev": true,
+      "requires": {
+        "async-foreach": "^0.1.3",
+        "chalk": "^1.1.1",
+        "cross-spawn": "^3.0.0",
+        "gaze": "^1.0.0",
+        "get-stdin": "^4.0.1",
+        "glob": "^7.0.3",
+        "in-publish": "^2.0.0",
+        "lodash": "^4.17.15",
+        "meow": "^3.7.0",
+        "mkdirp": "^0.5.1",
+        "nan": "^2.13.2",
+        "node-gyp": "^3.8.0",
+        "npmlog": "^4.0.0",
+        "request": "^2.88.0",
+        "sass-graph": "2.2.5",
+        "stdout-stream": "^1.4.0",
+        "true-case-path": "^1.0.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          }
+        },
+        "gaze": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
+          "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
+          "dev": true,
+          "requires": {
+            "globule": "^1.0.0"
+          }
+        },
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "globule": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
+          "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==",
+          "dev": true,
+          "requires": {
+            "glob": "~7.1.1",
+            "lodash": "~4.17.10",
+            "minimatch": "~3.0.2"
+          }
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "supports-color": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "dev": true
+        }
+      }
+    },
+    "nopt": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "dev": true,
+      "requires": {
+        "abbrev": "1"
+      }
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "requires": {
+        "remove-trailing-separator": "^1.0.1"
+      }
+    },
+    "normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "dev": true
+    },
+    "normalize-selector": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
+      "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
+      "dev": true
+    },
+    "now-and-later": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+      "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.2"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+      "dev": true
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+      "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.assign": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "function-bind": "^1.1.1",
+        "has-symbols": "^1.0.0",
+        "object-keys": "^1.0.11"
+      }
+    },
+    "object.defaults": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+      "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+      "dev": true,
+      "requires": {
+        "array-each": "^1.0.1",
+        "array-slice": "^1.0.0",
+        "for-own": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+      "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "dev": true,
+      "requires": {
+        "for-own": "^0.1.4",
+        "is-extendable": "^0.1.1"
+      },
+      "dependencies": {
+        "for-own": {
+          "version": "0.1.5",
+          "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+          "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+          "dev": true,
+          "requires": {
+            "for-in": "^1.0.1"
+          }
+        }
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "object.reduce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+      "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "once": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
+      "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "ordered-read-streams": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+      "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true
+    },
+    "os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+      "dev": true,
+      "requires": {
+        "lcid": "^1.0.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "dev": true,
+      "requires": {
+        "os-homedir": "^1.0.0",
+        "os-tmpdir": "^1.0.0"
+      }
+    },
+    "p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "requires": {
+        "p-try": "^2.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+      "dev": true,
+      "requires": {
+        "p-limit": "^2.0.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
+    },
+    "parse-entities": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
+      "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
+      "dev": true,
+      "requires": {
+        "character-entities": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "character-reference-invalid": "^1.0.0",
+        "is-alphanumerical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-hexadecimal": "^1.0.0"
+      }
+    },
+    "parse-filepath": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+      "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "map-cache": "^0.2.0",
+        "path-root": "^0.1.1"
+      }
+    },
+    "parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "dev": true,
+      "requires": {
+        "glob-base": "^0.3.0",
+        "is-dotfile": "^1.0.0",
+        "is-extglob": "^1.0.0",
+        "is-glob": "^2.0.0"
+      },
+      "dependencies": {
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        }
+      }
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "dev": true,
+      "requires": {
+        "error-ex": "^1.2.0"
+      }
+    },
+    "parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true
+    },
+    "path-dirname": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "dev": true,
+      "requires": {
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "path-root": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+      "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+      "dev": true,
+      "requires": {
+        "path-root-regex": "^0.1.0"
+      }
+    },
+    "path-root-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+      "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      },
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        }
+      }
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "plugin-error": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
+      "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
+      "dev": true,
+      "requires": {
+        "ansi-cyan": "^0.1.1",
+        "ansi-red": "^0.1.1",
+        "arr-diff": "^1.0.1",
+        "arr-union": "^2.0.1",
+        "extend-shallow": "^1.1.2"
+      },
+      "dependencies": {
+        "arr-diff": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
+          "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.0.1",
+            "array-slice": "^0.2.3"
+          }
+        },
+        "arr-union": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
+          "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
+          "dev": true
+        },
+        "array-slice": {
+          "version": "0.2.3",
+          "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+          "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
+          "dev": true
+        },
+        "extend-shallow": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
+          "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^1.1.0"
+          }
+        },
+        "kind-of": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
+          "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
+          "dev": true
+        }
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true
+    },
+    "postcss": {
+      "version": "6.0.23",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+      "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.4.1",
+        "source-map": "^0.6.1",
+        "supports-color": "^5.4.0"
+      }
+    },
+    "postcss-bem-linter": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/postcss-bem-linter/-/postcss-bem-linter-2.7.1.tgz",
+      "integrity": "sha512-ZrioXOS7tDQRynp5KoMgcukRerPWitTpkAE37XWmQNuNO8R4vYAh/f4/I7+5MwwfzTY6X6oy3Ab3iaSMNMF6vg==",
+      "dev": true,
+      "requires": {
+        "minimatch": "^3.0.3",
+        "postcss": "^5.0.0",
+        "postcss-resolve-nested-selector": "^0.1.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-html": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/postcss-html/-/postcss-html-0.12.0.tgz",
+      "integrity": "sha512-KxKUpj7AY7nlCbLcTOYxdfJnGE7QFAfU2n95ADj1Q90RM/pOLdz8k3n4avOyRFs7MDQHcRzJQWM1dehCwJxisQ==",
+      "dev": true,
+      "requires": {
+        "htmlparser2": "^3.9.2",
+        "remark": "^8.0.0",
+        "unist-util-find-all-after": "^1.0.1"
+      }
+    },
+    "postcss-less": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-1.1.5.tgz",
+      "integrity": "sha512-QQIiIqgEjNnquc0d4b6HDOSFZxbFQoy4MPpli2lSLpKhMyBkKwwca2HFqu4xzxlKID/F2fxSOowwtKpgczhF7A==",
+      "dev": true,
+      "requires": {
+        "postcss": "^5.2.16"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^2.2.1",
+            "escape-string-regexp": "^1.0.2",
+            "has-ansi": "^2.0.0",
+            "strip-ansi": "^3.0.0",
+            "supports-color": "^2.0.0"
+          },
+          "dependencies": {
+            "supports-color": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+              "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+              "dev": true
+            }
+          }
+        },
+        "has-flag": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+          "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+          "dev": true
+        },
+        "postcss": {
+          "version": "5.2.18",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+          "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^1.1.3",
+            "js-base64": "^2.1.9",
+            "source-map": "^0.5.6",
+            "supports-color": "^3.2.3"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+          "dev": true,
+          "requires": {
+            "has-flag": "^1.0.0"
+          }
+        }
+      }
+    },
+    "postcss-load-config": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
+      "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^2.1.0",
+        "object-assign": "^4.1.0",
+        "postcss-load-options": "^1.2.0",
+        "postcss-load-plugins": "^2.3.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "postcss-load-options": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz",
+      "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^2.1.0",
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "postcss-load-plugins": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz",
+      "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=",
+      "dev": true,
+      "requires": {
+        "cosmiconfig": "^2.1.1",
+        "object-assign": "^4.1.0"
+      },
+      "dependencies": {
+        "object-assign": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "dev": true
+        }
+      }
+    },
+    "postcss-media-query-parser": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
+      "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
+      "dev": true
+    },
+    "postcss-reporter": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-5.0.0.tgz",
+      "integrity": "sha512-rBkDbaHAu5uywbCR2XE8a25tats3xSOsGNx6mppK6Q9kSFGKc/FyAzfci+fWM2l+K402p1D0pNcfDGxeje5IKg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.0.1",
+        "lodash": "^4.17.4",
+        "log-symbols": "^2.0.0",
+        "postcss": "^6.0.8"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-resolve-nested-selector": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
+      "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
+      "dev": true
+    },
+    "postcss-safe-parser": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-3.0.1.tgz",
+      "integrity": "sha1-t1Pv9sfArqXoN1++TN6L+QY/8UI=",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.6"
+      }
+    },
+    "postcss-sass": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.2.0.tgz",
+      "integrity": "sha512-cUmYzkP747fPCQE6d+CH2l1L4VSyIlAzZsok3HPjb5Gzsq3jE+VjpAdGlPsnQ310WKWI42sw+ar0UNN59/f3hg==",
+      "dev": true,
+      "requires": {
+        "gonzales-pe": "^4.0.3",
+        "postcss": "^6.0.6"
+      }
+    },
+    "postcss-scss": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-1.0.6.tgz",
+      "integrity": "sha512-4EFYGHcEw+H3E06PT/pQQri06u/1VIIPjeJQaM8skB80vZuXMhp4cSNV5azmdNkontnOID/XYWEvEEELLFB1ww==",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.23"
+      }
+    },
+    "postcss-selector-parser": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
+      "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
+      "dev": true,
+      "requires": {
+        "dot-prop": "^5.2.0",
+        "indexes-of": "^1.0.1",
+        "uniq": "^1.0.1"
+      }
+    },
+    "postcss-sorting": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-3.1.0.tgz",
+      "integrity": "sha512-YCPTcJwGIInF1LpMD1lIYvMHTGUL4s97o/OraA6eKvoauhhk6vjwOWDDjm6uRKqug/kyDPMKEzmYZ6FtW6RDgw==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.4",
+        "postcss": "^6.0.13"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        }
+      }
+    },
+    "postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
+      "dev": true
+    },
+    "preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+      "dev": true
+    },
+    "pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "psl": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+      "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+      "dev": true
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "requires": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.0.0"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
+    },
+    "qs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+      "dev": true
+    },
+    "quick-lru": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
+      "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
+      "dev": true
+    },
+    "randomatic": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+      "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+      "dev": true,
+      "requires": {
+        "is-number": "^4.0.0",
+        "kind-of": "^6.0.0",
+        "math-random": "^1.0.1"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "dev": true,
+      "requires": {
+        "load-json-file": "^1.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^1.0.0"
+      }
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "dev": true,
+      "requires": {
+        "find-up": "^1.0.0",
+        "read-pkg": "^1.0.0"
+      }
+    },
+    "readable-stream": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+      "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      }
+    },
+    "readdirp": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "micromatch": "^3.1.10",
+        "readable-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
+    "redent": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+      "dev": true,
+      "requires": {
+        "indent-string": "^2.1.0",
+        "strip-indent": "^1.0.1"
+      }
+    },
+    "regex-cache": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+      "dev": true,
+      "requires": {
+        "is-equal-shallow": "^0.1.3"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "remark": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/remark/-/remark-8.0.0.tgz",
+      "integrity": "sha512-K0PTsaZvJlXTl9DN6qYlvjTkqSZBFELhROZMrblm2rB+085flN84nz4g/BscKRMqDvhzlK1oQ/xnWQumdeNZYw==",
+      "dev": true,
+      "requires": {
+        "remark-parse": "^4.0.0",
+        "remark-stringify": "^4.0.0",
+        "unified": "^6.0.0"
+      }
+    },
+    "remark-parse": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-4.0.0.tgz",
+      "integrity": "sha512-XZgICP2gJ1MHU7+vQaRM+VA9HEL3X253uwUM/BGgx3iv6TH2B3bF3B8q00DKcyP9YrJV+/7WOWEWBFF/u8cIsw==",
+      "dev": true,
+      "requires": {
+        "collapse-white-space": "^1.0.2",
+        "is-alphabetical": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "is-word-character": "^1.0.0",
+        "markdown-escapes": "^1.0.0",
+        "parse-entities": "^1.0.2",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "trim": "0.0.1",
+        "trim-trailing-lines": "^1.0.0",
+        "unherit": "^1.0.4",
+        "unist-util-remove-position": "^1.0.0",
+        "vfile-location": "^2.0.0",
+        "xtend": "^4.0.1"
+      }
+    },
+    "remark-stringify": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-4.0.0.tgz",
+      "integrity": "sha512-xLuyKTnuQer3ke9hkU38SUYLiTmS078QOnoFavztmbt/pAJtNSkNtFgR0U//uCcmG0qnyxao+PDuatQav46F1w==",
+      "dev": true,
+      "requires": {
+        "ccount": "^1.0.0",
+        "is-alphanumeric": "^1.0.0",
+        "is-decimal": "^1.0.0",
+        "is-whitespace-character": "^1.0.0",
+        "longest-streak": "^2.0.1",
+        "markdown-escapes": "^1.0.0",
+        "markdown-table": "^1.1.0",
+        "mdast-util-compact": "^1.0.0",
+        "parse-entities": "^1.0.2",
+        "repeat-string": "^1.5.4",
+        "state-toggle": "^1.0.0",
+        "stringify-entities": "^1.0.1",
+        "unherit": "^1.0.4",
+        "xtend": "^4.0.1"
+      }
+    },
+    "remove-bom-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^1.1.5",
+        "is-utf8": "^0.2.1"
+      }
+    },
+    "remove-bom-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+      "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
+      "dev": true,
+      "requires": {
+        "remove-bom-buffer": "^3.0.0",
+        "safe-buffer": "^5.1.0",
+        "through2": "^2.0.3"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "dev": true,
+      "requires": {
+        "is-finite": "^1.0.0"
+      }
+    },
+    "replace-ext": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+      "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
+      "dev": true
+    },
+    "replace-homedir": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
+      "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1",
+        "is-absolute": "^1.0.0",
+        "remove-trailing-separator": "^1.1.0"
+      }
+    },
+    "request": {
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+      "dev": true,
+      "requires": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.3",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.5.0",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-from-string": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
+      "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.17.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
+      "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
+      "dev": true,
+      "requires": {
+        "path-parse": "^1.0.6"
+      }
+    },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      }
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true
+    },
+    "resolve-options": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+      "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
+      "dev": true,
+      "requires": {
+        "value-or-function": "^3.0.0"
+      }
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "sass-graph": {
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
+      "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.0.0",
+        "lodash": "^4.0.0",
+        "scss-tokenizer": "^0.2.3",
+        "yargs": "^13.3.2"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
+      }
+    },
+    "scss-tokenizer": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
+      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
+      "dev": true,
+      "requires": {
+        "js-base64": "^2.1.8",
+        "source-map": "^0.4.2"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "dev": true,
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        }
+      }
+    },
+    "semver": {
+      "version": "4.3.6",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
+      "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
+      "dev": true
+    },
+    "semver-greatest-satisfied-range": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+      "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
+      "dev": true,
+      "requires": {
+        "sver-compat": "^1.5.0"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "signal-exit": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+      "dev": true
+    },
+    "slash": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+      "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+      "dev": true,
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0"
+      },
+      "dependencies": {
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.2",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+      "dev": true
+    },
+    "sparkles": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+      "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+      "dev": true
+    },
+    "specificity": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.3.2.tgz",
+      "integrity": "sha512-Nc/QN/A425Qog7j9aHmwOrlwX2e7pNI47ciwxwy4jOlvbbMHkNNJchit+FX+UjF3IAdiaaV5BKeWuDUnws6G1A==",
+      "dev": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "sshpk": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "dev": true,
+      "requires": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      }
+    },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+      "dev": true
+    },
+    "state-toggle": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+      "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "stdout-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
+      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "stream-exhaust": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+      "dev": true
+    },
+    "stream-shift": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
+      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
+      "dev": true
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "dev": true,
+      "requires": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      }
+    },
+    "string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+      "dev": true
+    },
+    "stringify-entities": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz",
+      "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==",
+      "dev": true,
+      "requires": {
+        "character-entities-html4": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "is-alphanumerical": "^1.0.0",
+        "is-hexadecimal": "^1.0.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^4.0.1"
+      }
+    },
+    "style-search": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
+      "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
+      "dev": true
+    },
+    "stylelint": {
+      "version": "8.4.0",
+      "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-8.4.0.tgz",
+      "integrity": "sha512-56hPH5mTFnk8LzlEuTWq0epa34fHuS54UFYQidBOFt563RJBNi1nz1F2HK2MoT1X1waq47milvRsRahFCCJs/Q==",
+      "dev": true,
+      "requires": {
+        "autoprefixer": "^7.1.2",
+        "balanced-match": "^1.0.0",
+        "chalk": "^2.0.1",
+        "cosmiconfig": "^3.1.0",
+        "debug": "^3.0.0",
+        "execall": "^1.0.0",
+        "file-entry-cache": "^2.0.0",
+        "get-stdin": "^5.0.1",
+        "globby": "^7.0.0",
+        "globjoin": "^0.1.4",
+        "html-tags": "^2.0.0",
+        "ignore": "^3.3.3",
+        "imurmurhash": "^0.1.4",
+        "known-css-properties": "^0.5.0",
+        "lodash": "^4.17.4",
+        "log-symbols": "^2.0.0",
+        "mathml-tag-names": "^2.0.1",
+        "meow": "^4.0.0",
+        "micromatch": "^2.3.11",
+        "normalize-selector": "^0.2.0",
+        "pify": "^3.0.0",
+        "postcss": "^6.0.6",
+        "postcss-html": "^0.12.0",
+        "postcss-less": "^1.1.0",
+        "postcss-media-query-parser": "^0.2.3",
+        "postcss-reporter": "^5.0.0",
+        "postcss-resolve-nested-selector": "^0.1.1",
+        "postcss-safe-parser": "^3.0.1",
+        "postcss-sass": "^0.2.0",
+        "postcss-scss": "^1.0.2",
+        "postcss-selector-parser": "^3.1.0",
+        "postcss-value-parser": "^3.3.0",
+        "resolve-from": "^4.0.0",
+        "specificity": "^0.3.1",
+        "string-width": "^2.1.0",
+        "style-search": "^0.1.0",
+        "sugarss": "^1.0.0",
+        "svg-tags": "^1.0.0",
+        "table": "^4.0.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "arr-diff": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+          "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.0.1"
+          }
+        },
+        "array-unique": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+          "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+          "dev": true
+        },
+        "braces": {
+          "version": "1.8.5",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+          "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+          "dev": true,
+          "requires": {
+            "expand-range": "^1.8.1",
+            "preserve": "^0.2.0",
+            "repeat-element": "^1.1.2"
+          }
+        },
+        "camelcase": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+          "dev": true
+        },
+        "camelcase-keys": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
+          "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
+          "dev": true,
+          "requires": {
+            "camelcase": "^4.1.0",
+            "map-obj": "^2.0.0",
+            "quick-lru": "^1.0.0"
+          }
+        },
+        "cosmiconfig": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-3.1.0.tgz",
+          "integrity": "sha512-zedsBhLSbPBms+kE7AH4vHg6JsKDz6epSv2/+5XHs8ILHlgDciSJfSWf8sX9aQ52Jb7KI7VswUTsLpR/G0cr2Q==",
+          "dev": true,
+          "requires": {
+            "is-directory": "^0.3.1",
+            "js-yaml": "^3.9.0",
+            "parse-json": "^3.0.0",
+            "require-from-string": "^2.0.1"
+          }
+        },
+        "debug": {
+          "version": "3.2.6",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "expand-brackets": {
+          "version": "0.1.5",
+          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+          "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+          "dev": true,
+          "requires": {
+            "is-posix-bracket": "^0.1.0"
+          }
+        },
+        "extglob": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+          "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        },
+        "find-up": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+          "dev": true,
+          "requires": {
+            "locate-path": "^2.0.0"
+          }
+        },
+        "get-stdin": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
+          "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
+          "dev": true
+        },
+        "graceful-fs": {
+          "version": "4.2.4",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+          "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+          "dev": true
+        },
+        "indent-string": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+          "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+          "dev": true
+        },
+        "is-extglob": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+          "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "is-glob": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+          "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^1.0.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        },
+        "load-json-file": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+          "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "parse-json": "^4.0.0",
+            "pify": "^3.0.0",
+            "strip-bom": "^3.0.0"
+          },
+          "dependencies": {
+            "parse-json": {
+              "version": "4.0.0",
+              "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+              "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+              "dev": true,
+              "requires": {
+                "error-ex": "^1.3.1",
+                "json-parse-better-errors": "^1.0.1"
+              }
+            }
+          }
+        },
+        "locate-path": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+          "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+          "dev": true,
+          "requires": {
+            "p-locate": "^2.0.0",
+            "path-exists": "^3.0.0"
+          }
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "map-obj": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
+          "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
+          "dev": true
+        },
+        "meow": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz",
+          "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==",
+          "dev": true,
+          "requires": {
+            "camelcase-keys": "^4.0.0",
+            "decamelize-keys": "^1.0.0",
+            "loud-rejection": "^1.0.0",
+            "minimist": "^1.1.3",
+            "minimist-options": "^3.0.1",
+            "normalize-package-data": "^2.3.4",
+            "read-pkg-up": "^3.0.0",
+            "redent": "^2.0.0",
+            "trim-newlines": "^2.0.0"
+          }
+        },
+        "micromatch": {
+          "version": "2.3.11",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+          "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^2.0.0",
+            "array-unique": "^0.2.1",
+            "braces": "^1.8.2",
+            "expand-brackets": "^0.1.4",
+            "extglob": "^0.3.1",
+            "filename-regex": "^2.0.0",
+            "is-extglob": "^1.0.0",
+            "is-glob": "^2.0.1",
+            "kind-of": "^3.0.2",
+            "normalize-path": "^2.0.1",
+            "object.omit": "^2.0.0",
+            "parse-glob": "^3.0.4",
+            "regex-cache": "^0.4.2"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "p-limit": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+          "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+          "dev": true,
+          "requires": {
+            "p-try": "^1.0.0"
+          }
+        },
+        "p-locate": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+          "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+          "dev": true,
+          "requires": {
+            "p-limit": "^1.1.0"
+          }
+        },
+        "p-try": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+          "dev": true
+        },
+        "parse-json": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-3.0.0.tgz",
+          "integrity": "sha1-+m9HsY4jgm6tMvJj50TQ4ehH+xM=",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.3.1"
+          }
+        },
+        "path-exists": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "dev": true
+        },
+        "path-type": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+          "dev": true,
+          "requires": {
+            "pify": "^3.0.0"
+          }
+        },
+        "pify": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+          "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+          "dev": true
+        },
+        "read-pkg": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+          "dev": true,
+          "requires": {
+            "load-json-file": "^4.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^3.0.0"
+          }
+        },
+        "read-pkg-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
+          "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+          "dev": true,
+          "requires": {
+            "find-up": "^2.0.0",
+            "read-pkg": "^3.0.0"
+          }
+        },
+        "redent": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
+          "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=",
+          "dev": true,
+          "requires": {
+            "indent-string": "^3.0.0",
+            "strip-indent": "^2.0.0"
+          }
+        },
+        "require-from-string": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+          "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "dev": true,
+          "requires": {
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^4.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        },
+        "strip-bom": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+          "dev": true
+        },
+        "strip-indent": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
+          "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
+          "dev": true
+        },
+        "trim-newlines": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
+          "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=",
+          "dev": true
+        }
+      }
+    },
+    "stylelint-config-recommended": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-1.0.0.tgz",
+      "integrity": "sha512-wp50rY5A6MWndIIkKNNzJv/S58lTvqQEriS7CXTBN1SwtoY/YjHhCLIOkjundLnUWMvJJska6GnciLbs76UQrA==",
+      "dev": true
+    },
+    "stylelint-config-standard": {
+      "version": "17.0.0",
+      "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-17.0.0.tgz",
+      "integrity": "sha512-G8jMZ0KsaVH7leur9XLZVhwOBHZ2vdbuJV8Bgy0ta7/PpBhEHo6fjVDaNchyCGXB5sRcWVq6O9rEU/MvY9cQDQ==",
+      "dev": true,
+      "requires": {
+        "stylelint-config-recommended": "^1.0.0"
+      }
+    },
+    "stylelint-order": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-0.6.0.tgz",
+      "integrity": "sha1-ciIr4MZNh4Ky/CN9DZrJdAOflos=",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.4",
+        "postcss": "^6.0.7",
+        "postcss-sorting": "^3.0.1",
+        "stylelint": "^8.0.0"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        }
+      }
+    },
+    "stylelint-scss": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-2.5.0.tgz",
+      "integrity": "sha512-+joZpza5nQxAyGwzRMancFEl0EH9+1Vy88YzBghRMS0wHulzDPE9fEkBi6ZOlz+I3tYIBI4x9NbqO5/LkbeE3Q==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.4",
+        "postcss-media-query-parser": "^0.2.3",
+        "postcss-resolve-nested-selector": "^0.1.1",
+        "postcss-selector-parser": "^3.1.1",
+        "postcss-value-parser": "^3.3.0"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        }
+      }
+    },
+    "stylelint-selector-bem-pattern": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stylelint-selector-bem-pattern/-/stylelint-selector-bem-pattern-1.1.1.tgz",
+      "integrity": "sha512-PGCjc5yc/tg12ZTKavWHO8a/snpgLdHb8CAJG/MGug0qA7Z6deBNT4FViAVRTGTrQT7+CseJ5MTOqhM/kNmOcQ==",
+      "dev": true,
+      "requires": {
+        "lodash": ">=3.10.0",
+        "postcss": ">=5.0.19",
+        "postcss-bem-linter": "^2.1.0",
+        "stylelint": ">=3.0.2"
+      },
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        }
+      }
+    },
+    "sugarss": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-1.0.1.tgz",
+      "integrity": "sha512-3qgLZytikQQEVn1/FrhY7B68gPUUGY3R1Q1vTiD5xT+Ti1DP/8iZuwFet9ONs5+bmL8pZoDQ6JrQHVgrNlK6mA==",
+      "dev": true,
+      "requires": {
+        "postcss": "^6.0.14"
+      }
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "sver-compat": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+      "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "^2.0.1",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "svg-tags": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
+      "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+      "dev": true
+    },
+    "table": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz",
+      "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.0.1",
+        "ajv-keywords": "^3.0.0",
+        "chalk": "^2.1.0",
+        "lodash": "^4.17.4",
+        "slice-ansi": "1.0.0",
+        "string-width": "^2.1.1"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "lodash": {
+          "version": "4.17.15",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "dev": true,
+          "requires": {
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^4.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
+    "tar": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
+      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
+      "dev": true,
+      "requires": {
+        "block-stream": "*",
+        "fstream": "^1.0.12",
+        "inherits": "2"
+      }
+    },
+    "through2": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "~2.3.6",
+        "xtend": "~4.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "through2-filter": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+      "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+      "dev": true,
+      "requires": {
+        "through2": "~2.0.0",
+        "xtend": "~4.0.0"
+      }
+    },
+    "time-stamp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+      "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
+      "dev": true
+    },
+    "to-absolute-glob": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+      "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "is-negated-glob": "^1.0.0"
+      }
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      }
+    },
+    "to-through": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+      "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
+      "dev": true,
+      "requires": {
+        "through2": "^2.0.3"
+      }
+    },
+    "tough-cookie": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+      "dev": true,
+      "requires": {
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
+      }
+    },
+    "trim": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+      "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+      "dev": true
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+      "dev": true
+    },
+    "trim-trailing-lines": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
+      "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
+      "dev": true
+    },
+    "trough": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+      "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+      "dev": true
+    },
+    "true-case-path": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
+      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.2"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
+      }
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true
+    },
+    "type": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+      "dev": true
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "unc-path-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+      "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+      "dev": true
+    },
+    "undertaker": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz",
+      "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "bach": "^1.0.0",
+        "collection-map": "^1.0.0",
+        "es6-weak-map": "^2.0.1",
+        "last-run": "^1.1.0",
+        "object.defaults": "^1.0.0",
+        "object.reduce": "^1.0.0",
+        "undertaker-registry": "^1.0.0"
+      }
+    },
+    "undertaker-registry": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
+      "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=",
+      "dev": true
+    },
+    "unherit": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+      "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "unified": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
+      "integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
+      "dev": true,
+      "requires": {
+        "bail": "^1.0.0",
+        "extend": "^3.0.0",
+        "is-plain-obj": "^1.1.0",
+        "trough": "^1.0.0",
+        "vfile": "^2.0.0",
+        "x-is-string": "^0.1.0"
+      }
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
+    "uniq": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+      "dev": true
+    },
+    "unique-stream": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+      "dev": true,
+      "requires": {
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "through2-filter": "^3.0.0"
+      }
+    },
+    "unist-util-find-all-after": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz",
+      "integrity": "sha512-lWgIc3rrTMTlK1Y0hEuL+k+ApzFk78h+lsaa2gHf63Gp5Ww+mt11huDniuaoq1H+XMK2lIIjjPkncxXcDp3QDw==",
+      "dev": true,
+      "requires": {
+        "unist-util-is": "^3.0.0"
+      }
+    },
+    "unist-util-is": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+      "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+      "dev": true
+    },
+    "unist-util-remove-position": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
+      "integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
+      "dev": true,
+      "requires": {
+        "unist-util-visit": "^1.1.0"
+      }
+    },
+    "unist-util-stringify-position": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
+      "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==",
+      "dev": true
+    },
+    "unist-util-visit": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+      "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+      "dev": true,
+      "requires": {
+        "unist-util-visit-parents": "^2.0.0"
+      }
+    },
+    "unist-util-visit-parents": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+      "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+      "dev": true,
+      "requires": {
+        "unist-util-is": "^3.0.0"
+      }
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        }
+      }
+    },
+    "upath": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+      "dev": true
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+      "dev": true
+    },
+    "v8flags": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz",
+      "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "value-or-function": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+      "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
+      "dev": true
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    },
+    "vfile": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
+      "integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^1.1.4",
+        "replace-ext": "1.0.0",
+        "unist-util-stringify-position": "^1.0.0",
+        "vfile-message": "^1.0.0"
+      },
+      "dependencies": {
+        "replace-ext": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+          "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+          "dev": true
+        }
+      }
+    },
+    "vfile-location": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
+      "integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA==",
+      "dev": true
+    },
+    "vfile-message": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
+      "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
+      "dev": true,
+      "requires": {
+        "unist-util-stringify-position": "^1.1.1"
+      }
+    },
+    "vinyl": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+      "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
+      "dev": true,
+      "requires": {
+        "clone": "^1.0.0",
+        "clone-stats": "^0.0.1",
+        "replace-ext": "0.0.1"
+      }
+    },
+    "vinyl-fs": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+      "dev": true,
+      "requires": {
+        "fs-mkdirp-stream": "^1.0.0",
+        "glob-stream": "^6.1.0",
+        "graceful-fs": "^4.0.0",
+        "is-valid-glob": "^1.0.0",
+        "lazystream": "^1.0.0",
+        "lead": "^1.0.0",
+        "object.assign": "^4.0.4",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.3.3",
+        "remove-bom-buffer": "^3.0.0",
+        "remove-bom-stream": "^1.2.0",
+        "resolve-options": "^1.1.0",
+        "through2": "^2.0.0",
+        "to-through": "^2.0.0",
+        "value-or-function": "^3.0.0",
+        "vinyl": "^2.0.0",
+        "vinyl-sourcemap": "^1.1.0"
+      },
+      "dependencies": {
+        "clone": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "dev": true
+        },
+        "clone-stats": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "replace-ext": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+          "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        },
+        "vinyl": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
+          "dev": true,
+          "requires": {
+            "clone": "^2.1.1",
+            "clone-buffer": "^1.0.0",
+            "clone-stats": "^1.0.0",
+            "cloneable-readable": "^1.0.0",
+            "remove-trailing-separator": "^1.0.1",
+            "replace-ext": "^1.0.0"
+          }
+        }
+      }
+    },
+    "vinyl-sourcemap": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+      "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
+      "dev": true,
+      "requires": {
+        "append-buffer": "^1.0.2",
+        "convert-source-map": "^1.5.0",
+        "graceful-fs": "^4.1.6",
+        "normalize-path": "^2.1.1",
+        "now-and-later": "^2.0.0",
+        "remove-bom-buffer": "^3.0.0",
+        "vinyl": "^2.0.0"
+      },
+      "dependencies": {
+        "clone": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "dev": true
+        },
+        "clone-stats": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
+          "dev": true
+        },
+        "replace-ext": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+          "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+          "dev": true
+        },
+        "vinyl": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
+          "dev": true,
+          "requires": {
+            "clone": "^2.1.1",
+            "clone-buffer": "^1.0.0",
+            "clone-stats": "^1.0.0",
+            "cloneable-readable": "^1.0.0",
+            "remove-trailing-separator": "^1.0.1",
+            "replace-ext": "^1.0.0"
+          }
+        }
+      }
+    },
+    "vinyl-sourcemaps-apply": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+      "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.5.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "dev": true
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "wrap-ansi": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+      "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.0",
+        "string-width": "^3.0.0",
+        "strip-ansi": "^5.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true,
+      "requires": {
+        "mkdirp": "^0.5.1"
+      }
+    },
+    "x-is-string": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
+      "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "dev": true
+    },
+    "y18n": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "dev": true
+    },
+    "yargs": {
+      "version": "13.3.2",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+      "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+      "dev": true,
+      "requires": {
+        "cliui": "^5.0.0",
+        "find-up": "^3.0.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^3.0.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^13.1.2"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^3.0.0"
+          }
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "yargs-parser": {
+      "version": "13.1.2",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "5.3.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+          "dev": true
+        }
+      }
+    }
+  }
+}
diff --git a/web/modules/paragraphs/css/package.json b/web/modules/paragraphs/css/package.json
index 5a426d2c91..827ed7460a 100644
--- a/web/modules/paragraphs/css/package.json
+++ b/web/modules/paragraphs/css/package.json
@@ -6,7 +6,7 @@
   "license": "GPL-2.0",
   "devDependencies": {
     "autoprefixer": "^7.1.3",
-    "gulp": "^3.9.1",
+    "gulp": "^4.0.0",
     "gulp-load-plugins": "^1.5.0",
     "gulp-postcss": "^7.0.0",
     "gulp-sass": "^3.1.0",
diff --git a/web/modules/paragraphs/css/paragraphs.modal.css b/web/modules/paragraphs/css/paragraphs.modal.css
index 299c77aa76..a48f555e35 100644
--- a/web/modules/paragraphs/css/paragraphs.modal.css
+++ b/web/modules/paragraphs/css/paragraphs.modal.css
@@ -4,7 +4,7 @@ ul.paragraphs-add-dialog-list {
   list-style-type: none;
 }
 
-ul.paragraphs-add-dialog-list input.field-add-more-submit {
+ul.paragraphs-add-dialog-list .button.button--small {
   background-repeat: no-repeat;
   background-position: 10px;
   background-size: auto calc(100% - 10px);
diff --git a/web/modules/paragraphs/css/paragraphs.modal.scss b/web/modules/paragraphs/css/paragraphs.modal.scss
index 96631e5ea6..fc817341c0 100644
--- a/web/modules/paragraphs/css/paragraphs.modal.scss
+++ b/web/modules/paragraphs/css/paragraphs.modal.scss
@@ -3,7 +3,7 @@ ul.paragraphs-add-dialog-list {
   padding: 0;
   list-style-type: none;
 
-  input.field-add-more-submit {
+  .button.button--small {
     background-repeat: no-repeat;
     background-position: 10px;
     background-size: auto calc(100% - 10px);
diff --git a/web/modules/paragraphs/css/paragraphs.seven.css b/web/modules/paragraphs/css/paragraphs.seven.css
new file mode 100644
index 0000000000..1224e5296c
--- /dev/null
+++ b/web/modules/paragraphs/css/paragraphs.seven.css
@@ -0,0 +1,4 @@
+.no-touchevents .button.button--small {
+  padding: 4px 1.5em;
+  font-size: 0.875rem;
+}
diff --git a/web/modules/paragraphs/css/paragraphs.seven.scss b/web/modules/paragraphs/css/paragraphs.seven.scss
new file mode 100644
index 0000000000..6cd7934f29
--- /dev/null
+++ b/web/modules/paragraphs/css/paragraphs.seven.scss
@@ -0,0 +1,9 @@
+// We added button-small class for the Claro theme UX definitions.
+// We therefore need to reset small button styles for the Seven theme.
+.no-touchevents {
+  // Need to be more specific in order to override Seven's definition.
+  .button.button--small {
+    padding: 4px 1.5em;
+    font-size: 0.875rem;
+  }
+}
diff --git a/web/modules/paragraphs/css/paragraphs.widget.css b/web/modules/paragraphs/css/paragraphs.widget.css
index a2616b936c..5d115b3eb3 100644
--- a/web/modules/paragraphs/css/paragraphs.widget.css
+++ b/web/modules/paragraphs/css/paragraphs.widget.css
@@ -137,7 +137,7 @@
   }
 }
 
-.paragraphs-tabs-wrapper .paragraphs-tabs {
+.paragraphs-tabs-wrapper .paragraphs-tabs-hide {
   display: none;
 }
 
@@ -211,12 +211,15 @@
 }
 
 .js .field--widget-paragraphs .field-multiple-drag {
-  vertical-align: top;
+  vertical-align: middle;
+  min-width: 40px;
 }
 
 .js .field--widget-paragraphs .draggable .tabledrag-handle {
-  min-width: 50px;
   margin-left: 0;
+  margin-top: 3px;
+  padding-right: .25em;
+  width: 23px;
 }
 
 .js .field--widget-paragraphs .draggable .tabledrag-handle:focus::before {
@@ -224,8 +227,24 @@
   margin-right: .1em;
 }
 
+.js .field--widget-paragraphs .draggable .tabledrag-handle::after {
+  margin-left: 0;
+  padding: .5rem;
+}
+
+.js .field--widget-paragraphs .draggable .tabledrag-handle:hover .handle {
+  -webkit-transform: scale(1.25);
+          transform: scale(1.25);
+}
+
+.js .field--widget-paragraphs .tabledrag-changed {
+  text-decoration: none;
+}
+
 .js .field--widget-paragraphs .tabledrag-handle .handle {
   height: 22px;
+  margin-left: 0;
+  margin-right: 0;
 }
 
 .js .field--widget-paragraphs .delta-order {
@@ -375,6 +394,11 @@ tr:hover .paragraphs-description::after {
   background: #057ec7 none;
 }
 
+.paragraphs-dragdrop__item .paragraphs-summary-wrapper .paragraphs-description .paragraphs-content-wrapper,
+.paragraphs-dragdrop__item .paragraphs-summary-wrapper .paragraphs-description .paragraphs-plugin-wrapper {
+  font-size: 81.3%;
+}
+
 .paragraph--view-mode--preview {
   padding-right: 1em;
 }
diff --git a/web/modules/paragraphs/css/paragraphs.widget.scss b/web/modules/paragraphs/css/paragraphs.widget.scss
index 3dedd0b966..a14f7fa172 100644
--- a/web/modules/paragraphs/css/paragraphs.widget.scss
+++ b/web/modules/paragraphs/css/paragraphs.widget.scss
@@ -1,6 +1,6 @@
 //
 // @file
-// Experimental paragraphs widget CSS.
+// Stable paragraphs widget CSS.
 //
 
 @import "variables";
@@ -58,7 +58,7 @@
 
 
 .paragraphs-tabs-wrapper {
-  .paragraphs-tabs {
+  .paragraphs-tabs-hide {
     display: none;
   }
 }
@@ -143,12 +143,15 @@
     }
 
     .field-multiple-drag {
-      vertical-align: top;
+      vertical-align: middle;
+      min-width: 40px;
     }
 
     .draggable .tabledrag-handle {
-      min-width: 50px;
       margin-left: 0;
+      margin-top: 3px;
+      padding-right: .25em;
+      width: 23px;
 
       // Fix active focus.
       &:focus {
@@ -157,10 +160,27 @@
           margin-right: .1em;
         }
       }
+
+      // Claro theme fix for the handle icon position.
+      &::after {
+        margin-left: 0;
+        padding: .5rem;
+      }
+
+      // Scale the icon on hover.
+      &:hover .handle {
+        transform: scale(1.25);
+      }
+    }
+
+    .tabledrag-changed {
+      text-decoration: none;
     }
 
     .tabledrag-handle .handle {
       height: 22px;
+      margin-left: 0;
+      margin-right: 0;
     }
 
     .delta-order {
@@ -291,6 +311,17 @@
   }
 }
 
+.paragraphs-dragdrop__item {
+  .paragraphs-summary-wrapper {
+    .paragraphs-description {
+      .paragraphs-content-wrapper,
+      .paragraphs-plugin-wrapper {
+        font-size: 81.3%;
+      }
+    }
+  }
+}
+
 .paragraph--view-mode--preview {
   padding-right: 1em;
 }
diff --git a/web/modules/paragraphs/js/paragraphs.actions.js b/web/modules/paragraphs/js/paragraphs.actions.js
index 27e2d48f0d..90792cb0cf 100644
--- a/web/modules/paragraphs/js/paragraphs.actions.js
+++ b/web/modules/paragraphs/js/paragraphs.actions.js
@@ -3,7 +3,7 @@
  * Paragraphs actions JS code for paragraphs actions button.
  */
 
-(function ($, Drupal) {
+(function ($, Drupal, once) {
 
   'use strict';
 
@@ -17,7 +17,7 @@
    */
   Drupal.behaviors.paragraphsActions = {
     attach: function (context, settings) {
-      var $actionsElement = $(context).find('.paragraphs-dropdown').once('paragraphs-dropdown');
+      var $actionsElement = $(once('paragraphs-dropdown', '.paragraphs-dropdown', context));
       // Attach event handlers to toggle button.
       $actionsElement.each(function () {
         var $this = $(this);
@@ -40,4 +40,4 @@
     }
   };
 
-})(jQuery, Drupal);
+})(jQuery, Drupal, once);
diff --git a/web/modules/paragraphs/js/paragraphs.add_above_button.js b/web/modules/paragraphs/js/paragraphs.add_above_button.js
index cc49ca15f8..6f1e85987f 100644
--- a/web/modules/paragraphs/js/paragraphs.add_above_button.js
+++ b/web/modules/paragraphs/js/paragraphs.add_above_button.js
@@ -3,7 +3,7 @@
  * Paragraphs actions JS code for paragraphs actions button.
  */
 
-(function ($, Drupal) {
+(function ($, Drupal, once) {
 
   'use strict';
 
@@ -13,19 +13,35 @@
    * @param event
    *   Click event.
    */
-  var clickHandler = function(event) {
+  var clickHandler = function (event) {
     event.preventDefault();
+    // We need to stop event propagation in order to prevent triggering jQuery
+    // UI dialog.js mousedown method. This method order call is not predictable.
+    // When we are in dialog for editing reusable library (parent dialog) then
+    // for 'Add Paragraph' button it will be called before child dialog
+    // creation, but for 'Add above' button it will be called after child dialog
+    // creation and this will result in moving parent dialog in front of
+    // child dialog.
+    event.stopPropagation();
+
     var $button = $(this);
-    var $add_more_wrapper = $button.closest('table').siblings('.clearfix').find('.paragraphs-add-dialog');
 
     // Find delta for row without interference of unrelated table rows.
     var $anchorRow = $button.closest('tr');
     var delta = $anchorRow.parent().find('> .draggable').index($anchorRow);
+    // We need the siblings function to avoid finding the 'Add paragraph' button inside a container.
+    var $add_more_wrapper = $button.closest('.field-multiple-table').siblings('.clearfix,.form-actions').find('.paragraphs-add-wrapper');
 
     // Set delta before opening of dialog.
-    $add_more_wrapper.parent().find('.paragraph-type-add-modal-delta').val(delta);
+    $add_more_wrapper.find('.paragraph-type-add-delta').val(delta);
 
-    Drupal.paragraphsAddModal.openDialog($add_more_wrapper, Drupal.t('Add above'));
+    // If the add mode is modal open the dialog, otherwise press the add button.
+    if ($add_more_wrapper.find('.paragraph-type-add-delta').hasClass('modal')) {
+      Drupal.paragraphsAddModal.openDialog($add_more_wrapper.find('.paragraphs-add-dialog'), Drupal.t('Add above'));
+    }
+    else {
+      $add_more_wrapper.find('.field-add-more-submit').trigger('mousedown');
+    }
   };
 
   /**
@@ -35,18 +51,28 @@
    */
   Drupal.behaviors.paragraphsAddAboveButton = {
     attach: function (context, settings) {
-      $('.paragraphs-dropdown-actions', context).once('paragraphs-add-above-button').each(function () {
+      $(once('paragraphs-add-above-button', '.paragraphs-dropdown-actions', context)).each(function () {
         var $actions = $(this);
         if ($actions.closest('.paragraph-top').hasClass('add-above-on')) {
-          var $button = $('<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button js-form-submit form-submit" type="submit" value="' + Drupal.t('Add above') + '">');
-          // "Mousedown" is used since the original actions created by paragraphs
-          // use the event "focusout" to hide the actions dropdown.
-          $button.on('mousedown', clickHandler);
+          var $add_above = false;
+          var $add_more_wrapper = $actions.closest('.field-multiple-table').siblings('.clearfix,.form-actions').find('.paragraphs-add-wrapper');
+          // The Add Above button is added when the add mode is modal or when
+          // there is only one add button in the other add modes.
+          if ($add_more_wrapper.find('.paragraph-type-add-delta').hasClass('modal') || $add_more_wrapper.find('.field-add-more-submit').length === 1) {
+            $add_above = true;
+          }
+          // Prepend the Add above button only if there is only one button.
+          if ($add_above) {
+            var $button = $('<input class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button button--small js-form-submit form-submit" type="submit" onClick="return false;" value="' + Drupal.t('Add above') + '">');
+            // "Mousedown" is used since the original actions created by
+            // paragraphs use the event "focusout" to hide the actions dropdown.
+            $button.on('mousedown', clickHandler);
 
-          $actions.prepend($button);
+            $actions.prepend($button);
+          }
         }
       });
     }
   };
 
-})(jQuery, Drupal);
+})(jQuery, Drupal, once);
diff --git a/web/modules/paragraphs/js/paragraphs.admin.js b/web/modules/paragraphs/js/paragraphs.admin.js
index f0696cb952..b7fb3e11a2 100644
--- a/web/modules/paragraphs/js/paragraphs.admin.js
+++ b/web/modules/paragraphs/js/paragraphs.admin.js
@@ -1,4 +1,4 @@
-(function ($, Drupal) {
+(function ($, Drupal, once) {
 
   'use strict';
 
@@ -18,12 +18,14 @@
   *   Main paragraph region.
   */
   var setUpTab = function ($parWidget, $parTabs, $parContent, $parBehavior, $mainRegion) {
-    var $tabContent = $parTabs.find('#content');
-    var $tabBehavior = $parTabs.find('#behavior');
+    var $tabContent = $parTabs.find('.paragraphs_content_tab');
+    var $tabBehavior = $parTabs.find('.paragraphs_behavior_tab');
     if ($tabBehavior.hasClass('is-active')) {
       $parWidget.removeClass('content-active').addClass('behavior-active');
       $tabContent.removeClass('is-active');
+      $tabContent.find('a').removeClass('is-active');
       $tabBehavior.addClass('is-active');
+      $tabBehavior.find('a').addClass('is-active');
     }
     else {
       // Activate content tab visually if there is no previously
@@ -31,12 +33,13 @@
       if (!($mainRegion.hasClass('content-active'))
         && !($mainRegion.hasClass('behavior-active'))) {
         $tabContent.addClass('is-active');
+        $tabContent.find('a').addClass('is-active');
         $parWidget.addClass('content-active');
       }
 
-      $parTabs.show();
+      $parTabs.removeClass('paragraphs-tabs-hide');
       if ($parBehavior.length === 0) {
-        $parTabs.hide();
+        $parTabs.addClass('paragraphs-tabs-hide');
       }
     }
   };
@@ -54,10 +57,12 @@
     var $clickedTabParent = $clickedTab.parent();
 
     $parTabs.find('li').removeClass('is-active');
+    $parTabs.find('li').find('a').removeClass('is-active');
     $clickedTabParent.addClass('is-active');
+    $clickedTabParent.find('a').addClass('is-active');
 
     $parWidget.removeClass('behavior-active content-active');
-    if ($clickedTabParent.attr('id') === 'content') {
+    if ($clickedTabParent.hasClass('paragraphs_content_tab')) {
       $parWidget.addClass('content-active');
       $parWidget.find('.paragraphs-add-wrapper').parent().removeClass('hidden');
     }
@@ -131,7 +136,7 @@
       });
 
       // Initialization.
-      $topLevelParWidgets.once('paragraphs-bodytabs').each(function() {
+      $(once('paragraphs-bodytabs', $topLevelParWidgets)).each(function() {
         var $parWidget = $(this);
         var $parTabs = $parWidget.find('.paragraphs-tabs');
 
@@ -185,5 +190,5 @@
       }
     }
   };
-})(jQuery, Drupal);
+})(jQuery, Drupal, once);
 
diff --git a/web/modules/paragraphs/js/paragraphs.modal.js b/web/modules/paragraphs/js/paragraphs.modal.js
index 16128f17aa..a8a7057aac 100644
--- a/web/modules/paragraphs/js/paragraphs.modal.js
+++ b/web/modules/paragraphs/js/paragraphs.modal.js
@@ -3,7 +3,7 @@
  *
  */
 
-(function ($, Drupal) {
+(function ($, Drupal, once) {
 
   'use strict';
 
@@ -14,7 +14,7 @@
    */
   Drupal.behaviors.paragraphsModalAdd = {
     attach: function (context) {
-      $('.paragraph-type-add-modal-button', context).once('add-click-handler').on('click', function (event) {
+      $(once('add-click-handler', '.paragraph-type-add-modal-button', context)).on('click', function (event) {
         var $button = $(this);
         Drupal.paragraphsAddModal.openDialog($button.parent().siblings('.paragraphs-add-dialog'), $button.val());
 
@@ -47,7 +47,7 @@
     var $element = $(element);
 
     // Get the delta element before moving $element to dialog element.
-    var $modalDelta = $element.parent().find('.paragraph-type-add-modal-delta');
+    var $modalDelta = $element.parent().find('.paragraph-type-add-delta');
 
     // Deep clone with all attached events. We need to work on cloned element
     // and not directly on origin because Drupal dialog.ajax.js
@@ -67,7 +67,7 @@
     // Close the dialog after a button was clicked.
     // Use mousedown event, because we are using ajax in the modal add mode
     // which explicitly suppresses the click event.
-    $element.once().find('.field-add-more-submit').on('mousedown', function () {
+    $(once('paragraphs-add-more-submit-modal', $element.find('.field-add-more-submit'))).on('mousedown', function () {
       dialog.close();
     });
 
@@ -86,4 +86,4 @@
     }
   });
 
-})(jQuery, Drupal);
+})(jQuery, Drupal, once);
diff --git a/web/modules/paragraphs/migrations/d7_field_collection.yml b/web/modules/paragraphs/migrations/d7_field_collection.yml
new file mode 100644
index 0000000000..a7077d36cf
--- /dev/null
+++ b/web/modules/paragraphs/migrations/d7_field_collection.yml
@@ -0,0 +1,21 @@
+id: d7_field_collection
+label: Field Collections
+migration_tags:
+  - Drupal 7
+  - Content
+  - Field Collection Content
+deriver: Drupal\paragraphs\Plugin\migrate\D7FieldCollectionItemDeriver
+source:
+  plugin: d7_field_collection_item
+process:
+  type: bundle
+  # @todo Get the langcode from the parent entity.
+  # See https://drupal.org/i/3146632.
+  # langcode: langcode
+destination:
+  plugin: entity_reference_revisions:paragraph
+migration_dependencies:
+  required:
+    - d7_field_collection_type
+  optional:
+    - d7_field_instance
diff --git a/web/modules/paragraphs/migrations/d7_field_collection_revisions.yml b/web/modules/paragraphs/migrations/d7_field_collection_revisions.yml
new file mode 100644
index 0000000000..01ca0e3e82
--- /dev/null
+++ b/web/modules/paragraphs/migrations/d7_field_collection_revisions.yml
@@ -0,0 +1,30 @@
+id: d7_field_collection_revisions
+label: Field Collection Revisions
+migration_tags:
+  - Drupal 7
+  - Content
+  - Field Collection Revisions Content
+deriver: Drupal\paragraphs\Plugin\migrate\D7FieldCollectionItemDeriver
+source:
+  plugin: d7_field_collection_item_revision
+process:
+  id:
+    -
+      plugin: paragraphs_lookup
+      tags:
+        - Field Collection Content
+      source: item_id
+    -
+      plugin: extract
+      index:
+        - id
+  type: bundle
+  # @todo Get the langcode from the parent entity revision.
+  # See https://drupal.org/i/3146632.
+  # langcode: langcode
+destination:
+  plugin: entity_reference_revisions:paragraph
+  new_revisions: TRUE
+migration_dependencies:
+  required:
+    - d7_field_collection
diff --git a/web/modules/paragraphs/migrations/d7_field_collection_type.yml b/web/modules/paragraphs/migrations/d7_field_collection_type.yml
index 79227c3a22..b0cdcebcba 100644
--- a/web/modules/paragraphs/migrations/d7_field_collection_type.yml
+++ b/web/modules/paragraphs/migrations/d7_field_collection_type.yml
@@ -2,6 +2,7 @@ id: d7_field_collection_type
 label: Paragraphs - Field Collection type configuration
 migration_tags:
   - Drupal 7
+  - Configuration
 source:
   plugin: d7_field_collection_type
   add_description: true
diff --git a/web/modules/paragraphs/migrations/d7_paragraphs.yml b/web/modules/paragraphs/migrations/d7_paragraphs.yml
new file mode 100644
index 0000000000..89ab1664d8
--- /dev/null
+++ b/web/modules/paragraphs/migrations/d7_paragraphs.yml
@@ -0,0 +1,21 @@
+id: d7_paragraphs
+label: Paragraphs
+migration_tags:
+  - Drupal 7
+  - Content
+  - Paragraphs Content
+deriver: Drupal\paragraphs\Plugin\migrate\D7ParagraphsItemDeriver
+source:
+  plugin: d7_paragraphs_item
+process:
+  type: bundle
+  # @todo Get the langcode from the parent entity.
+  # See https://drupal.org/i/3146632.
+  # langcode: langcode
+destination:
+  plugin: entity_reference_revisions:paragraph
+migration_dependencies:
+  required:
+    - d7_paragraphs_type
+  optional:
+    - d7_field_instance
diff --git a/web/modules/paragraphs/migrations/d7_paragraphs_revisions.yml b/web/modules/paragraphs/migrations/d7_paragraphs_revisions.yml
new file mode 100644
index 0000000000..676fa1c599
--- /dev/null
+++ b/web/modules/paragraphs/migrations/d7_paragraphs_revisions.yml
@@ -0,0 +1,30 @@
+id: d7_paragraphs_revisions
+label: Paragraphs Revisions
+migration_tags:
+  - Drupal 7
+  - Content
+  - Paragraphs Revisions Content
+deriver: Drupal\paragraphs\Plugin\migrate\D7ParagraphsItemDeriver
+source:
+  plugin: d7_paragraphs_item_revision
+process:
+  id:
+    -
+      plugin: paragraphs_lookup
+      tags:
+        - Paragraphs Content
+      source: item_id
+    -
+      plugin: extract
+      index:
+        - id
+  type: bundle
+  # @todo Get the langcode from the parent entity revision.
+  # See https://drupal.org/i/3146632.
+  # langcode: langcode
+destination:
+  plugin: entity_reference_revisions:paragraph
+  new_revisions: TRUE
+migration_dependencies:
+  required:
+    - d7_paragraphs
diff --git a/web/modules/paragraphs/migrations/d7_paragraphs_type.yml b/web/modules/paragraphs/migrations/d7_paragraphs_type.yml
index ac38f5bf49..2d385f7dba 100644
--- a/web/modules/paragraphs/migrations/d7_paragraphs_type.yml
+++ b/web/modules/paragraphs/migrations/d7_paragraphs_type.yml
@@ -2,6 +2,7 @@ id: d7_paragraphs_type
 label: Paragraphs type configuration
 migration_tags:
   - Drupal 7
+  - Configuration
 source:
   plugin: d7_paragraphs_type
   add_description: true
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml b/web/modules/paragraphs/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
index a415b8a8bb..6086fb41e2 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
+++ b/web/modules/paragraphs/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
@@ -40,11 +40,6 @@ content:
     weight: 2
     settings: {  }
     third_party_settings: {  }
-  path:
-    type: path
-    weight: 30
-    settings: {  }
-    third_party_settings: {  }
   promote:
     type: boolean_checkbox
     weight: 15
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
index 0a67b970e1..d1e0859b28 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_demo/paragraphs_demo.info.yml
@@ -1,5 +1,5 @@
 description: 'Provides multilingual demo Paragraphs types.'
-core_version_requirement: ^8.7.7 || ^9
+core_version_requirement: ^9.3 || ^10
 dependencies:
   - paragraphs:paragraphs
   - drupal:field
@@ -21,7 +21,7 @@ name: Paragraphs Demo
 package: Paragraphs
 type: module
 
-# Information added by Drupal.org packaging script on 2020-05-21
-version: '8.x-1.12'
+# Information added by Drupal.org packaging script on 2022-08-25
+version: '8.x-1.15'
 project: 'paragraphs'
-datestamp: 1590061337
+datestamp: 1661440900
diff --git a/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
index 56ab0fb793..4f199f6082 100644
--- a/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_demo/tests/src/Functional/ParagraphsDemoTest.php
@@ -19,7 +19,7 @@ class ParagraphsDemoTest extends BrowserTestBase {
    *
    * @var string[]
    */
-  public static $modules = array(
+  protected static $modules = array(
     'paragraphs_demo',
     'block',
   );
@@ -32,11 +32,9 @@ class ParagraphsDemoTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
   }
 
   /**
@@ -81,9 +79,9 @@ public function testConfigurationsAndCreation() {
 
     // Set edit mode to open.
     $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display');
-    $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit");
+    $this->submitForm([], "field_paragraphs_demo_settings_edit");
     $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check for all pre-configured paragraphs_types.
     $this->drupalGet('admin/structure/paragraphs_type');
@@ -144,7 +142,7 @@ public function testConfigurationsAndCreation() {
 
     $this->drupalGet('node/add/paragraphed_content_demo');
     $this->assertSession()->responseContains('<h4 class="label">Paragraphs</h4>');
-    $this->drupalPostForm(NULL, NULL, t('Add Text'));
+    $this->submitForm([], 'Add Text');
     $this->assertSession()->responseNotContains('<strong data-drupal-selector="edit-field-paragraphs-demo-title">Paragraphs</strong>');
     $this->assertSession()->responseContains('<h4 class="label">Paragraphs</h4>');
     $edit = array(
@@ -152,11 +150,11 @@ public function testConfigurationsAndCreation() {
       'moderation_state[0][state]' => 'published',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Paragraph text',
     );
-    $this->drupalPostForm(NULL, $edit, t('Add User'));
+    $this->submitForm($edit, 'Add User');
     $edit = [
       'field_paragraphs_demo[1][subform][field_user_demo][0][target_id]' => $admin_user->label() . ' (' . $admin_user->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $this->assertSession()->pageTextContains('Paragraphed article Paragraph title has been created.');
     $this->assertSession()->pageTextContains('Paragraph title');
@@ -173,7 +171,7 @@ public function testConfigurationsAndCreation() {
     $this->assertSession()->responseNotContains('Welcome to the Paragraphs Demo module!');
 
     // Check that the dropbutton of Nested Paragraph has the Duplicate function.
-    // For now, this indicates that it is using the EXPERIMENTAL widget.
+    // For now, this indicates that it is using the stable widget.
     $this->drupalGet('node/1/edit');
     $this->assertSession()->buttonExists('field_paragraphs_demo_3_subform_field_paragraphs_demo_0_duplicate');
 
diff --git a/web/modules/paragraphs/modules/paragraphs_library/config/install/core.entity_view_display.paragraphs_library_item.paragraphs_library_item.summary.yml b/web/modules/paragraphs/modules/paragraphs_library/config/install/core.entity_view_display.paragraphs_library_item.paragraphs_library_item.summary.yml
index 22f6fb5240..7325396cc4 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/config/install/core.entity_view_display.paragraphs_library_item.paragraphs_library_item.summary.yml
+++ b/web/modules/paragraphs/modules/paragraphs_library/config/install/core.entity_view_display.paragraphs_library_item.paragraphs_library_item.summary.yml
@@ -21,7 +21,7 @@ content:
     third_party_settings: {  }
   paragraphs:
     label: hidden
-    type: paragraph_summary
+    type: library_item_summary
     weight: 0
     region: content
     settings: {  }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
index f2372be3de..0c206d263c 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.info.yml
@@ -1,7 +1,7 @@
 name: Paragraphs Library
 type: module
 description: 'Provides a library for reusing paragraphs.'
-core_version_requirement: ^8.7.7 || ^9
+core_version_requirement: ^9.3 || ^10
 package: Paragraphs
 configure: paragraphs_library_item.settings
 dependencies:
@@ -11,7 +11,7 @@ dependencies:
 test_dependencies:
   - entity_browser:entity_browser
 
-# Information added by Drupal.org packaging script on 2020-05-21
-version: '8.x-1.12'
+# Information added by Drupal.org packaging script on 2022-08-25
+version: '8.x-1.15'
 project: 'paragraphs'
-datestamp: 1590061337
+datestamp: 1661440900
diff --git a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
index d2e4829de7..4a1f1a604d 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
+++ b/web/modules/paragraphs/modules/paragraphs_library/paragraphs_library.module
@@ -139,7 +139,7 @@ function paragraphs_library_preprocess_paragraph(&$variables) {
     // Only replace the content if access is allowed to the library. Access
     // cacheability metadata is already returned by the original widget in case
     // access is not allowed.
-    if ($library_item->access('view')) {
+    if ($library_item->access('view') && isset($variables['elements']['field_reusable_paragraph'][0]['#view_mode'])) {
       $view_builder = \Drupal::entityTypeManager()
         ->getViewBuilder('paragraphs_library_item');
       $library_item_render_array = $view_builder->view($library_item, $variables['elements']['field_reusable_paragraph'][0]['#view_mode']);
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
index 138afb4810..fde2eb0149 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Controller/LibraryItemController.php
@@ -196,6 +196,7 @@ protected function getRevisionIds(LibraryItemInterface $library_item) {
     $result = $this->entityTypeManager->getStorage('paragraphs_library_item')->getQuery()
       ->allRevisions()
       ->condition('id', $library_item->id())
+      ->accessCheck(TRUE)
       ->sort($library_item->getEntityType()->getKey('revision'), 'DESC')
       ->pager(50)
       ->execute();
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
index 3dfe46a230..0b3cde3895 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Entity/LibraryItem.php
@@ -267,6 +267,11 @@ public static function createFromParagraph(ParagraphInterface $paragraph) {
       'langcode' => $paragraph->language()->getId(),
     ]);
 
+    // If the item has a moderation field, set it to published.
+    if ($library_item->hasField('moderation_state')) {
+      $library_item->set('moderation_state', 'published');
+    }
+
     // Build the label in each available translation and ensure the translations
     // exist.
     foreach ($duplicate_paragraph->getTranslationLanguages() as $langcode => $language) {
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
index a2ed4c6124..64dd676a6f 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemForm.php
@@ -50,10 +50,10 @@ public function save(array $form, FormStateInterface $form_state) {
     parent::save($form, $form_state);
     $form_state->setRedirect('entity.paragraphs_library_item.collection');
     if ($insert) {
-      $this->messenger->addMessage(t('Paragraph %label has been created.', ['%label' => $this->entity->label()]));
+      $this->messenger->addMessage($this->t('Paragraph %label has been created.', ['%label' => $this->entity->label()]));
     }
     else {
-      $this->messenger->addMessage(t('Paragraph %label has been updated.', ['%label' => $this->entity->label()]));
+      $this->messenger->addMessage($this->t('Paragraph %label has been updated.', ['%label' => $this->entity->label()]));
     }
   }
 
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
index 3d2f3fb61e..7bff0f850b 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemRevisionRevertForm.php
@@ -102,7 +102,7 @@ public function getQuestion() {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     $original_revision_timestamp = $this->revision->getChangedTime();
     $this->revision = $this->prepareRevertedRevision($this->revision);
-    $this->revision->revision_log = t('Copy of the revision from %date.', [
+    $this->revision->revision_log = $this->t('Copy of the revision from %date.', [
       '%date' => $this->dateFormatter->format($original_revision_timestamp)
     ]);
     $this->revision->setChangedTime($this->time->getRequestTime());
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemSettingsForm.php b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemSettingsForm.php
index 718ae99f6b..f59433bddb 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemSettingsForm.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Form/LibraryItemSettingsForm.php
@@ -30,7 +30,7 @@ protected function getEditableConfigNames() {
   public function buildForm(array $form, FormStateInterface $form_state) {
     // This exists to make the field UI pages visible and must not be removed.
     $form['account'] = array(
-      '#markup' => '<p>' . t('There are no settings yet.') . '</p>',
+      '#markup' => '<p>' . $this->t('There are no settings yet.') . '</p>',
     );
 
     return $form;
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Field/FieldFormatter/LibraryItemSummaryFormatter.php b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Field/FieldFormatter/LibraryItemSummaryFormatter.php
new file mode 100644
index 0000000000..2fb4fcfc54
--- /dev/null
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Plugin/Field/FieldFormatter/LibraryItemSummaryFormatter.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\paragraphs_library\Plugin\Field\FieldFormatter;
+
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\paragraphs\Plugin\Field\FieldFormatter\ParagraphsSummaryFormatter;
+
+/**
+ * Plugin implementation of the 'paragraph_summary' formatter.
+ *
+ * @FieldFormatter(
+ *   id = "library_item_summary",
+ *   label = @Translation("Library item summary"),
+ *   field_types = {
+ *     "entity_reference_revisions"
+ *   }
+ * )
+ */
+class LibraryItemSummaryFormatter extends ParagraphsSummaryFormatter {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewElements(FieldItemListInterface $items, $langcode) {
+    $elements = parent::viewElements($items, $langcode);
+    if (!$items->getEntity()->isPublished()) {
+      $published = [
+        '#theme' => 'paragraphs_info_icon',
+        '#message' => $this->t('Unpublished'),
+        '#icon' => 'view',
+      ];
+      $elements[0]['info'] += $published;
+    }
+    return $elements;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isApplicable(FieldDefinitionInterface $field_definition) {
+    if ($field_definition->getTargetEntityTypeId() == 'paragraphs_library_item' && $field_definition->getName() == 'paragraphs') {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+}
diff --git a/web/modules/paragraphs/modules/paragraphs_library/src/Routing/LibraryItemRouteProvider.php b/web/modules/paragraphs/modules/paragraphs_library/src/Routing/LibraryItemRouteProvider.php
index d6c89d6a5b..e55fe4b088 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/src/Routing/LibraryItemRouteProvider.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/src/Routing/LibraryItemRouteProvider.php
@@ -15,9 +15,14 @@ class LibraryItemRouteProvider extends DefaultHtmlRouteProvider {
    */
   public function getRoutes(EntityTypeInterface $entity_type) {
     $route_collection = parent::getRoutes($entity_type);
-    // Display library items using default theme.
     if ($canonical_route = $route_collection->get("entity.{$entity_type->id()}.canonical")) {
+      // Display library items using default theme.
       $canonical_route->setOption('_admin_route', FALSE);
+
+      // Restrict access based on permission.
+      $canonical_route->addRequirements([
+        '_permission' => 'administer paragraphs library+create paragraph library item+edit paragraph library item',
+      ]);
     }
     return $route_collection;
   }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
index 94f7c1291b..4af581cc7d 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/MultilingualBehaviorTest.php
@@ -3,7 +3,7 @@
 namespace Drupal\Tests\paragraphs_library\Functional;
 
 use Drupal\language\Entity\ConfigurableLanguage;
-use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetStable\ParagraphsTestBase;
 
 /**
  * Tests paragraphs library multilingual functionality.
@@ -11,12 +11,12 @@
  * @package Drupal\paragraphs_library\Tests
  * @group paragraphs_library
  */
-class MultilingualBehaviorTest extends ParagraphsExperimentalTestBase {
+class MultilingualBehaviorTest extends ParagraphsTestBase {
 
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'language',
     'content_translation',
     'paragraphs_library',
@@ -25,7 +25,7 @@ class MultilingualBehaviorTest extends ParagraphsExperimentalTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     $this->addParagraphedContentType('paragraphed_test');
@@ -49,7 +49,8 @@ public function setUp() {
     $edit = [
       'language_configuration[content_translation]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test', $edit, 'Save content type');
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test');
+    $this->submitForm($edit, 'Save content type');
 
     $this->fieldUIAddNewField('admin/structure/paragraphs_type/test_content', 'paragraphs_text', 'Test content', 'text_long', [], []);
 
@@ -70,7 +71,8 @@ public function setUp() {
       'settings[paragraph][test_content][fields][field_paragraphs_text]' => TRUE,
       'settings[paragraphs_library_item][paragraphs_library_item][translatable]' => TRUE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, 'Save configuration');
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
@@ -79,13 +81,13 @@ public function setUp() {
   public function testReuseTranslationForNestedParagraphFromLibrary() {
     // Add nested paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->submitForm([], 'paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph En label Test nested paragraph has been created.');
 
     // Translate nested paragraphs library item.
@@ -95,23 +97,24 @@ public function testReuseTranslationForNestedParagraphFromLibrary() {
       'label[0][value]' => 'De label Test geschachtelten Absatz',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test in geschachteltem Absatz.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add translation for test node.
     $node = $this->drupalGetNodeByTitle('En label Test node nested');
     $edit = [
       'title[0][value]' => 'De label Test geschachtelten Absatz',
     ];
-    $this->drupalPostForm('de/node/' . $node->id() . '/translations/add/en/de', $edit, 'Save (this translation)');
+    $this->drupalGet('de/node/' . $node->id() . '/translations/add/en/de');
+    $this->submitForm($edit, 'Save (this translation)');
 
     $this->drupalGet('node/' . $node->id());
     $this->assertSession()->pageTextContains('En label Example text for test in nested paragraph.');
@@ -123,7 +126,8 @@ public function testReuseTranslationForNestedParagraphFromLibrary() {
     $edit = [
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test geander.',
     ];
-    $this->drupalPostForm('de/admin/content/paragraphs/1/edit', $edit, 'Save');
+    $this->drupalGet('de/admin/content/paragraphs/1/edit');
+    $this->submitForm($edit, 'Save');
 
     // Check updated content.
     $this->drupalGet('de/node/' . $node->id());
@@ -138,13 +142,13 @@ public function testMoveTranslatedNestedParagraphToLibrary() {
 
     // Add node with text paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add translation for node.
     $node = $this->drupalGetNodeByTitle('En label Test node nested');
@@ -154,12 +158,12 @@ public function testMoveTranslatedNestedParagraphToLibrary() {
       'title[0][value]' => 'Testknoten',
       'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test in geschachteltem Absatz.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save (this translation)');
+    $this->submitForm($edit, 'Save (this translation)');
 
     // Convert translated paragraph to library.
     $this->drupalGet($node->toUrl('edit-form'));
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_promote_to_library');
-    $this->drupalPostForm(NULL, NULL, 'Save (this translation)');
+    $this->submitForm([], 'field_paragraphs_0_promote_to_library');
+    $this->submitForm([], 'Save (this translation)');
 
     // Check translation.
     $this->drupalGet($node->toUrl());
@@ -173,6 +177,86 @@ public function testMoveTranslatedNestedParagraphToLibrary() {
     $this->assertSession()->pageTextContains('De label Beispieltext fur den Test in geschachteltem Absatz.');
   }
 
+  /**
+   * Tests converting moderated translated nested paragraph into library.
+   */
+  public function testMoveModeratedTranslatedNestedParagraphToLibrary() {
+    $this->container->get('module_installer')->install(['content_moderation']);
+    $this->createEditorialWorkflow('paragraphed_test');
+
+    $this->loginAsAdmin([
+      'access administration pages',
+      'view any unpublished content',
+      'view all revisions',
+      'revert all revisions',
+      'view latest version',
+      'view any unpublished content',
+      'use ' . $this->workflow->id() . ' transition create_new_draft',
+      'use ' . $this->workflow->id() . ' transition publish',
+      'use ' . $this->workflow->id() . ' transition archived_published',
+      'use ' . $this->workflow->id() . ' transition archived_draft',
+      'use ' . $this->workflow->id() . ' transition archive',
+      'administer nodes',
+      'bypass node access',
+      'administer content translation',
+      'translate any entity',
+      'create content translations',
+      'administer languages',
+      'administer content types',
+      'administer node form display',
+      'edit any paragraphed_test content',
+      'create paragraphed_test content',
+      'edit behavior plugin settings',
+      'administer paragraphs library',
+      'administer workflows'
+    ]);
+
+    $this->drupalGet('admin/config/workflow/workflows/manage/' . $this->workflow->id() . '/type/paragraphs_library_item');
+    $edit = [
+      'bundles[paragraphs_library_item]' => 1,
+    ];
+    $this->submitForm($edit, 'Save');
+
+    $this->enableConvertingParagraphsTypeToLibrary('nested_paragraph');
+
+    // Add node with text paragraph.
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_err_field_test_content_add_more');
+    $edit = [
+      'title[0][value]' => 'En label Test node nested',
+      'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test in nested paragraph',
+      'moderation_state[0][state]' => 'published'
+    ];
+    $this->submitForm($edit, 'Save');
+
+    // Add translation for node.
+    $node = $this->drupalGetNodeByTitle('En label Test node nested');
+    $this->drupalGet('node/' . $node->id() . '/translations');
+    $this->clickLink('Add');
+    $edit = [
+      'title[0][value]' => 'Testknoten',
+      'field_paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test in geschachteltem Absatz.',
+    ];
+    $this->submitForm($edit, 'Save (this translation)');
+
+    // Convert translated paragraph to library.
+    $this->drupalGet($node->toUrl('edit-form'));
+    $this->submitForm([], 'field_paragraphs_0_promote_to_library');
+    $this->submitForm([], 'Save (this translation)');
+
+    // Visible to admins.
+    $this->drupalGet($node->toUrl());
+    $this->assertSession()->pageTextContains('En label Example text for test in nested paragraph');
+    $this->drupalGet('de/node/' . $node->id());
+    $this->assertSession()->pageTextContains('De label Beispieltext fur den Test in geschachteltem Absatz.');
+
+    // And to anonymous users as well.
+    $this->drupalLogout();
+    $this->drupalGet('de/node/' . $node->id());
+    $this->assertSession()->pageTextContains('De label Beispieltext fur den Test in geschachteltem Absatz.');
+  }
+
   /**
    * Tests converting translated nested paragraph from library.
    */
@@ -181,13 +265,13 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
 
     // Add paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->submitForm([], 'paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph En label Test nested paragraph has been created.');
 
     // Translate nested paragraphs library item.
@@ -197,23 +281,24 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
       'label[0][value]' => 'De label Test geschachtelten Absatz',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test in geschachteltem Absatz.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add translation for test node.
     $node = $this->drupalGetNodeByTitle('En label Test node nested');
     $edit = [
       'title[0][value]' => 'De label Testknoten',
     ];
-    $this->drupalPostForm('de/node/' . $node->id() . '/translations/add/en/de', $edit, 'Save (this translation)');
+    $this->drupalGet('de/node/' . $node->id() . '/translations/add/en/de');
+    $this->submitForm($edit, 'Save (this translation)');
 
     $this->assertSession()->pageTextContains('De label Beispieltext fur den Test in geschachteltem Absatz.');
 
@@ -225,7 +310,7 @@ public function testDetachTranslatedNestedParagraphItemFromLibrary() {
     $this->drupalGet('node/' . $node->id());
     $this->assertSession()->pageTextContains('En label Example text for test.');
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_unlink_from_library');
+    $this->submitForm([], 'field_paragraphs_0_unlink_from_library');
     $this->assertSession()->pageTextContains('En label Example text for test.');
   }
 
@@ -237,13 +322,13 @@ public function testDetachBeforeTranslation() {
 
     // Add paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->submitForm([], 'paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'En label Test nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'En label Example text for test.'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph En label Test nested paragraph has been created.');
 
     // Translate nested paragraphs library item.
@@ -253,24 +338,25 @@ public function testDetachBeforeTranslation() {
       'label[0][value]' => 'De label Test geschachtelten Absatz',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'De label Beispieltext fur den Test in geschachteltem Absatz.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Create test content.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_from_library_add_more');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'En label Test nested paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_unlink_from_library');
+    $this->submitForm($edit, 'field_paragraphs_0_unlink_from_library');
     $edit = [
       'title[0][value]' => 'En label Test node nested',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add translation for test node.
     $node = $this->drupalGetNodeByTitle('En label Test node nested');
-    $this->drupalPostForm('de/node/' . $node->id() . '/translations/add/en/de', NULL, 'Save (this translation)');
+    $this->drupalGet('de/node/' . $node->id() . '/translations/add/en/de');
+    $this->submitForm([], 'Save (this translation)');
 
     $this->assertSession()->pageTextContains('De label Beispieltext fur den Test in geschachteltem Absatz.');
 
@@ -291,6 +377,7 @@ public function enableConvertingParagraphsTypeToLibrary($paragraphs_type) {
     $edit = [
       'allow_library_conversion' => 1,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraphs_type, $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraphs_type);
+    $this->submitForm($edit, 'Save');
   }
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
index 0f13b888e0..da3e76016f 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTest.php
@@ -8,6 +8,7 @@
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 
 /**
  * Tests the functionality of the Paragraphs Library.
@@ -16,14 +17,14 @@
  */
 class ParagraphsLibraryItemTest extends BrowserTestBase {
 
-  use ParagraphsTestBaseTrait, FieldUiTestTrait;
+  use ParagraphsTestBaseTrait, FieldUiTestTrait, ParagraphsCoreVersionUiTestTrait;
 
   /**
    * Modules to be enabled.
    *
    * @var string[]
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_library',
     'block',
@@ -38,7 +39,7 @@ class ParagraphsLibraryItemTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
     $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs');
 
@@ -56,10 +57,7 @@ public function setUp() {
     ]);
     $this->drupalLogin($admin);
 
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
   }
 
   /**
@@ -80,7 +78,7 @@ public function testLibraryItemsAccessControl() {
       'label[0][value]' => 'Library item',
       'paragraphs[0][subform][field_text][0][value]' => 'Item content',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph Library item has been created');
     // Assert a user has no access to the global library overview page.
     $this->assertSession()->statusCodeEquals(403);
@@ -165,8 +163,8 @@ public function testNoConversionSideEffects() {
 
     // Convert the container to a library item.
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Promote to library');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Promote to library');
+    $this->submitForm([], 'Save');
 
     // Check that the child text paragraph is present in the node.
     $this->assertSession()->pageTextContains('Test text 1');
@@ -181,7 +179,7 @@ public function testNoConversionSideEffects() {
     $this->getSession()->getPage()
       ->findButton('paragraphs_0_subform_paragraphs_container_paragraphs_0_remove')
       ->press();
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the child text paragraph is no longer present in the
     // library item or the node.
@@ -205,9 +203,9 @@ public function testNoConversionSideEffects() {
 
     // Add a new text paragraph to the library item.
     $this->drupalGet('/admin/content/paragraphs/' . $library_item->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Add text');
+    $this->submitForm([], 'Add text');
     $this->getSession()->getPage()->fillField('field_text', 'Test text 2');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the child text paragraph is present in the library item and
     // the node.
@@ -219,11 +217,11 @@ public function testNoConversionSideEffects() {
     // Convert the library item in the node back to a container paragraph and
     // delete it.
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Unlink from library');
+    $this->submitForm([], 'Unlink from library');
     $this->getSession()->getPage()
       ->findButton('field_paragraphs_0_subform_paragraphs_container_paragraphs_0_remove')
       ->press();
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the child text paragraph is no longer present in the node but
     // still present in the library item.
@@ -275,7 +273,7 @@ public function testLibraryItemUsageTab() {
       'label[0][value]' => 'Test usage nested paragraph',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'Example text for revision in nested paragraph.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $assert_session->pageTextContains('Paragraph Test usage nested paragraph has been created.');
 
     // Create content with referenced paragraph.
@@ -285,7 +283,7 @@ public function testLibraryItemUsageTab() {
       'title[0][value]' => 'Test content',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'Test usage nested paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('Test content');
 
     // Check Usage tab.
@@ -308,8 +306,8 @@ public function testLibraryItemUsageTab() {
     // Unlink library item and check usage tab.
     $node = $this->drupalGetNodeByTitle('Test content');
     $this->drupalGet($node->toUrl('edit-form'));
-    $this->drupalPostForm(NULL, [], 'Unlink from library');
-    $this->drupalPostForm(NULL, ['revision' => TRUE], 'Save');
+    $this->submitForm([], 'Unlink from library');
+    $this->submitForm(['revision' => TRUE], 'Save');
 
     // Check Usage tab.
     $this->drupalGet('admin/content/paragraphs');
@@ -341,7 +339,7 @@ public function testLibraryItemDeleteWarningMessage() {
       'label[0][value]' => 'Test usage warning message',
       'paragraphs[0][subform][field_text][0][value]' => 'Example text.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $assert_session->pageTextContains('Paragraph Test usage warning message has been created.');
 
     // Create content with referenced paragraph.
@@ -351,7 +349,7 @@ public function testLibraryItemDeleteWarningMessage() {
       'title[0][value]' => 'Test content',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'Test usage warning message',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     $node = $this->drupalGetNodeByTitle('Test content');
     $library_item = $node->get('field_paragraphs')->entity->get('field_reusable_paragraph')->entity;
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
index 3fd2014f97..af0af92242 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryItemTranslationTest.php
@@ -2,12 +2,14 @@
 
 namespace Drupal\Tests\paragraphs_library\Functional;
 
+use Drupal\block\Entity\Block;
 use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\paragraphs\Entity\ParagraphsType;
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\LoginAdminTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 
 /**
  * Tests the multilingual functionality of the Paragraphs Library.
@@ -19,13 +21,14 @@ class ParagraphsLibraryItemTranslationTest extends BrowserTestBase {
   use ParagraphsTestBaseTrait;
   use LoginAdminTrait;
   use FieldUiTestTrait;
+  use ParagraphsCoreVersionUiTestTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'views',
     'paragraphs_library',
     'link',
@@ -44,14 +47,11 @@ class ParagraphsLibraryItemTranslationTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->addParagraphedContentType('paragraphed_test');
 
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     // Add a second language (German) to the site.
     ConfigurableLanguage::createFromLangcode('de')->save();
@@ -92,14 +92,15 @@ public function testLibraryItemTranslation() {
       'settings[paragraphs_library_item][paragraphs_library_item][translatable]' => TRUE,
       'settings[node][paragraphed_test][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     $assert_session = $this->assertSession();
     $page = $this->getSession()->getPage();
 
     // Add a node and translate it.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
 
     $assert_session->buttonExists('field_paragraphs_0_promote_to_library');
     $assert_session->buttonExists('Promote to library');
@@ -107,7 +108,7 @@ public function testLibraryItemTranslation() {
       'title[0][value]' => 'EN Title',
       'field_paragraphs[0][subform][field_text][0][value]' => 'EN Library text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $assert_session->pageTextContains('paragraphed_test EN Title has been created.');
 
     $this->clickLink('Translate');
@@ -117,7 +118,7 @@ public function testLibraryItemTranslation() {
       'title[0][value]' => 'DE Title',
       'field_paragraphs[0][subform][field_text][0][value]' => 'DE Library text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save (this translation)');
+    $this->submitForm($edit, 'Save (this translation)');
     $assert_session->pageTextContains('paragraphed_test DE Title has been updated.');
 
     // Convert the text to a library item and make sure it is displayed
@@ -126,7 +127,7 @@ public function testLibraryItemTranslation() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $page->pressButton('Promote to library');
     $assert_session->fieldValueEquals('Reusable paragraph', 'text: EN Library text (1)');
-    $this->drupalPostForm(NULL, NULL, 'Save');
+    $this->submitForm([], 'Save');
 
     $assert_session->pageTextContains('EN Title');
     $assert_session->pageTextContains('EN Library text');
@@ -152,13 +153,13 @@ public function testLibraryItemTranslation() {
 
     // Add a node with a text paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $edit = [
       'title[0][value]' => 'DE Llama Test',
       'langcode[0][value]' => 'de',
       'field_paragraphs[0][subform][field_text][0][value]' => 'DE Text Paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $assert_session->pageTextContains('paragraphed_test DE Llama Test has been created.');
 
     // Translate the node to the default language.
@@ -168,7 +169,7 @@ public function testLibraryItemTranslation() {
       'title[0][value]' => 'EN Llama Test',
       'field_paragraphs[0][subform][field_text][0][value]' => 'EN Library text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save (this translation)');
+    $this->submitForm($edit, 'Save (this translation)');
     $assert_session->pageTextContains('paragraphed_test EN Llama Test has been updated.');
 
     // Assert the original node can promote paragraphs to the library.
@@ -176,7 +177,7 @@ public function testLibraryItemTranslation() {
     $this->drupalGet('de/node/' . $node->id() . '/edit');
     $page->pressButton('field_paragraphs_0_promote_to_library');
     $assert_session->fieldValueEquals('Reusable paragraph', 'text: DE Text Paragraph (2)');
-    $this->drupalPostForm(NULL, NULL, 'Save');
+    $this->submitForm([], 'Save');
     $assert_session->pageTextContains('paragraphed_test DE Llama Test has been updated.');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $assert_session->pageTextContains('Reusable paragraph');
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
index d8970da270..aabcd51914 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/Functional/ParagraphsLibraryTest.php
@@ -3,21 +3,21 @@
 namespace Drupal\Tests\paragraphs_library\Functional;
 
 use Drupal\Core\Url;
-use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetStable\ParagraphsTestBase;
 
 /**
  * Tests paragraphs library functionality.
  *
  * @group paragraphs_library
  */
-class ParagraphsLibraryTest extends ParagraphsExperimentalTestBase {
+class ParagraphsLibraryTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'views',
     'paragraphs_library',
   ];
@@ -25,7 +25,7 @@ class ParagraphsLibraryTest extends ParagraphsExperimentalTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->addParagraphedContentType('paragraphed_test');
   }
@@ -47,17 +47,21 @@ public function testLibraryItems() {
     // Add a new library item.
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_text_paragraph_add_more');
     $edit = [
       'label[0][value]' => 're usable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 're_usable_text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->clickLink('re usable paragraph label');
     $this->assertSession()->responseContains('bartik/css/base/elements.css');
     $this->clickLink('Edit');
     $this->assertSession()->responseNotContains('class="messages messages--warning"');
-    $items = \Drupal::entityQuery('paragraphs_library_item')->sort('id', 'DESC')->range(0, 1)->execute();
+    $items = \Drupal::entityQuery('paragraphs_library_item')
+      ->accessCheck(TRUE)
+      ->sort('id', 'DESC')
+      ->range(0, 1)
+      ->execute();
     $library_item_id = reset($items);
 
     // Assert local tasks and URLs.
@@ -85,12 +89,13 @@ public function testLibraryItems() {
     $this->assertSession()->fieldExists('paragraphs[0][subform][field_text][0][value]');
 
     // Create a node with the library paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     $library_items = \Drupal::entityTypeManager()->getStorage('paragraphs_library_item')->loadByProperties(['label' => 're usable paragraph label']);
     $this->drupalGet('admin/content/paragraphs/' . current($library_items)->id() . '/edit');
@@ -159,7 +164,7 @@ public function testLibraryItems() {
     $alternative_display->save();
 
     $this->drupalGet('node/' . $node_one->id());
-    $this->assertText('re_usable_text');
+    $this->assertSession()->pageTextContains('re_usable_text');
 
     /** @var \Drupal\Core\Entity\Entity\EntityViewDisplay $from_library_view_display */
     $from_library_view_display = $display_storage->load('paragraph.from_library.default');
@@ -169,7 +174,7 @@ public function testLibraryItems() {
     $from_library_view_display->save();
 
     $this->drupalGet('node/' . $node_one->id());
-    $this->assertNoText('re_usable_text');
+    $this->assertSession()->pageTextNotContains('re_usable_text');
 
     $from_library_view_display = $display_storage->load('paragraph.from_library.default');
     $field_reusable_paragraph_component = $from_library_view_display->getComponent('field_reusable_paragraph');
@@ -178,12 +183,13 @@ public function testLibraryItems() {
     $from_library_view_display->save();
 
     // Create a new node with the library paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test_new',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     // Assert that the paragraph is shown correctly.
     $node_two = $this->getNodeByTitle('library_test_new');
     $this->assertSession()->addressEquals('node/' . $node_two->id());
@@ -193,13 +199,13 @@ public function testLibraryItems() {
     $this->assertSession()->elementTextNotContains('css', '.paragraph--type--from-library', 'Paragraphs');
 
     $this->drupalGet('node/' . $node_two->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test_new',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)',
       'field_paragraphs[1][subform][field_reusable_paragraph][0][target_id]' => 're usable paragraph label (1)',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     $reusable_paragraphs_text = $this->xpath('//div[contains(@class, "field--name-field-paragraphs")]/div[@class="field__items"]/div[1]//div[@class="field__item"]/p');
     $this->assertEquals($reusable_paragraphs_text[0]->getText(), 're_usable_text');
@@ -220,7 +226,7 @@ public function testLibraryItems() {
     $edit = [
       'paragraphs[0][subform][field_text][0][value]' => 're_usable_text_new',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check in both nodes that the text is updated. Test as anonymous user, so
     // that the cache is populated.
@@ -239,7 +245,7 @@ public function testLibraryItems() {
     $edit = [
       'status[value]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node_one->id());
     $this->assertSession()->pageTextContains('re_usable_text_new');
 
@@ -254,7 +260,7 @@ public function testLibraryItems() {
     $edit = [
       'status[value]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node_one->id());
     $this->assertSession()->pageTextContains('re_usable_text_new');
 
@@ -290,7 +296,7 @@ public function testLibraryItems() {
     $this->assertSession()->linkExists('Manage display');
     // Assert that users can create fields to
     $this->clickLink('Manage fields');
-    $this->clickLink(t('Add field'));
+    $this->clickLink('Add field');
     $this->assertSession()->statusCodeEquals(200);
     $this->assertSession()->pageTextNotContains('plugin does not exist');
     $this->drupalGet('admin/config/content');
@@ -315,31 +321,32 @@ public function testConvertLibraryItemIntoParagraph() {
     // Add a new library item.
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
+    $this->submitForm([], 'paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'reusable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 'reusable_text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph reusable paragraph label has been created.');
 
     // Add created library item to a node.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_from_library_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'Node with converted library item',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Node with converted library item has been created.');
     $this->assertSession()->pageTextContains('reusable_text');
 
     // Convert library item to paragraph.
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_unlink_from_library');
+    $this->submitForm([], 'field_paragraphs_0_unlink_from_library');
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_text][0][value]');
     $this->assertSession()->fieldNotExists('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]');
     $this->assertSession()->pageTextContains('reusable_text');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('reusable_text');
   }
 
@@ -360,11 +367,12 @@ public function testConvertParagraphIntoLibrary() {
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
 
     $edit = ['allow_library_conversion' => 1];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/text');
+    $this->submitForm($edit, 'Save');
 
     // Adding library item is available with the administer library permission.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $this->assertSession()->buttonExists('field_paragraphs_0_promote_to_library');
     $this->drupalGet('admin/content/paragraphs/add/default');
     $this->assertSession()->statusCodeEquals(200);
@@ -374,7 +382,7 @@ public function testConvertParagraphIntoLibrary() {
     $user_role = end($user_roles);
     user_role_revoke_permissions($user_role, ['administer paragraphs library']);
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $this->assertSession()->buttonNotExists('field_paragraphs_0_promote_to_library');
     $this->drupalGet('admin/content/paragraphs/add/default');
     $this->assertSession()->statusCodeEquals(403);
@@ -383,19 +391,20 @@ public function testConvertParagraphIntoLibrary() {
     $edit = [
       'behavior_plugins[test_text_color][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/text');
+    $this->submitForm($edit, 'Save');
     // Assign "create paragraph library item" permission to a user.
     user_role_grant_permissions($user_role, ['create paragraph library item']);
     $this->drupalGet('admin/content/paragraphs/add/default');
     $this->assertSession()->statusCodeEquals(200);
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $this->assertSession()->buttonExists('field_paragraphs_0_promote_to_library');
     $this->assertSession()->responseContains('Promote to library');
     $edit = [
       'field_paragraphs[0][subform][field_text][0][value]' => 'Random text for testing converting into library.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
+    $this->submitForm($edit, 'field_paragraphs_0_promote_to_library');
     $this->assertSession()->pageTextContains('From library');
     $this->assertSession()->pageTextContains('Reusable paragraph');
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]');
@@ -404,21 +413,21 @@ public function testConvertParagraphIntoLibrary() {
     ];
     $this->assertSession()->buttonNotExists('field_paragraphs_0_promote_to_library');
     $this->assertSession()->buttonExists('field_paragraphs_0_unlink_from_library');
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/1');
     $this->assertSession()->pageTextContains('Random text for testing converting into library.');
 
     // Create library item from existing paragraph item.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $edit = [
       'title[0][value]' => 'NodeTitle',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Random text for testing converting into library.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $node = $this->getNodeByTitle('NodeTitle');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_promote_to_library');
+    $this->submitForm($edit, 'field_paragraphs_0_promote_to_library');
     user_role_grant_permissions($user_role, ['administer paragraphs library']);
     $this->drupalGet('/admin/content/paragraphs');
     $this->assertSession()->pageTextContains('Text');
@@ -426,7 +435,8 @@ public function testConvertParagraphIntoLibrary() {
 
     // Test disallow convesrion.
     $edit = ['allow_library_conversion' => FALSE];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/text');
+    $this->submitForm($edit, 'Save');
 
     /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
     $config_factory = \Drupal::service('config.factory');
@@ -434,7 +444,7 @@ public function testConvertParagraphIntoLibrary() {
     $this->assertFalse(isset($third_party['paragraphs_library']['allow_library_conversion']));
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, 'Add text');
+    $this->submitForm([], 'Add text');
     $this->assertSession()->responseNotContains('Promote to library');
 
     // Test that the checkbox is not visible on from_library.
@@ -462,14 +472,15 @@ public function testLibraryItemParagraphsSummary() {
     $edit = [
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->drupalPostForm('admin/content/paragraphs/add/default', [], 'paragraphs_nested_test_add_more');
-    $this->drupalPostForm(NULL, [], 'paragraphs_0_subform_field_paragraphs_text_add_more');
+    $this->submitForm($edit, 'Save');
+    $this->drupalGet('admin/content/paragraphs/add/default');
+    $this->submitForm([], 'paragraphs_nested_test_add_more');
+    $this->submitForm([], 'paragraphs_0_subform_field_paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'Test nested',
       'paragraphs[0][subform][field_paragraphs][0][subform][field_text][0][value]' => 'test text paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('test text paragraph');
 
     // Assert that the user with the access content permission can see the
@@ -504,26 +515,26 @@ public function testLibraryitemValidation() {
     $this->clickLink('Add library item');
 
     // Check the label validation.
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Label field is required.');
     $edit = [
       'label[0][value]' => 're usable paragraph label',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check the paragraph validation.
     $this->assertSession()->pageTextContains('Paragraphs field is required.');
-    $this->drupalPostForm(NULL, [], 'paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_text_paragraph_add_more');
     $edit['paragraphs[0][subform][field_text][0][value]'] = 're_usable_text';
 
     // Check that the library item is created.
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph re usable paragraph label has been created.');
     $this->clickLink('Edit');
     $edit = [
       'paragraphs[0][subform][field_text][0][value]' => 'new text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph re usable paragraph label has been updated.');
   }
 
@@ -543,23 +554,23 @@ public function testLibraryReferencingParagraphValidation() {
     // Add a library item with paragraphs type "Text".
     $this->drupalGet('admin/content/paragraphs');
     $this->clickLink('Add library item');
-    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
+    $this->submitForm([], 'paragraphs_text_add_more');
     $edit = [
       'label[0][value]' => 'reusable paragraph label',
       'paragraphs[0][subform][field_text][0][value]' => 'reusable_text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph reusable paragraph label has been created.');
 
     // Create a node with a "From library" paragraph referencing the library
     // item.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_from_library_add_more');
+    $this->submitForm([], 'field_paragraphs_from_library_add_more');
     $edit = [
       'title[0][value]' => 'library_test',
       'field_paragraphs[0][subform][field_reusable_paragraph][0][target_id]' => 'reusable paragraph label',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test library_test has been created.');
 
     // Disallow the paragraphs type "Text" for the used content type.
@@ -569,13 +580,13 @@ public function testLibraryReferencingParagraphValidation() {
       'settings[handler_settings][target_bundles_drag_drop][from_library][enabled]' => 1,
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved field_paragraphs configuration.');
 
     // Check that the node now fails validation.
     $node = $this->getNodeByTitle('library_test');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->addressEquals('node/' . $node->id() . '/edit');
     $this->assertSession()->pageTextContains('The Reusable paragraph field cannot contain a text paragraph, because the parent field_paragraphs field disallows it.');
   }
@@ -603,13 +614,13 @@ public function testLibraryItemRevisions() {
 
     // Add nested paragraph directly in library.
     $this->drupalGet('admin/content/paragraphs/add/default');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'paragraphs_0_subform_field_err_field_test_content_add_more');
+    $this->submitForm([], 'paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'paragraphs_0_subform_field_err_field_test_content_add_more');
     $edit = [
       'label[0][value]' => 'Test revisions nested original',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'Example text for revision original.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph Test revisions nested original has been created.');
 
     // Check revisions tab.
@@ -624,7 +635,7 @@ public function testLibraryItemRevisions() {
       'label[0][value]' => 'Test revisions nested first change',
       'paragraphs[0][subform][field_err_field][0][subform][field_paragraphs_text][0][value]' => 'Example text for revision first change.',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Check previous revision.
     $storage = \Drupal::entityTypeManager()->getStorage('paragraphs_library_item');
@@ -642,14 +653,9 @@ public function testLibraryItemRevisions() {
 
     // Test reverting revision.
     $this->clickLink('Revert');
-    $this->assertSession()->responseContains(t('Are you sure you want to revert revision from %revision-date?', [
-      '%revision-date' => $date_formatter->format($revision->getChangedTime())
-    ]));
-    $this->drupalPostForm(NULL, NULL, 'Revert');
-    $this->assertSession()->responseContains(t('%title has been reverted to the revision from %revision-date.', [
-      '%title' => 'Test revisions nested original',
-      '%revision-date' => $date_formatter->format($revision->getChangedTime())
-    ]));
+    $this->assertSession()->responseContains('Are you sure you want to revert revision from ' . $date_formatter->format($revision->getChangedTime()) . '?');
+    $this->submitForm([], 'Revert');
+    $this->assertSession()->pageTextContains('Test revisions nested original has been reverted to the revision from ' . $date_formatter->format($revision->getChangedTime()) . '.');
 
     // Check current revision.
     $current_revision = $storage->loadRevision(3);
@@ -660,13 +666,9 @@ public function testLibraryItemRevisions() {
     // Test deleting revision.
     $revision_for_deleting = $storage->loadRevision(2);
     $this->clickLink('Delete');
-    $this->assertSession()->responseContains(t('Are you sure you want to delete revision from %revision-date', [
-      '%revision-date' => $date_formatter->format($revision_for_deleting->getChangedTime())
-    ]));
-    $this->drupalPostForm(NULL, NULL, 'Delete');
-    $this->assertSession()->responseContains(t('Revision from %revision-date has been deleted.', [
-      '%revision-date' => $date_formatter->format($revision_for_deleting->getChangedTime())
-    ]));
+    $this->assertSession()->responseContains('Are you sure you want to delete revision from ' . $date_formatter->format($revision_for_deleting->getChangedTime()));
+    $this->submitForm([], 'Delete');
+    $this->assertSession()->pageTextContains('Revision from ' . $date_formatter->format($revision_for_deleting->getChangedTime()) .' has been deleted.');
   }
 
 }
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
index a8a2a6233f..9f95136199 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php
@@ -3,9 +3,11 @@
 namespace Drupal\Tests\paragraphs_library\FunctionalJavascript;
 
 use Behat\Mink\Element\Element;
-use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+use Drupal\paragraphs\Entity\ParagraphsType;
+use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -15,7 +17,7 @@
  */
 class ParagraphsContentModerationTest extends WebDriverTestBase {
 
-  use ParagraphsTestBaseTrait, FieldUiTestTrait, ParagraphsLastEntityQueryTrait;
+  use ParagraphsTestBaseTrait, FieldUiTestTrait, ParagraphsLastEntityQueryTrait, ParagraphsCoreVersionUiTestTrait;
 
   /**
    * A user with permission to bypass access content.
@@ -58,9 +60,9 @@ class ParagraphsContentModerationTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
-    $this->addParagraphedContentType('paragraphed_moderated_test', 'field_paragraphs', 'entity_reference_paragraphs');
+    $this->addParagraphedContentType('paragraphed_moderated_test', 'field_paragraphs');
 
     $this->addParagraphsType('text');
     $this->addFieldtoParagraphType('text', 'field_text', 'text');
@@ -112,10 +114,7 @@ public function setUp() {
       'view all revisions',
     ]);
 
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     $this->drupalLogin($this->adminUser);
   }
@@ -260,10 +259,11 @@ public function testModeratedParagraphedContent() {
     $this->drupalGet("/node/{$host_node_id}/edit");
     $page->fillField('title[0][value]', 'Host page 1 (rev 4)');
     $page->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2 modified again');
+    $row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(3)');
+    $dropdown = $assert_session->elementExists('css', '.paragraphs-dropdown', $row);
+    $dropdown->click();
     $paragraph3_remove_button = $assert_session->elementExists('css', 'input[name="field_paragraphs_2_remove"]');
     $paragraph3_remove_button->press();
-    $paragraph3_confirm_remove_button = $assert_session->waitForElement('css', 'input[name="field_paragraphs_2_confirm_remove"]');
-    $paragraph3_confirm_remove_button->press();
     $assert_session->assertWaitOnAjaxRequest();
     $page->selectFieldOption('moderation_state[0][state]', 'draft');
     $page->find('css', 'a[href="#edit-revision-information"]')->click();
@@ -406,11 +406,13 @@ public function testModeratedParagraphedContent() {
     $nodes = \Drupal::entityTypeManager()->getStorage('node')->getQuery()
       ->allRevisions()
       ->condition($host_node->getEntityType()->getKey('id'), $host_node->id())
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals(7, count($nodes));
     $library_items = \Drupal::entityTypeManager()->getStorage('paragraphs_library_item')->getQuery()
       ->allRevisions()
       ->condition($library_item->getEntityType()->getKey('id'), $library_item->id())
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals(6, count($library_items));
 
@@ -421,6 +423,56 @@ public function testModeratedParagraphedContent() {
     $assert_session->pageTextContains('Content types');
     $assert_session->elementNotExists('css', 'a[href$="' . $this->workflow->id() . '/type/paragraph"]');
     $assert_session->elementExists('css', 'a[href$="' . $this->workflow->id() . '/type/node"]');
+
+    // Promote a library and assert that is published when created.
+    $paragraph_type = ParagraphsType::load('text');
+    $paragraph_type->setThirdPartySetting('paragraphs_library', 'allow_library_conversion', TRUE);
+    $paragraph_type->save();
+    $this->drupalGet('/node/add/paragraphed_moderated_test');
+    $page->fillField('title[0][value]', 'Host page 1');
+    $dropbutton_paragraphs = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper .dropbutton-arrow');
+    $dropbutton_paragraphs->click();
+    $add_text_paragraph = $assert_session->elementExists('css', '#field-paragraphs-text-add-more');
+    $add_text_paragraph->press();
+    $textfield = $assert_session->waitForElement('css', 'input[name="field_paragraphs[0][subform][field_text][0][value]"]');
+    $this->assertNotNull($textfield);
+    $page->fillField('field_paragraphs[0][subform][field_text][0][value]', 'Promoted library item');
+    $first_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)');
+    $dropdown = $assert_session->elementExists('css', '.paragraphs-dropdown', $first_row);
+    $dropdown->click();
+    $add_above_button = $assert_session->elementExists('css', 'input[name="field_paragraphs_0_promote_to_library"]', $first_row);
+    $add_above_button->click();
+    $library_item = $this->getLastEntityOfType('paragraphs_library_item', TRUE);
+    $this->assertEquals('published', $library_item->moderation_state->value);
+
+    // Assert the unpublished indicator for library items.
+    ParagraphsType::load('text')->setThirdPartySetting('paragraphs_library', 'allow_library_conversion', TRUE)->save();
+    $this->drupalGet('node/add');
+    $title = $assert_session->fieldExists('Title');
+    $title->setValue('Paragraph test');
+    $element = $page->find('xpath', '//*[contains(@class, "dropbutton-toggle")]');
+    $element->click();
+    $button = $page->findButton('Add text');
+    $button->press();
+    $assert_session->waitForElementVisible('css', '.ui-dialog');
+    $page->fillField('field_paragraphs[0][subform][field_text][0][value]', 'This is a reusable text UPDATED.');
+    $first_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)');
+    $dropdown = $assert_session->elementExists('css', '.paragraphs-dropdown', $first_row);
+    $dropdown->click();
+    $page->pressButton('Promote to library');
+    $assert_session->assertWaitOnAjaxRequest();
+    // New library items are published by default.
+    $status_icon = $page->find('css', '.paragraph-formatter.paragraphs-icon-view');
+    $this->assertNull($status_icon);
+    // Archive the library item and assert there is a unpublished icon.
+    $edit_button = $page->find('css', 'input[name^="field_reusable_paragraph_edit_button"]');
+    $edit_button->press();
+    $assert_session->waitForElementVisible('css', '.ui-dialog');
+    $assert_session->elementExists('css', '.ui-dialog')->selectFieldOption('moderation_state[0][state]', 'archived');
+    $page->find('css', '.ui-dialog-buttonset button:contains("Save")')->press();
+    $assert_session->assertWaitOnAjaxRequest();
+    $status_icon = $page->find('css', '.paragraphs-icon-view');
+    $this->assertTrue($status_icon->isVisible());
   }
 
   /**
diff --git a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
index 4090c498ab..5753d8ea09 100644
--- a/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsLibraryItemEntityBrowserTest.php
@@ -18,8 +18,7 @@ class ParagraphsLibraryItemEntityBrowserTest extends EntityBrowserWebDriverTestB
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
-    'ctools',
+  protected static $modules = [
     'views',
     'block',
     'node',
@@ -65,7 +64,8 @@ public function testEntityBrowserWidget() {
       'entity_types[paragraphs_library_item]' => TRUE,
       'settings[paragraphs_library_item][paragraphs_library_item][translatable]' => TRUE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     $this->addParagraphsType('text');
     $this->addFieldtoParagraphType('text', 'field_text', 'text');
@@ -105,7 +105,7 @@ public function testEntityBrowserWidget() {
     // processing in the iframe.
     sleep(1);
     $this->waitForAjaxToFinish();
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     // Check that the paragraph was correctly reused.
     $this->assertSession()->pageTextContains('reusable_text');
 
@@ -118,7 +118,7 @@ public function testEntityBrowserWidget() {
       'label[0][value]' => 'DE Title',
       'paragraphs[0][subform][field_text][0][value]' => 'DE Library text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Paragraph DE Title has been updated.');
 
     // Add a node with a paragraph from library.
diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
index 6c65ff200e..74e3a3c56f 100644
--- a/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
+++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/paragraphs_type_permissions.info.yml
@@ -1,13 +1,13 @@
 name: Paragraphs Type Permissions
 type: module
 description: 'Allows users to configure permissions for individual Paragraphs types.'
-core_version_requirement: ^8.7.7 || ^9
+core_version_requirement: ^9.3 || ^10
 package: Paragraphs
 
 dependencies:
   - paragraphs:paragraphs
 
-# Information added by Drupal.org packaging script on 2020-05-21
-version: '8.x-1.12'
+# Information added by Drupal.org packaging script on 2022-08-25
+version: '8.x-1.15'
 project: 'paragraphs'
-datestamp: 1590061337
+datestamp: 1661440900
diff --git a/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
index 223bf255f8..0dd14b350f 100644
--- a/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
+++ b/web/modules/paragraphs/modules/paragraphs_type_permissions/tests/src/Functional/ParagraphsTypePermissionsTest.php
@@ -40,7 +40,7 @@ class ParagraphsTypePermissionsTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->drupalPlaceBlock('system_breadcrumb_block');
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
@@ -83,7 +83,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     $display_options = [
       'type' => 'image',
@@ -141,24 +142,24 @@ public function testAnonymousParagraphsTypePermissions() {
 
     // Create a node with some Paragraph types.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text_image');
+    $this->submitForm([], 'Add images');
+    $this->submitForm([], 'Add text');
 
     $image_text = $this->getTestFiles('image')[0];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_0_subform_field_image_demo_0]' => $image_text->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $images = $this->getTestFiles('image')[1];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $edit = [
       'title[0][value]' => 'paragraph node title',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Paragraph type Image + Text',
       'field_paragraphs_demo[2][subform][field_text_demo][0][value]' => 'Paragraph type Text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Get the node to edit it later.
     $node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
@@ -195,9 +196,9 @@ public function testAnonymousParagraphsTypePermissions() {
 
     // Set edit mode to open.
     $this->drupalGet('admin/structure/types/manage/paragraphed_content_demo/form-display');
-    $this->drupalPostForm(NULL, [], "field_paragraphs_demo_settings_edit");
+    $this->submitForm([], "field_paragraphs_demo_settings_edit");
     $edit = ['fields[field_paragraphs_demo][settings_edit_form][settings][edit_mode]' => 'open'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Unpublish the 'Image + Text' paragraph type.
     $this->drupalGet('node/' . $node->id() . '/edit');
@@ -205,7 +206,7 @@ public function testAnonymousParagraphsTypePermissions() {
     $edit = [
       'field_paragraphs_demo[0][subform][status][value]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check that 'Image + Text' paragraph is not shown anymore for admin user.
     $this->assertSession()->responseNotContains($image_text_tag);
diff --git a/web/modules/paragraphs/paragraphs.info.yml b/web/modules/paragraphs/paragraphs.info.yml
index f3c67844e9..657d499f8d 100644
--- a/web/modules/paragraphs/paragraphs.info.yml
+++ b/web/modules/paragraphs/paragraphs.info.yml
@@ -1,7 +1,7 @@
 name: Paragraphs
 type: module
 description: 'Enables the creation of paragraphs entities.'
-core_version_requirement: ^8.8 || ^9
+core_version_requirement: ^9.3 || ^10
 package: Paragraphs
 configure: entity.paragraphs_type.collection
 
@@ -16,7 +16,7 @@ test_dependencies:
   - field_group:field_group
   - block_field:block_field
 
-# Information added by Drupal.org packaging script on 2020-05-21
-version: '8.x-1.12'
+# Information added by Drupal.org packaging script on 2022-08-25
+version: '8.x-1.15'
 project: 'paragraphs'
-datestamp: 1590061337
+datestamp: 1661440900
diff --git a/web/modules/paragraphs/paragraphs.libraries.yml b/web/modules/paragraphs/paragraphs.libraries.yml
index e59af4435b..c928e10762 100644
--- a/web/modules/paragraphs/paragraphs.libraries.yml
+++ b/web/modules/paragraphs/paragraphs.libraries.yml
@@ -3,8 +3,7 @@ drupal.paragraphs.admin:
     - core/jquery
     - core/drupal
     - core/drupalSettings
-    - core/jquery.once
-    - core/jquery.form
+    - core/once
     - core/drupal.ajax
     - core/drupal.dropbutton
   css:
@@ -16,8 +15,7 @@ drupal.paragraphs.widget:
     - core/jquery
     - core/drupal
     - core/drupalSettings
-    - core/jquery.once
-    - core/jquery.form
+    - core/once
     - core/drupal.ajax
     - core/drupal.dropbutton
     - paragraphs/drupal.paragraphs.summary
@@ -35,9 +33,8 @@ drupal.paragraphs.add_above_button:
     js/paragraphs.add_above_button.js: {}
   dependencies:
     - core/drupalSettings
-    - core/jquery.once
+    - core/once
     - core/jquery
-    - core/jquery.form
     - core/drupal.ajax
     - core/drupal
 
@@ -49,9 +46,8 @@ drupal.paragraphs.actions:
     js/paragraphs.actions.js: {}
   dependencies:
     - core/drupalSettings
-    - core/jquery.once
+    - core/once
     - core/jquery
-    - core/jquery.form
     - core/drupal.ajax
     - core/drupal
 
@@ -70,7 +66,7 @@ drupal.paragraphs.modal:
   dependencies:
     - core/drupal.dialog
     - core/drupal.dialog.ajax
-    - core/jquery.once
+    - core/once
 
 paragraphs-dragdrop:
   css:
@@ -94,3 +90,8 @@ drupal.paragraphs.unpublished:
   css:
     theme:
       css/paragraphs.unpublished.css: {}
+
+paragraphs.seven:
+  css:
+    theme:
+      css/paragraphs.seven.css: {}
diff --git a/web/modules/paragraphs/paragraphs.module b/web/modules/paragraphs/paragraphs.module
index 53f7d5f091..a7fa93770b 100644
--- a/web/modules/paragraphs/paragraphs.module
+++ b/web/modules/paragraphs/paragraphs.module
@@ -5,15 +5,12 @@
  * Contains paragraphs.module
  */
 
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\field\FieldStorageConfigInterface;
-use Drupal\field\Plugin\migrate\source\d7\Field;
-use Drupal\field\Plugin\migrate\source\d7\FieldInstance;
-use Drupal\field\Plugin\migrate\source\d7\ViewMode;
-use Drupal\migrate_drupal\Plugin\migrate\FieldMigration;
 use Drupal\paragraphs\Entity\ParagraphsType;
-use Drupal\paragraphs\Plugin\migrate\field\FieldCollection;
+use Drupal\paragraphs\MigrationPluginsAlterer;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Entity\EntityTypeInterface;
 
@@ -103,7 +100,7 @@ function paragraphs_theme_suggestions_paragraph(array $variables) {
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function paragraphs_form_entity_form_display_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
+function paragraphs_form_entity_form_display_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($form['#entity_type'], $form['#bundle']);
   // Loop over ERR field's display options with paragraph target type.
   foreach (array_keys($field_definitions) as $field_name) {
@@ -120,7 +117,7 @@ function paragraphs_form_entity_form_display_edit_form_alter(&$form, \Drupal\Cor
 /**
  * Implements hook_form_FORM_ID_alter().
  */
-function paragraphs_form_field_storage_config_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
+function paragraphs_form_field_storage_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   if ($form_state->getFormObject()->getEntity()->getType() == 'entity_reference') {
     // Entity Reference fields are no longer supported to reference Paragraphs.
     unset($form['settings']['target_type']['#options'][(string) t('Content')]['paragraph']);
@@ -132,7 +129,7 @@ function paragraphs_form_field_storage_config_edit_form_alter(&$form, \Drupal\Co
  *
  * Indicate unsupported multilingual paragraphs field configuration.
  */
-function paragraphs_form_field_config_edit_form_alter(&$form,  \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
+function paragraphs_form_field_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   $field = $form_state->getFormObject()->getEntity();
 
   if (!\Drupal::hasService('content_translation.manager')) {
@@ -195,7 +192,7 @@ function paragraphs_module_implements_alter(&$implementations, $hook) {
  * Add a warning that paragraph fields can not be translated.
  * Switch to error if a paragraph field is marked as translatable.
  */
-function paragraphs_form_language_content_settings_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
+function paragraphs_form_language_content_settings_form_alter(&$form, FormStateInterface $form_state, $form_id) {
   // Without it Paragraphs message are meaningless.
   if (!\Drupal::hasService('content_translation.manager')) {
     return;
@@ -314,6 +311,10 @@ function template_preprocess_paragraphs_add_dialog(&$variables) {
       // $add variable for the add button.
       $variables['add'] = $variables['element'][$key];
     }
+    elseif ($key == 'add_more_delta') {
+      // Add the delta to the add wrapper.
+      $variables['add'][$key] = $variables['element'][$key];
+    }
     else {
       // Buttons for the paragraph types in the modal form.
       $variables['buttons'][$key] = $variables['element'][$key];
@@ -350,10 +351,10 @@ function template_preprocess_paragraphs_actions(&$variables) {
  * Implements hook_preprocess_HOOK() for field_multiple_value_form().
  */
 function paragraphs_preprocess_field_multiple_value_form(&$variables) {
-  if (!empty($variables['table']['#header']) && isset($variables['table']['#rows'])) {
+  if (!empty($variables['table']['#header']) && isset($variables['table']['#rows'][0])) {
     // Find paragraph_actions and move to header.
     // @see template_preprocess_field_multiple_value_form()
-    if (!empty($variables['table']['#rows'][0]['data'][1]['data']['#paragraphs_header'])) {
+    if (is_array($variables['table']['#rows'][0]['data'][1]) && !empty($variables['table']['#rows'][0]['data'][1]['data']['#paragraphs_header'])) {
       $variables['table']['#header'][0]['data'] = [
         'title' => $variables['table']['#header'][0]['data'],
         'button' => $variables['table']['#rows'][0]['data'][1]['data'],
@@ -383,9 +384,11 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) {
       foreach ($variables['table']['#rows'] as $key => $value) {
         $variables['table']['#rows'][$key]['data'][0]['class'][] = 'paragraph-bullet';
         // Restore the removed weight and give access FALSE.
-        $variables['table']['#rows'][$key]['data'][1]['data']['_weight'] = $value['data'][2]['data'];
-        unset($variables['table']['#rows'][$key]['data'][2]);
-        $variables['table']['#rows'][$key]['data'][1]['data']['_weight']['#access'] = FALSE;
+        if (isset($value['data'][2])) {
+          $variables['table']['#rows'][$key]['data'][1]['data']['_weight'] = $value['data'][2]['data'];
+          unset($variables['table']['#rows'][$key]['data'][2]);
+          $variables['table']['#rows'][$key]['data'][1]['data']['_weight']['#access'] = FALSE;
+        }
       }
     }
   }
@@ -398,38 +401,9 @@ function paragraphs_preprocess_field_multiple_value_form(&$variables) {
  * https://www.drupal.org/project/drupal/issues/2904765 is resolved
  */
 function paragraphs_migration_plugins_alter(array &$migrations) {
-  /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */
-  $migration_plugin_manager = \Drupal::service('plugin.manager.migration');
-  /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */
-  $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source');
-
-  foreach ($migrations as &$migration) {
-    if (!empty($migration['source'])) {
-      $configuration = $migration['source'];
-      $migration_stub = $migration_plugin_manager->createStubMigration($migration);
-      $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub);
-      if (is_a($migration['class'], FieldMigration::class, TRUE)) {
-
-        // Field storage.
-        if (is_a($source, Field::class)) {
-          _paragraphs_migration_entity_type_adjust($migration);
-        }
-
-        // Field instance.
-        if (is_a($source, FieldInstance::class)) {
-          _paragraphs_migration_entity_type_adjust($migration);
-          _paragraphs_migration_bundle_adjust($migration);
-          $migration['migration_dependencies']['optional']['d7_field_collection_type'] = 'd7_field_collection_type';
-          $migration['migration_dependencies']['optional']['d7_paragraphs_type'] = 'd7_paragraphs_type';
-        }
-      }
-
-      // View Modes.
-      if (is_a($source, ViewMode::class)) {
-        _paragraphs_migration_entity_type_adjust($migration, 'targetEntityType');
-      }
-    }
-  }
+  $migration_plugins_alterer = \Drupal::service('paragraphs.migration_plugins_alterer');
+  assert($migration_plugins_alterer instanceof MigrationPluginsAlterer);
+  $migration_plugins_alterer->alterMigrationPlugins($migrations);
 }
 
 /**
@@ -457,62 +431,33 @@ function paragraphs_entity_base_field_info_alter(&$fields, EntityTypeInterface $
  *
  * @param array $migration
  *   The migration configuration to process.
+ *
+ * @deprecated in paragraphs:8.x-1.13 and is removed from paragraphs:8.x-2.0.
+ *   Use \Drupal\paragraphs\MigrationPluginsAlterer::paragraphsMigrationBundleAdjust().
+ * @see https://www.drupal.org/project/paragraphs/issues/2911244
  */
 function _paragraphs_migration_bundle_adjust(array &$migration) {
-
-  if (!isset($migration['process']['bundle'])) {
-    $migration['process']['bundle'] = [];
-  }
-
-  $bundle_process = $migration['process']['bundle'];
-
-  // Try to play nice with other modules altering this, and don't replace
-  // it outright unless it's unchanged.
-  if (array_key_exists('plugin', $bundle_process)) {
-    $bundle_process = [$bundle_process];
-  }
-  $bundle_process['paragraphs'] = [
-    'plugin' => 'paragraphs_process_on_value',
-    'source_value' => 'entity_type',
-    'expected_value' => 'field_collection_item',
-    'process' => [
-      'plugin' => 'substr',
-      'start' => FieldCollection::FIELD_COLLECTION_PREFIX_LENGTH,
-    ],
-  ];
-  $migration['process']['bundle'] = $bundle_process;
+  $migration_plugins_alterer = \Drupal::service('paragraphs.migration_plugins_alterer');
+  assert($migration_plugins_alterer instanceof MigrationPluginsAlterer);
+  $migration_plugins_alterer->paragraphsMigrationBundleAdjust($migration);
 }
 
 /**
  * Map field_collection_item and 'paragraphs_item' fields to 'paragraph'.
  *
  * @param array $migration
- *   Thei migration to process.
+ *   The migration to process.
  * @param string $destination
  *   The process destination.
+ *
+ * @deprecated in paragraphs:8.x-1.13 and is removed from paragraphs:8.x-2.0.
+ *   Use \Drupal\paragraphs\MigrationPluginsAlterer::paragraphsMigrationEntityTypeAdjust().
+ * @see https://www.drupal.org/project/paragraphs/issues/2911244
  */
 function _paragraphs_migration_entity_type_adjust(array &$migration, $destination = 'entity_type') {
-  $entity_type_process = $migration['process'][$destination];
-
-  // Try to play with other modules altering this, and don't replace it
-  // outright unless it's unchanged.
-  if (!is_array($entity_type_process)) {
-    $entity_type_process = [
-      [
-        'plugin' => 'get',
-        'source' => 'entity_type',
-      ],
-    ];
-  }
-  $entity_type_process['paragraphs'] = [
-    'plugin' => 'static_map',
-    'map' => [
-      'field_collection_item' => 'paragraph',
-      'paragraphs_item' => 'paragraph',
-    ],
-    'bypass' => TRUE,
-  ];
-  $migration['process'][$destination] = $entity_type_process;
+  $migration_plugins_alterer = \Drupal::service('paragraphs.migration_plugins_alterer');
+  assert($migration_plugins_alterer instanceof MigrationPluginsAlterer);
+  $migration_plugins_alterer->paragraphsMigrationEntityTypeAdjust($migration, $destination);
 }
 
 /**
diff --git a/web/modules/paragraphs/paragraphs.post_update.php b/web/modules/paragraphs/paragraphs.post_update.php
index d76c3d2e8d..e0ce29a102 100644
--- a/web/modules/paragraphs/paragraphs.post_update.php
+++ b/web/modules/paragraphs/paragraphs.post_update.php
@@ -22,7 +22,7 @@ function paragraphs_post_update_set_paragraphs_parent_fields(&$sandbox) {
   // Don't execute the function if paragraphs_update_8003() was already executed
   // which used to do the same.
 
-  $module_schema = drupal_get_installed_schema_version('paragraphs');
+  $module_schema = \Drupal::service('update.update_hook_registry')->getInstalledVersion('paragraphs');
 
   // The state entry 'paragraphs_update_8003_placeholder' is used in order to
   // indicate that the placeholder paragraphs_update_8003() function has been
diff --git a/web/modules/paragraphs/paragraphs.services.yml b/web/modules/paragraphs/paragraphs.services.yml
index b8c96660c1..4410694c27 100644
--- a/web/modules/paragraphs/paragraphs.services.yml
+++ b/web/modules/paragraphs/paragraphs.services.yml
@@ -8,3 +8,4 @@ services:
     arguments: ['@cache.bootstrap', '@lock', '@entity_type.manager']
     tags:
       - { name: needs_destruction }
+
diff --git a/web/modules/paragraphs/src/Entity/Paragraph.php b/web/modules/paragraphs/src/Entity/Paragraph.php
index 07e86ab139..702b78d8e1 100644
--- a/web/modules/paragraphs/src/Entity/Paragraph.php
+++ b/web/modules/paragraphs/src/Entity/Paragraph.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Render\Markup;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\entity_reference_revisions\EntityNeedsSaveTrait;
@@ -83,7 +84,7 @@
  *       }
  *     },
  *     "entity_form_display" = {
- *       "type" = "entity_reference_paragraphs"
+ *       "type" = "paragraphs"
  *     },
  *     "entity_view_display" = {
  *       "type" = "entity_reference_revisions_entity_view"
@@ -100,6 +101,7 @@ class Paragraph extends ContentEntityBase implements ParagraphInterface {
 
   use EntityNeedsSaveTrait;
   use EntityPublishedTrait;
+  use StringTranslationTrait;
 
   /**
    * The behavior plugin data for the paragraph entity.
@@ -164,7 +166,7 @@ public function label() {
       }
     }
     else {
-      $label = t('Orphaned @type: @summary', ['@summary' => Unicode::truncate(strip_tags($this->getSummary()), 50, FALSE, TRUE), '@type' => $this->get('type')->entity->label()]);
+      $label = $this->t('Orphaned @type: @summary', ['@summary' => Unicode::truncate(strip_tags($this->getSummary()), 50, FALSE, TRUE), '@type' => $this->get('type')->entity->label()]);
     }
     return $label;
   }
@@ -219,6 +221,8 @@ public function setAllBehaviorSettings(array $settings) {
    * {@inheritdoc}
    */
   public function setBehaviorSettings($plugin_id, array $settings) {
+    // Get existing behaviors first.
+    $this->getAllBehaviorSettings();
     // Set behavior settings fields.
     $this->unserializedBehaviorSettings[$plugin_id] = $settings;
   }
@@ -736,7 +740,7 @@ public function getTextSummary($field_name, FieldDefinitionInterface $field_defi
         return '';
       }
 
-      $text = $this->get($field_name)->value;
+      $text = $this->get($field_name)->value ?? '';
       $summary = Unicode::truncate(trim(strip_tags($text)), 150);
       if (empty($summary)) {
         // Autoescape is applied to the summary when it is rendered with twig,
diff --git a/web/modules/paragraphs/src/Entity/ParagraphsType.php b/web/modules/paragraphs/src/Entity/ParagraphsType.php
index 9b815c0988..51ac1998ee 100644
--- a/web/modules/paragraphs/src/Entity/ParagraphsType.php
+++ b/web/modules/paragraphs/src/Entity/ParagraphsType.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
 use Drupal\file\Entity\File;
+use Drupal\file\FileInterface;
 use Drupal\paragraphs\ParagraphsBehaviorCollection;
 use Drupal\paragraphs\ParagraphsTypeInterface;
 use Drupal\Core\File\FileSystemInterface;
@@ -118,7 +119,7 @@ protected function restoreDefaultIcon() {
       // Compose the default icon file destination.
       $icon_meta = stream_get_meta_data($icon_data);
       // File extension from MIME, only JPG/JPEG, PNG and SVG expected.
-      list(, $icon_file_ext) = explode('image/', $icon_meta['mediatype']);
+      [, $icon_file_ext] = explode('image/', $icon_meta['mediatype']);
       // SVG special case.
       if ($icon_file_ext == 'svg+xml') {
         $icon_file_ext = 'svg';
@@ -137,7 +138,7 @@ protected function restoreDefaultIcon() {
           'uri' => $icon_file_uri,
           'uid' => \Drupal::currentUser()->id(),
           'uuid' => $this->icon_uuid,
-          'status' => FILE_STATUS_PERMANENT,
+          'status' => FileInterface::STATUS_PERMANENT,
         ];
 
         // Delete existent icon file if it exists.
@@ -159,9 +160,11 @@ protected function restoreDefaultIcon() {
    * {@inheritdoc}
    */
   public function getIconFile() {
-    $icon = $this->getFileByUuid($this->icon_uuid) ?: $this->restoreDefaultIcon();
-    if ($this->icon_uuid && $icon) {
-      return $icon;
+    if ($this->icon_uuid !== NULL) {
+      $icon = $this->getFileByUuid($this->icon_uuid) ?: $this->restoreDefaultIcon();
+      if ($icon) {
+        return $icon;
+      }
     }
 
     return FALSE;
@@ -182,7 +185,7 @@ public function getBehaviorPlugins() {
    */
   public function getIconUrl() {
     if ($image = $this->getIconFile()) {
-      return file_create_url($image->getFileUri());
+      return \Drupal::service('file_url_generator')->generateString($image->getFileUri());
     }
 
     return FALSE;
diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
index ac6bb77c35..dc57041c28 100644
--- a/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
+++ b/web/modules/paragraphs/src/Form/ParagraphsTypeDeleteConfirm.php
@@ -17,6 +17,7 @@ class ParagraphsTypeDeleteConfirm extends EntityDeleteForm {
   public function buildForm(array $form, FormStateInterface $form_state) {
     $num_paragraphs = $this->entityTypeManager->getStorage('paragraph')->getQuery()
       ->condition('type', $this->entity->id())
+      ->accessCheck(FALSE)
       ->count()
       ->execute();
     if ($num_paragraphs) {
@@ -49,6 +50,7 @@ public function deleteExistingEntities(array $form, FormStateInterface $form_sta
     $storage = $this->entityTypeManager->getStorage('paragraph');
     $ids = $storage->getQuery()
       ->condition('type', $this->entity->id())
+      ->accessCheck(FALSE)
       ->execute();
 
     if (!empty($ids)) {
diff --git a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
index 986533e5c0..dee8c7a691 100644
--- a/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
+++ b/web/modules/paragraphs/src/Form/ParagraphsTypeForm.php
@@ -69,7 +69,7 @@ public function form(array $form, FormStateInterface $form_state) {
     $paragraphs_type = $this->entity;
 
     if (!$paragraphs_type->isNew()) {
-      $form['#title'] = (t('Edit %title paragraph type', [
+      $form['#title'] = ($this->t('Edit %title paragraph type', [
         '%title' => $paragraphs_type->label(),
       ]));
     }
@@ -107,17 +107,18 @@ public function form(array $form, FormStateInterface $form_state) {
     }
 
     $form['description'] = [
-      '#title' => t('Description'),
+      '#title' => $this->t('Description'),
       '#type' => 'textarea',
       '#default_value' => $paragraphs_type->getDescription(),
-      '#description' => t('This text will be displayed on the <em>Add new paragraph</em> page.'),
+      '#description' => $this->t('This text will be displayed on the <em>Add new paragraph</em> page.'),
     ];
 
     // Loop over the plugins that can be applied to this paragraph type.
     if ($behavior_plugin_definitions = $this->paragraphsBehaviorManager->getApplicableDefinitions($paragraphs_type)) {
       $form['message'] = [
         '#type' => 'container',
-        '#markup' => $this->t('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget.', [], ['context' => 'paragraphs']),
+        '#markup' => $this->t('Behavior plugins are only supported by the stable paragraphs widget.', [], ['context' =>
+          'paragraphs']),
         '#attributes' => ['class' => ['messages', 'messages--warning']]
       ];
       $form['behavior_plugins'] = [
diff --git a/web/modules/paragraphs/src/MigrationPluginsAlterer.php b/web/modules/paragraphs/src/MigrationPluginsAlterer.php
new file mode 100644
index 0000000000..f749dde99d
--- /dev/null
+++ b/web/modules/paragraphs/src/MigrationPluginsAlterer.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace Drupal\paragraphs;
+
+use Drupal\Core\Logger\LoggerChannelFactoryInterface;
+use Drupal\migrate\Plugin\MigrationDeriverTrait;
+use Drupal\paragraphs\Plugin\migrate\field\FieldCollection;
+
+/**
+ * Class MigrationPluginsAlterer.
+ */
+final class MigrationPluginsAlterer {
+
+  use MigrationDeriverTrait;
+
+  /**
+   * Paragraphs' logger channel.
+   *
+   * @var \Drupal\Core\Logger\LoggerChannelInterface
+   */
+  protected $loggerChannel;
+
+  /**
+   * Constructs a MigratePluginAlterer object.
+   *
+   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
+   *   The logger factory service.
+   */
+  public function __construct(LoggerChannelFactoryInterface $logger_factory) {
+    $this->loggerChannel = $logger_factory->get('paragraphs');
+  }
+
+  /**
+   * Adds field collection and paragraph migration dependencies where needed.
+   *
+   * @param array[] $migrations
+   *   An associative array of migrations keyed by migration ID, the same that
+   *   is passed to hook_migration_plugins_alter() hooks.
+   */
+  public function alterMigrationPlugins(array &$migrations) {
+    foreach ($migrations as &$migration) {
+      if (!isset($migration['process']) || !is_array($migration['process'])) {
+        continue;
+      }
+
+      foreach (['entity_type', 'targetEntityType'] as $process_property) {
+        if (isset($migration['process'][$process_property])) {
+          $this->paragraphsMigrationEntityTypeAdjust($migration, $process_property);
+          $this->paragraphsMigrationBundleAdjust($migration);
+          $migration['migration_dependencies']['optional'][] = 'd7_field_collection_type';
+          $migration['migration_dependencies']['optional'][] = 'd7_paragraphs_type';
+        }
+      }
+    }
+  }
+
+  /**
+   * Map field_collection_item and 'paragraphs_item' fields to 'paragraph'.
+   *
+   * @param array $migration
+   *   Thei migration to process.
+   * @param string $process_property
+   *   The process destination.
+   */
+  public function paragraphsMigrationEntityTypeAdjust(array &$migration, $process_property) {
+    if (!$this->paragraphsMigrationPrepareProcess($migration['process'], $process_property)) {
+      return;
+    }
+
+    $entity_type_process = &$migration['process'][$process_property];
+    $entity_type_process[] = [
+      'plugin' => 'static_map',
+      'map' => [
+        'field_collection_item' => 'paragraph',
+        'paragraphs_item' => 'paragraph',
+      ],
+      'bypass' => TRUE,
+    ];
+  }
+
+  /**
+   * Remove 'field_' prefix from field collection bundles.
+   *
+   * @param array $migration
+   *   The migration configuration to process.
+   */
+  public function paragraphsMigrationBundleAdjust(array &$migration) {
+    // @see https://www.drupal.org/project/drupal/releases/9.1.4
+    // @see https://www.drupal.org/project/drupal/issues/2565931
+    $key = version_compare(\Drupal::VERSION, '9.1.4', '<')
+      ? 'bundle'
+      : 'bundle_mapped';
+    if (!$this->paragraphsMigrationPrepareProcess($migration['process'], $key)) {
+      return;
+    }
+
+    $bundle_process = &$migration['process'][$key];
+    $bundle_process[] = [
+      'plugin' => 'paragraphs_process_on_value',
+      'source_value' => 'entity_type',
+      'expected_value' => 'field_collection_item',
+      'process' => [
+        'plugin' => 'substr',
+        'start' => FieldCollection::FIELD_COLLECTION_PREFIX_LENGTH,
+      ],
+    ];
+  }
+
+  /**
+   * Converts a migration process to array for adding another process elements.
+   *
+   * @param array $process
+   *   The array of process definitions of a migration.
+   * @param string $property
+   *   The property which process definition should me converted to an array of
+   *   process definitions.
+   *
+   * @return bool
+   *   TRUE when the action was successful, FALSE otherwise.
+   */
+  public function paragraphsMigrationPrepareProcess(array &$process, $property): bool {
+    if (!isset($process[$property])) {
+      return FALSE;
+    }
+
+    $process_element = &$process[$property];
+
+    // Try to play with other modules altering this, and don't replace it
+    // outright unless it's unchanged.
+    if (is_string($process_element)) {
+      $process_element = [
+        [
+          'plugin' => 'get',
+          'source' => $process_element,
+        ],
+      ];
+    }
+    elseif (is_array($process_element) && array_key_exists('plugin', $process_element)) {
+      $process_element = [$process_element];
+    }
+
+    if (!is_array($process_element)) {
+      $this->loggerChannel->error('Unknown migration process element type: @type.', ['@type' => gettype($process_element)]);
+      return FALSE;
+    }
+
+    return TRUE;
+  }
+
+}
diff --git a/web/modules/paragraphs/src/ParagraphInterface.php b/web/modules/paragraphs/src/ParagraphInterface.php
index 6d7969b345..4cd6f10e36 100644
--- a/web/modules/paragraphs/src/ParagraphInterface.php
+++ b/web/modules/paragraphs/src/ParagraphInterface.php
@@ -18,7 +18,7 @@ interface ParagraphInterface extends ContentEntityInterface, EntityOwnerInterfac
    *
    * Preserves language context with translated entities.
    *
-   * @return ContentEntityInterface
+   * @return \Drupal\Core\Entity\ContentEntityInterface|null
    *   The parent entity.
    */
   public function getParentEntity();
diff --git a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
index e3ecb3b87a..bf64a016f0 100644
--- a/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
+++ b/web/modules/paragraphs/src/ParagraphsBehaviorInterface.php
@@ -95,9 +95,6 @@ public function preprocess(&$variables);
    *   entity components.
    * @param string $view_mode
    *   The view mode the entity is rendered in.
-   *
-   * @return array
-   *   A render array provided by the plugin.
    */
   public function view(array &$build, Paragraph $paragraph, EntityViewDisplayInterface $display, $view_mode);
 
diff --git a/web/modules/paragraphs/src/ParagraphsServiceProvider.php b/web/modules/paragraphs/src/ParagraphsServiceProvider.php
index db38ed640e..a0a78e0301 100644
--- a/web/modules/paragraphs/src/ParagraphsServiceProvider.php
+++ b/web/modules/paragraphs/src/ParagraphsServiceProvider.php
@@ -28,5 +28,13 @@ public function register(ContainerBuilder $container) {
       $service_definition->setPublic(TRUE);
       $container->setDefinition('replicate.event_subscriber.paragraphs', $service_definition);
     }
+    // Check for installed Migrate module.
+    if (isset($modules['migrate']) ) {
+      // Add a Migration plugins alterer service.
+      $service_definition = new Definition('Drupal\paragraphs\MigrationPluginsAlterer');
+      $service_definition->addArgument(new Reference('logger.factory'));
+      $service_definition->setPublic(TRUE);
+      $container->setDefinition('paragraphs.migration_plugins_alterer', $service_definition);
+    }
   }
 }
diff --git a/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
index 9786eb1023..af3fde082f 100644
--- a/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
+++ b/web/modules/paragraphs/src/ParagraphsTypeIconUuidLookup.php
@@ -40,6 +40,7 @@ public function __construct(CacheBackendInterface $cache, LockBackendInterface $
   protected function resolveCacheMiss($key) {
     $ids = $this->entityTypeManager->getStorage('file')->getQuery()
       ->condition('uuid', $key)
+      ->accessCheck(TRUE)
       ->execute();
 
     // Only cache if there is a match, otherwise creating new entities would
diff --git a/web/modules/paragraphs/src/ParagraphsTypeInterface.php b/web/modules/paragraphs/src/ParagraphsTypeInterface.php
index 9cee2ee496..c08b263846 100644
--- a/web/modules/paragraphs/src/ParagraphsTypeInterface.php
+++ b/web/modules/paragraphs/src/ParagraphsTypeInterface.php
@@ -46,7 +46,7 @@ public function getEnabledBehaviorPlugins();
   /**
    * Returns the icon file entity.
    *
-   * @return \Drupal\file\FileInterface|bool
+   * @return \Drupal\file\FileInterface|false
    *   The icon's file entity or FALSE if icon does not exist.
    */
   public function getIconFile();
@@ -54,7 +54,7 @@ public function getIconFile();
   /**
    * Returns the icon's URL.
    *
-   * @return string|bool
+   * @return string|false
    *   The icon's URL or FALSE if icon does not exits.
    */
   public function getIconUrl();
diff --git a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
index 1545d85cc5..5564a48803 100644
--- a/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
+++ b/web/modules/paragraphs/src/Plugin/EntityReferenceSelection/ParagraphSelection.php
@@ -250,7 +250,7 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS')
     $entity_type = $this->entityTypeManager->getDefinition($target_type);
 
     $query = $this->entityTypeManager->getStorage($target_type)->getQuery();
-
+    $query->accessCheck(TRUE);
     // If 'target_bundles' is NULL, all bundles are referenceable, no further
     // conditions are needed.
     if (is_array($this->configuration['target_bundles'])) {
diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
index d90cb147c6..aa2b7070c2 100644
--- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
+++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -26,8 +26,8 @@
  *
  * @FieldWidget(
  *   id = "entity_reference_paragraphs",
- *   label = @Translation("Paragraphs Classic"),
- *   description = @Translation("A paragraphs inline form widget."),
+ *   label = @Translation("Paragraphs Legacy"),
+ *   description = @Translation("The legacy paragraphs inline form widget."),
  *   field_types = {
  *     "entity_reference_revisions"
  *   }
@@ -298,8 +298,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     if ($paragraphs_entity) {
       // Detect if we are translating.
       $this->initIsTranslating($form_state, $host);
-      $langcode = $form_state->get('langcode');
-
+      $langcode = $this->getCurrentLangcode($form_state, $items);
       if (!$this->isTranslating) {
         // Set the langcode if we are not translating.
         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
@@ -929,6 +928,14 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
 
     $host = $items->getEntity();
     $this->initIsTranslating($form_state, $host);
+    if (!$form_state->has('langcode')) {
+      // Entity forms usually have the langcode set, but it's not guaranteed.
+      // Any form object can embed entities with their field widgets.
+      // At this point, without knowing the langcode from the form state,
+      // it's not certain which language is chosen. Remember the host entity,
+      // to get the langcode at a stage when the chosen value is more certain.
+      $elements['#host'] = $host;
+    }
 
     if (($this->realItemCount < $cardinality || $cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) && !$form_state->isProgrammed() && !$this->isTranslating) {
       $elements['add_more'] = $this->buildAddActions();
@@ -1127,11 +1134,15 @@ protected function buildSelectAddMode() {
    * is only accessibly through the form state.
    *
    * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
    * @param \Drupal\Core\Field\FieldItemListInterface $items
+   *   The field item list.
+   *
    * @return string
+   *   The language code.
    */
   protected function getCurrentLangcode(FormStateInterface $form_state, FieldItemListInterface $items) {
-    return $form_state->get('langcode') ?: $items->getEntity()->language()->getId();
+    return $form_state->has('langcode') ? $form_state->get('langcode') : $items->getEntity()->language()->getId();
   }
 
   /**
@@ -1291,7 +1302,7 @@ public function multipleElementValidate(array $elements, FormStateInterface $for
     $non_remove_mode_item_count = $widget_state['real_item_count'] - $remove_mode_item_count;
 
     if ($elements['#required'] && $non_remove_mode_item_count < 1) {
-      $form_state->setError($elements, t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
+      $form_state->setError($elements, $this->t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
     }
 
     static::setWidgetState($elements['#field_parents'], $field_name, $form_state, $widget_state);
@@ -1318,14 +1329,20 @@ public function massageFormValues(array $values, array $form, FormStateInterface
         // A content entity form saves without any rebuild. It needs to set the
         // language to update it in case of language change.
         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
-        if ($paragraphs_entity->get($langcode_key)->value != $form_state->get('langcode')) {
+        $langcode = $form_state->get('langcode');
+        if (!isset($langcode) && isset($element['#host'])) {
+          // Use the host entity as a last resort to determine the langcode.
+          // @see self::formMultipleElements
+          $langcode = $element['#host']->language()->getId();
+        }
+        if ($paragraphs_entity->get($langcode_key)->value != $langcode) {
           // If a translation in the given language already exists, switch to
           // that. If there is none yet, update the language.
-          if ($paragraphs_entity->hasTranslation($form_state->get('langcode'))) {
-            $paragraphs_entity = $paragraphs_entity->getTranslation($form_state->get('langcode'));
+          if ($paragraphs_entity->hasTranslation($langcode)) {
+            $paragraphs_entity = $paragraphs_entity->getTranslation($langcode);
           }
           else {
-            $paragraphs_entity->set($langcode_key, $form_state->get('langcode'));
+            $paragraphs_entity->set($langcode_key, $langcode);
           }
         }
 
@@ -1380,7 +1397,8 @@ protected function initIsTranslating(FormStateInterface $form_state, EntityInter
       // Adding a language through the ContentTranslationController.
       $this->isTranslating = TRUE;
     }
-    if ($host->hasTranslation($form_state->get('langcode')) && $host->getTranslation($form_state->get('langcode'))->get($default_langcode_key)->value == 0) {
+    $langcode = $form_state->get('langcode');
+    if (isset($langcode) && $host->hasTranslation($langcode) && $host->getTranslation($langcode)->get($default_langcode_key)->value == 0) {
       // Editing a translation.
       $this->isTranslating = TRUE;
     }
diff --git a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
index 6625db3a0d..5e31eedd84 100644
--- a/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
+++ b/web/modules/paragraphs/src/Plugin/Field/FieldWidget/ParagraphsWidget.php
@@ -27,8 +27,8 @@
  *
  * @FieldWidget(
  *   id = "paragraphs",
- *   label = @Translation("Paragraphs EXPERIMENTAL"),
- *   description = @Translation("An experimental paragraphs inline form widget."),
+ *   label = @Translation("Paragraphs (stable)"),
+ *   description = @Translation("The stable paragraphs inline form widget."),
  *   field_types = {
  *     "entity_reference_revisions"
  *   }
@@ -419,8 +419,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     if ($paragraphs_entity) {
       // Detect if we are translating.
       $this->initIsTranslating($form_state, $host);
-      $langcode = $form_state->get('langcode');
-
+      $langcode = $this->getCurrentLangcode($form_state, $items);
       if (!$this->isTranslating) {
         // Set the langcode if we are not translating.
         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
@@ -950,6 +949,7 @@ protected function buildModalAddForm(array &$element) {
       '#name' => 'button_add_modal',
       '#attributes' => [
         'class' => [
+          'field-add-more-submit',
           'paragraph-type-add-modal-button',
           'js-show',
           'button--small',
@@ -957,19 +957,6 @@ protected function buildModalAddForm(array &$element) {
       ],
     ];
 
-    // Hidden field provided by "Modal" mode. Field is provided for additional
-    // integrations, where also position of addition can be specified. It should
-    // be used by sub-modules or other paragraphs integration. CSS class is used
-    // to support easier element selecting in JavaScript.
-    $element['add_modal_form_area']['add_more_delta'] = [
-      '#type' => 'hidden',
-      '#attributes' => [
-        'class' => [
-          'paragraph-type-add-modal-delta',
-        ],
-      ],
-    ];
-
     $element['#attached']['library'][] = 'paragraphs/drupal.paragraphs.modal';
     if ($this->isFeatureEnabled('add_above')) {
       $element['#attached']['library'][] = 'paragraphs/drupal.paragraphs.add_above_button';
@@ -1062,7 +1049,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
     $is_multiple = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple();
 
     $field_title = $this->fieldDefinition->getLabel();
-    $description = FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription()));
+    $description = FieldFilteredMarkup::create(\Drupal::token()->replace($this->fieldDefinition->getDescription() ?? ''));
 
     $elements = array();
     $tabs = '';
@@ -1074,7 +1061,7 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
     $field_prefix = strtr($this->fieldIdPrefix, '_', '-');
     if (count($this->fieldParents) == 0) {
       if ($items->getEntity()->getEntityTypeId() != 'paragraph') {
-        $tabs = '<ul class="paragraphs-tabs tabs primary clearfix"><li id="content" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Content', [], ['context' => 'paragraphs']) . '</a></li><li id="behavior" class="tabs__tab"><a href="#' . $field_prefix . '-values">' . $this->t('Behavior', [], ['context' => 'paragraphs']) . '</a></li></ul>';
+        $tabs = '<ul class="paragraphs-tabs tabs primary tabs--secondary paragraphs-tabs-hide clearfix"><li class="tabs__tab paragraphs_content_tab"><a href="#' . $field_prefix . '-values" class="tabs__link">' . $this->t('Content', [], ['context' => 'paragraphs']) . '</a></li><li class="tabs__tab paragraphs_behavior_tab"><a href="#' . $field_prefix . '-values" class="tabs__link">' . $this->t('Behavior', [], ['context' => 'paragraphs']) . '</a></li></ul>';
       }
     }
     if (count($this->fieldParents) > 0) {
@@ -1183,6 +1170,14 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
 
     $host = $items->getEntity();
     $this->initIsTranslating($form_state, $host);
+    if (!$form_state->has('langcode')) {
+      // Entity forms usually have the langcode set, but it's not guaranteed.
+      // Any form object can embed entities with their field widgets.
+      // At this point, without knowing the langcode from the form state,
+      // it's not certain which language is chosen. Remember the host entity,
+      // to get the langcode at a stage when the chosen value is more certain.
+      $elements['#host'] = $host;
+    }
 
     $header_actions = $this->buildHeaderActions($field_state, $form_state);
     if ($header_actions) {
@@ -1200,12 +1195,30 @@ public function formMultipleElements(FieldItemListInterface $items, array &$form
       $elements['add_more'] = $this->buildAddActions();
       // Add the class to hide the add actions in the Behavior perspective.
       $elements['add_more']['#attributes']['class'][] = 'paragraphs-add-wrapper';
+
+      // Hidden field is provided for additional integrations, where also
+      // position of addition can be specified. It should be used by sub-modules
+      // or other paragraphs integration. CSS class is used to support easier
+      // element selecting in JavaScript.
+      $elements['add_more']['add_more_delta'] = [
+        '#type' => 'hidden',
+        '#attributes' => [
+          'class' => [
+            'paragraph-type-add-delta',
+            $this->getSetting('add_mode')
+          ],
+        ],
+      ];
     }
 
     $elements['#allow_reference_changes'] = $this->allowReferenceChanges();
     $elements['#paragraphs_widget'] = TRUE;
     $elements['#attached']['library'][] = 'paragraphs/drupal.paragraphs.widget';
 
+    if (\Drupal::theme()->getActiveTheme()->getName() == 'seven') {
+      $elements['#attached']['library'][] = 'paragraphs/paragraphs.seven';
+    }
+
     return $elements;
   }
 
@@ -1585,6 +1598,7 @@ protected function buildDropbutton(array $elements = []) {
       // Even though operations are run through the "links" element type, the
       // theme system will render any render array passed as a link "title".
       '#links' => $operations,
+      '#dropbutton_type' => 'small',
     ];
 
     return $build + $elements;
@@ -1607,7 +1621,7 @@ protected function buildButtonsAddMode() {
         '#type' => 'submit',
         '#name' => $this->fieldIdPrefix . '_' . $machine_name . '_add_more',
         '#value' => $add_mode == 'modal' ? $label : $this->t('Add @type', ['@type' => $label]),
-        '#attributes' => ['class' => ['field-add-more-submit']],
+        '#attributes' => ['class' => ['field-add-more-submit', 'button--small']],
         '#limit_validation_errors' => [array_merge($this->fieldParents, [$this->fieldDefinition->getName(), 'add_more'])],
         '#submit' => [[get_class($this), 'addMoreSubmit']],
         '#ajax' => [
@@ -1695,6 +1709,25 @@ protected function buildSelectAddMode() {
     return $add_more_elements;
   }
 
+  /**
+   * Gets current language code from the form state or item.
+   *
+   * Since the paragraph field is not set as translatable, the item language
+   * code is set to the source language. The intended translation language
+   * is only accessibly through the form state.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   * @param \Drupal\Core\Field\FieldItemListInterface $items
+   *   The field item list.
+   *
+   * @return string
+   *   The language code.
+   */
+  protected function getCurrentLangcode(FormStateInterface $form_state, FieldItemListInterface $items) {
+    return $form_state->has('langcode') ? $form_state->get('langcode') : $items->getEntity()->language()->getId();
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -1710,7 +1743,7 @@ public static function addMoreAjax(array $form, FormStateInterface $form_state)
     // Clear the Add more delta.
     NestedArray::setValue(
       $element,
-      ['add_more', 'add_modal_form_area', 'add_more_delta', '#value'],
+      ['add_more', 'add_more_delta', '#value'],
       ''
     );
 
@@ -1776,7 +1809,7 @@ protected static function prepareDeltaPosition(array &$widget_state, FormStateIn
     }
 
     // Add information into delta mapping for the new element.
-    $original_deltas_size = count($widget_state['original_deltas']);
+    $original_deltas_size = count($widget_state['original_deltas'] ?? []);
     $new_original_deltas[$new_delta] = $original_deltas_size;
     $user_input[$original_deltas_size]['_weight'] = $new_delta;
 
@@ -1794,7 +1827,7 @@ public static function addMoreSubmit(array $form, FormStateInterface $form_state
       $field_path = array_merge($submit['element']['#field_parents'], [$submit['element']['#field_name']]);
       $add_more_delta = NestedArray::getValue(
         $submit['element'],
-        ['add_more', 'add_modal_form_area', 'add_more_delta', '#value']
+        ['add_more', 'add_more_delta', '#value']
       );
 
       static::prepareDeltaPosition($submit['widget_state'], $form_state, $field_path, $add_more_delta);
@@ -2207,7 +2240,7 @@ public function multipleElementValidate(array $elements, FormStateInterface $for
     $widget_state = static::getWidgetState($elements['#field_parents'], $field_name, $form_state);
 
     if ($elements['#required'] && $widget_state['real_item_count'] < 1) {
-      $form_state->setError($elements, t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
+      $form_state->setError($elements, $this->t('@name field is required.', ['@name' => $this->fieldDefinition->getLabel()]));
     }
 
     static::setWidgetState($elements['#field_parents'], $field_name, $form_state, $widget_state);
@@ -2236,7 +2269,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface
       return $values;
     }
 
-    foreach ($values as $delta => &$item) {
+    foreach ($values as &$item) {
       if (isset($widget_state['paragraphs'][$item['_original_delta']]['entity'])
         && $widget_state['paragraphs'][$item['_original_delta']]['mode'] != 'remove') {
         /** @var \Drupal\paragraphs\ParagraphInterface $paragraphs_entity */
@@ -2250,14 +2283,20 @@ public function massageFormValues(array $values, array $form, FormStateInterface
         // A content entity form saves without any rebuild. It needs to set the
         // language to update it in case of language change.
         $langcode_key = $paragraphs_entity->getEntityType()->getKey('langcode');
-        if ($paragraphs_entity->get($langcode_key)->value != $form_state->get('langcode')) {
+        $langcode = $form_state->get('langcode');
+        if (!isset($langcode) && isset($element['#host'])) {
+          // Use the host entity as a last resort to determine the langcode.
+          // @see self::formMultipleElements
+          $langcode = $element['#host']->language()->getId();
+        }
+        if ($paragraphs_entity->get($langcode_key)->value != $langcode) {
           // If a translation in the given language already exists, switch to
           // that. If there is none yet, update the language.
-          if ($paragraphs_entity->hasTranslation($form_state->get('langcode'))) {
-            $paragraphs_entity = $paragraphs_entity->getTranslation($form_state->get('langcode'));
+          if ($paragraphs_entity->hasTranslation($langcode)) {
+            $paragraphs_entity = $paragraphs_entity->getTranslation($langcode);
           }
           else {
-            $paragraphs_entity->set($langcode_key, $form_state->get('langcode'));
+            $paragraphs_entity->set($langcode_key, $langcode);
           }
         }
         if (isset($item['behavior_plugins'])) {
@@ -2373,7 +2412,7 @@ protected function initIsTranslating(FormStateInterface $form_state, ContentEnti
       $this->isTranslating = TRUE;
     }
     $langcode = $form_state->get('langcode');
-    if ($host->hasTranslation($langcode) && $host->getTranslation($langcode)->get($default_langcode_key)->value == 0) {
+    if (isset($langcode) && $host->hasTranslation($langcode) && $host->getTranslation($langcode)->get($default_langcode_key)->value == 0) {
       // Editing a translation.
       $this->isTranslating = TRUE;
     }
diff --git a/web/modules/paragraphs/src/Plugin/migrate/D7FieldCollectionItemDeriver.php b/web/modules/paragraphs/src/Plugin/migrate/D7FieldCollectionItemDeriver.php
new file mode 100644
index 0000000000..6ee8bc916a
--- /dev/null
+++ b/web/modules/paragraphs/src/Plugin/migrate/D7FieldCollectionItemDeriver.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Drupal\paragraphs\Plugin\migrate;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\migrate\Exception\RequirementsException;
+use Drupal\migrate\Plugin\MigrationDeriverTrait;
+use Drupal\migrate_drupal\FieldDiscoveryInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Deriver for field collections.
+ */
+class D7FieldCollectionItemDeriver extends DeriverBase implements ContainerDeriverInterface {
+
+  use MigrationDeriverTrait;
+  use StringTranslationTrait;
+
+  /**
+   * The base plugin ID this derivative is for.
+   *
+   * @var string
+   */
+  protected $basePluginId;
+
+  /**
+   * The migration field discovery service.
+   *
+   * @var \Drupal\migrate_drupal\FieldDiscoveryInterface
+   */
+  protected $fieldDiscovery;
+
+  /**
+   * D7FieldCollectionItemDeriver constructor.
+   *
+   * @param string $base_plugin_id
+   *   The base plugin ID for the plugin ID.
+   * @param \Drupal\migrate_drupal\FieldDiscoveryInterface $field_discovery
+   *   The migration field discovery service.
+   */
+  public function __construct($base_plugin_id, FieldDiscoveryInterface $field_discovery) {
+    $this->basePluginId = $base_plugin_id;
+    $this->fieldDiscovery = $field_discovery;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $base_plugin_id,
+      $container->get('migrate_drupal.field_discovery')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $types = static::getSourcePlugin('d7_field_collection_type');
+
+    try {
+      $types->checkRequirements();
+    }
+    catch (RequirementsException $e) {
+      return $this->derivatives;
+    }
+
+    try {
+      foreach ($types as $row) {
+        /** @var \Drupal\migrate\Row $row */
+        $values = $base_plugin_definition;
+        $fc_bundle = $row->getSourceProperty('field_name');
+        $p_bundle = $row->getSourceProperty('bundle');
+        $values['label'] = $this->t('@label (@type)', [
+          '@label' => $values['label'],
+          '@type' => $row->getSourceProperty('name'),
+        ]);
+        $values['source']['field_name'] = $fc_bundle;
+        $values['destination']['default_bundle'] = $p_bundle;
+
+        /** @var \Drupal\migrate\Plugin\Migration $migration */
+        $migration = \Drupal::service('plugin.manager.migration')
+          ->createStubMigration($values);
+        $migration->setProcessOfProperty('parent_id', 'parent_id');
+        $migration->setProcessOfProperty('parent_type', 'parent_type');
+        $migration->setProcessOfProperty('parent_field_name', 'field_name');
+
+        $this->fieldDiscovery->addBundleFieldProcesses($migration, 'field_collection_item', $fc_bundle);
+        $this->derivatives[$p_bundle] = $migration->getPluginDefinition();
+      }
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      // Once we begin iterating the source plugin it is possible that the
+      // source tables will not exist. This can happen when the
+      // MigrationPluginManager gathers up the migration definitions but we do
+      // not actually have a Drupal 7 source database.
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/web/modules/paragraphs/src/Plugin/migrate/D7ParagraphsItemDeriver.php b/web/modules/paragraphs/src/Plugin/migrate/D7ParagraphsItemDeriver.php
new file mode 100644
index 0000000000..1e8e46da98
--- /dev/null
+++ b/web/modules/paragraphs/src/Plugin/migrate/D7ParagraphsItemDeriver.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Drupal\paragraphs\Plugin\migrate;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Database\DatabaseExceptionWrapper;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\migrate\Exception\RequirementsException;
+use Drupal\migrate\Plugin\MigrationDeriverTrait;
+use Drupal\migrate_drupal\FieldDiscoveryInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Deriver for Paragraph Items.
+ */
+class D7ParagraphsItemDeriver extends DeriverBase implements ContainerDeriverInterface {
+
+  use MigrationDeriverTrait;
+  use StringTranslationTrait;
+
+  /**
+   * The base plugin ID this derivative is for.
+   *
+   * @var string
+   */
+  protected $basePluginId;
+
+  /**
+   * The migration field discovery service.
+   *
+   * @var \Drupal\migrate_drupal\FieldDiscoveryInterface
+   */
+  protected $fieldDiscovery;
+
+  /**
+   * D7ParagraphsItemDeriver constructor.
+   *
+   * @param string $base_plugin_id
+   *   The base plugin ID for the plugin ID.
+   * @param \Drupal\migrate_drupal\FieldDiscoveryInterface $field_discovery
+   *   The migration field discovery service.
+   */
+  public function __construct($base_plugin_id, FieldDiscoveryInterface $field_discovery) {
+    $this->basePluginId = $base_plugin_id;
+    $this->fieldDiscovery = $field_discovery;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $base_plugin_id,
+      $container->get('migrate_drupal.field_discovery')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $types = static::getSourcePlugin('d7_paragraphs_type');
+    try {
+      $types->checkRequirements();
+    }
+    catch (RequirementsException $e) {
+      return $this->derivatives;
+    }
+
+    try {
+      foreach ($types as $row) {
+        $values = $base_plugin_definition;
+        $bundle = $row->getSourceProperty('bundle');
+        $values['label'] = $this->t('@label (@type)', [
+          '@label' => $values['label'],
+          '@type' => $row->getSourceProperty('name'),
+        ]);
+        $values['source']['bundle'] = $bundle;
+        $values['destination']['default_bundle'] = $bundle;
+
+        /** @var \Drupal\migrate\Plugin\Migration $migration */
+        $migration = \Drupal::service('plugin.manager.migration')
+          ->createStubMigration($values);
+        $this->fieldDiscovery->addBundleFieldProcesses($migration, 'paragraphs_item', $bundle);
+        $this->derivatives[$bundle] = $migration->getPluginDefinition();
+      }
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      // Once we begin iterating the source plugin it is possible that the
+      // source tables will not exist. This can happen when the
+      // MigrationPluginManager gathers up the migration definitions but we do
+      // not actually have a Drupal 7 source database.
+    }
+    return $this->derivatives;
+  }
+
+}
diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
index 19d9a21e4d..73d8b00617 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/field/FieldCollection.php
@@ -8,9 +8,6 @@
 /**
  * Field Plugin for field collection migrations.
  *
- * @todo Implement ::defineValueProcessPipeline()
- * @see https://www.drupal.org/project/paragraphs/issues/2911244
- *
  * @MigrateField(
  *   id = "field_collection",
  *   core = {7},
@@ -23,11 +20,64 @@
  */
 class FieldCollection extends FieldPluginBase {
 
-  /**
+  /*
    * Length of the 'field_' prefix that field collection prepends to bundles.
    */
   const FIELD_COLLECTION_PREFIX_LENGTH = 6;
 
+  /**
+   * {@inheritdoc}
+   */
+  public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) {
+    $process = [
+      'plugin' => 'sub_process',
+      'source' => $field_name,
+      'process' => [
+        'target_id' => [
+          [
+            'plugin' => 'paragraphs_lookup',
+            'tags' => 'Field Collection Content',
+            'source' => 'value',
+          ],
+          [
+            'plugin' => 'extract',
+            'index' => ['id'],
+          ],
+        ],
+        'target_revision_id' => [
+          [
+            'plugin' => 'paragraphs_lookup',
+            'tags' => [
+              'Field Collection Revisions Content',
+              'Field Collection Content',
+            ],
+            'tag_ids' => [
+              'Field Collection Revisions Content' => ['revision_id'],
+              'Field Collection Content' => ['value'],
+            ],
+          ],
+          [
+            'plugin' => 'extract',
+            'index' => ['revision_id'],
+          ],
+        ],
+      ],
+    ];
+    $migration->setProcessOfProperty($field_name, $process);
+
+    // Add the respective field collection migration as a dependency.
+    $migration_dependency = 'd7_field_collection:' . substr($field_name, static::FIELD_COLLECTION_PREFIX_LENGTH);
+    $migration_rev_dependency = 'd7_field_collection_revisions:' . substr($field_name, static::FIELD_COLLECTION_PREFIX_LENGTH);
+    $dependencies = $migration->getMigrationDependencies() + ['required' => []];
+    $dependencies['required'] = array_unique(array_merge(array_values($dependencies['required']), [$migration_dependency]));
+    $migration->set('migration_dependencies', $dependencies);
+
+    if (strpos($migration->getDestinationPlugin()->getPluginId(), 'entity_revision:') === 0 || strpos($migration->getDestinationPlugin()->getPluginId(), 'entity_complete:') === 0) {
+      $dependencies['required'] = array_unique(array_merge(array_values($dependencies['required']), [$migration_rev_dependency]));
+      $migration->set('migration_dependencies', $dependencies);
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -42,7 +92,6 @@ public function alterFieldFormatterMigration(MigrationInterface $migration) {
   public function getFieldFormatterMap() {
     return [
       'field_collection_view' => 'entity_reference_revisions_entity_view',
-    // TODO: Change the autogenerated stub.
     ] + parent::getFieldFormatterMap();
   }
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
index bb3d82121c..6c42aa497c 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/field/Paragraphs.php
@@ -8,9 +8,6 @@
 /**
  * Field Plugin for paragraphs migrations.
  *
- * @todo Implement ::defineValueProcessPipeline()
- * @see https://www.drupal.org/project/paragraphs/issues/2911244
- *
  * @MigrateField(
  *   id = "paragraphs",
  *   core = {7},
@@ -23,6 +20,68 @@
  */
 class Paragraphs extends FieldPluginBase {
 
+  /**
+   * {@inheritdoc}
+   */
+  public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) {
+    $process = [
+      'plugin' => 'sub_process',
+      'source' => $field_name,
+      'process' => [
+        'target_id' => [
+          [
+            'plugin' => 'paragraphs_lookup',
+            'tags' => 'Paragraphs Content',
+            'source' => 'value',
+          ],
+          [
+            'plugin' => 'extract',
+            'index' => ['id'],
+          ],
+        ],
+        'target_revision_id' => [
+          [
+            'plugin' => 'paragraphs_lookup',
+            'tags' => [
+              'Paragraphs Revisions Content',
+              'Paragraphs Content',
+            ],
+            'tag_ids' => [
+              'Paragraphs Revisions Content' => ['revision_id'],
+              'Paragraphs Content' => ['value'],
+            ],
+            // D8.4 Does not like an empty source value, Even when using ids.
+            'source' => 'value',
+          ],
+          [
+            'plugin' => 'extract',
+            'index' => ['revision_id'],
+          ],
+        ],
+      ],
+    ];
+    $migration->setProcessOfProperty($field_name, $process);
+
+    // Add paragraphs migration as a dependency (if this is not a paragraph
+    // migration).
+    // @todo: This is a great example why we should consider derive paragraph
+    // migrations based on parent entity type (and bundle).
+    if (!in_array('Paragraphs Content', $migration->getMigrationTags(), TRUE)) {
+      $dependencies = $migration->getMigrationDependencies() + ['required' => []];
+      $dependencies['required'] = array_unique(array_merge(array_values($dependencies['required']), [
+        'd7_paragraphs',
+      ]));
+      $migration->set('migration_dependencies', $dependencies);
+
+      if (strpos($migration->getDestinationPlugin()->getPluginId(), 'entity_revision:') === 0 || strpos($migration->getDestinationPlugin()->getPluginId(), 'entity_complete:') === 0) {
+        $dependencies['required'] = array_unique(array_merge(array_values($dependencies['required']), [
+          'd7_paragraphs_revisions',
+        ]));
+        $migration->set('migration_dependencies', $dependencies);
+      }
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -45,7 +104,6 @@ public function alterFieldFormatterMigration(MigrationInterface $migration) {
   public function getFieldFormatterMap() {
     return [
       'paragraphs_view' => 'entity_reference_revisions_entity_view',
-    // TODO: Change the autogenerated stub.
     ] + parent::getFieldFormatterMap();
   }
 
@@ -53,15 +111,15 @@ public function getFieldFormatterMap() {
    * {@inheritdoc}
    */
   public function getFieldWidgetMap() {
-    return ['paragraphs_embed' => 'entity_reference_paragraphs']
-      + parent::getFieldWidgetMap();
+    return [
+      'paragraphs_embed' => 'entity_reference_paragraphs',
+    ] + parent::getFieldWidgetMap();
   }
 
   /**
    * {@inheritdoc}
    */
   public function alterFieldMigration(MigrationInterface $migration) {
-
     $settings = [
       'paragraphs' => [
         'plugin' => 'paragraphs_field_settings',
@@ -74,7 +132,6 @@ public function alterFieldMigration(MigrationInterface $migration) {
    * {@inheritdoc}
    */
   public function alterFieldInstanceMigration(MigrationInterface $migration) {
-
     $settings = [
       'paragraphs' => [
         'plugin' => 'paragraphs_field_instance_settings',
diff --git a/web/modules/paragraphs/src/Plugin/migrate/process/FieldCollectionFieldInstanceSettings.php b/web/modules/paragraphs/src/Plugin/migrate/process/FieldCollectionFieldInstanceSettings.php
index e552a6716c..baf76bbaa6 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/process/FieldCollectionFieldInstanceSettings.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/process/FieldCollectionFieldInstanceSettings.php
@@ -26,7 +26,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     if ($type == 'field_collection') {
       $bundles = $this->entityTypeBundleInfo->getBundleInfo('paragraph');
 
-      $target_bundle = $row->getSourceProperty('field_name');
+      $target_bundle = $row->getSourceProperty('field_name') ?? '';
       // Remove field_ prefix for new bundle.
       $target_bundle = substr($target_bundle, FieldCollection::FIELD_COLLECTION_PREFIX_LENGTH);
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsLookup.php b/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsLookup.php
new file mode 100644
index 0000000000..f9474810d8
--- /dev/null
+++ b/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsLookup.php
@@ -0,0 +1,235 @@
+<?php
+
+namespace Drupal\paragraphs\Plugin\migrate\process;
+
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\migrate\MigrateException;
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\MigrateLookupInterface;
+use Drupal\migrate\MigrateStubInterface;
+use Drupal\migrate\Plugin\migrate\process\MigrationLookup;
+use Drupal\migrate\Plugin\MigrateIdMapInterface;
+use Drupal\migrate\Plugin\MigratePluginManagerInterface;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Looks up the value of a paragraph property based on previous migrations.
+ *
+ * Compared to the MigrationLookup, this process plugin can accept two new
+ * configuration option: these are 'tags' and 'tag_ids'.
+ * Every other configuration options are inherited from MigrationLookup. If
+ * 'tags' has value, then the migration tag based lookup takes precedence over
+ * the migration plugin ID based property lookup.
+ *
+ * @todo Clean up, add test coverage and document how the two extra config
+ *   option works in https://drupal.org/i/3146646.
+ *
+ * @MigrateProcessPlugin(
+ *   id = "paragraphs_lookup"
+ * )
+ */
+class ParagraphsLookup extends MigrationLookup {
+
+  /**
+   * The migration plugin manager.
+   *
+   * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
+   */
+  protected $migrationPluginManager;
+
+  /**
+   * The process plugin manager.
+   *
+   * @var \Drupal\migrate\Plugin\MigratePluginManager
+   */
+  protected $processPluginManager;
+
+  /**
+   * Constructs a MigrationLookup object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
+   *   The Migration the plugin is being used in.
+   * @param \Drupal\migrate\MigrateLookupInterface $migrate_lookup
+   *   The migrate lookup service.
+   * @param \Drupal\migrate\MigrateStubInterface $migrate_stub
+   *   The migrate stub service.
+   * @param \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager
+   *   The Migration Plugin Manager Interface.
+   * @param \Drupal\migrate\Plugin\MigratePluginManagerInterface $process_plugin_manager
+   *   The process migration plugin manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrateLookupInterface $migrate_lookup, MigrateStubInterface $migrate_stub, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManagerInterface $process_plugin_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $migrate_lookup, $migrate_stub);
+
+    $this->migrationPluginManager = $migration_plugin_manager;
+    $this->processPluginManager = $process_plugin_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('migrate.lookup'),
+      $container->get('migrate.stub'),
+      $container->get('plugin.manager.migration'),
+      $container->get('plugin.manager.migrate.process')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    $source_id_values = [];
+    $destination_ids = NULL;
+    $migrations = [];
+    if (isset($this->configuration['tags'])) {
+      $tags = (array) $this->configuration['tags'];
+      foreach ($tags as $tag) {
+        /** @var \Drupal\migrate\Plugin\MigrationInterface[] $tag_migrations */
+        $tag_migrations = $this->migrationPluginManager->createInstancesByTag($tag);
+        $migrations += $tag_migrations;
+        if (isset($this->configuration['tag_ids'][$tag])) {
+          $configuration = ['source' => $this->configuration['tag_ids'][$tag]];
+          try {
+            $get_process_plugin = $this->processPluginManager
+              ->createInstance('get', $configuration, $this->migration);
+          }
+          catch (PluginException $e) {
+            continue;
+          }
+          $value = $get_process_plugin->transform(NULL, $migrate_executable, $row, $destination_property);
+        }
+        foreach ($tag_migrations as $migration_id => $migration) {
+          $source_id_values[$migration_id] = (array) $value;
+          $destination_ids = $this->lookupDestination($migration, $value);
+          if ($destination_ids) {
+            break 2;
+          }
+        }
+      }
+    }
+    elseif (!empty($this->configuration['migration'])) {
+      $destination_ids = parent::transform($value, $migrate_executable, $row, $destination_property);
+      $migration_ids = $this->configuration['migration'];
+      if (!is_array($migration_ids)) {
+        $migration_ids = (array) $migration_ids;
+      }
+      /** @var \Drupal\migrate\Plugin\MigrationInterface[] $migrations */
+      $migrations = $this->migrationPluginManager->createInstances($migration_ids);
+      foreach ($migrations as $migration_id => $migration) {
+        if (isset($this->configuration['source_ids'][$migration_id])) {
+          $configuration = ['source' => $this->configuration['source_ids'][$migration_id]];
+          $value = $this->processPluginManager
+            ->createInstance('get', $configuration, $this->migration)
+            ->transform(NULL, $migrate_executable, $row, $destination_property);
+        }
+        $source_id_values[$migration_id] = (array) $value;
+        $destination_ids = $this->lookupDestination($migration, $value);
+        if ($destination_ids) {
+          break;
+        }
+      }
+    }
+    else {
+      throw new MigrateException("Either Migration or Tags must be defined.");
+    }
+
+    if (!$destination_ids && !empty($this->configuration['no_stub'])) {
+      return NULL;
+    }
+
+    if (!$destination_ids) {
+      // If the lookup didn't succeed, figure out which migration will do the
+      // stubbing.
+      if (isset($this->configuration['stub_id'])) {
+        $migration = $this->migrationPluginManager->createInstance($this->configuration['stub_id']);
+        assert($migration instanceof MigrationInterface);
+      }
+      else {
+        $migration = reset($migrations);
+      }
+      $destination_plugin = $migration->getDestinationPlugin(TRUE);
+      // Only keep the process necessary to produce the destination ID.
+      $process = $migration->getProcess();
+
+      // We already have the source ID values but need to key them for the Row
+      // constructor.
+      $source_ids = $migration->getSourcePlugin()->getIds();
+      $values = [];
+      foreach (array_keys($source_ids) as $index => $source_id) {
+        $values[$source_id] = $source_id_values[$migration->getPluginId()][$index];
+      }
+
+      // @todo use the migration.stub service.
+      $stub_row = new Row($values + $migration->getSourceConfiguration(), $source_ids, TRUE);
+
+      // Do a normal migration with the stub row.
+      $migrate_executable->processRow($stub_row, $process);
+      $destination_ids = [];
+      $id_map = $migration->getIdMap();
+      try {
+        $destination_ids = $destination_plugin->import($stub_row);
+      }
+      catch (\Exception $e) {
+        $id_map->saveMessage($stub_row->getSourceIdValues(), $e->getMessage());
+      }
+
+      if ($destination_ids) {
+        $id_map->saveIdMapping($stub_row, $destination_ids, MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
+      }
+    }
+    if ($destination_ids) {
+      if (count($destination_ids) == 1) {
+        return reset($destination_ids);
+      }
+      else {
+        return $destination_ids;
+      }
+    }
+
+    throw new MigrateException("Paragraphs lookup wasn't able to find the corresponding property for paragraph with source ID $value for the destination property $destination_property.");
+  }
+
+  /**
+   * Look for destination records.
+   *
+   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
+   *   The migration that should be checked.
+   * @param string|string[] $value
+   *   The source ID.
+   *
+   * @return array|false
+   *   The array of the destination identifiers, or FALSE if destination cannot
+   *   be determined.
+   *
+   * @throws \Drupal\migrate\MigrateException
+   * @throws \Drupal\migrate\MigrateSkipProcessException
+   */
+  protected function lookupDestination(MigrationInterface $migration, $value) {
+    $value = (array) $value;
+    $this->skipInvalid($value);
+
+    // Break out of the loop as soon as a destination ID is found.
+    if ($destination_ids = $migration->getIdMap()->lookupDestinationIds($value)) {
+      $destination_ids = array_combine(array_keys($migration->getDestinationPlugin()->getIds()), reset($destination_ids));
+      return $destination_ids;
+    }
+    return FALSE;
+  }
+
+}
diff --git a/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsProcessOnValue.php b/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsProcessOnValue.php
index 2e3992651f..cc77f4a4d5 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsProcessOnValue.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/process/ParagraphsProcessOnValue.php
@@ -3,7 +3,6 @@
 namespace Drupal\paragraphs\Plugin\migrate\process;
 
 use Drupal\migrate\MigrateExecutableInterface;
-use Drupal\migrate\MigrateSkipRowException;
 use Drupal\migrate\Row;
 
 /**
@@ -43,9 +42,14 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       throw new \InvalidArgumentException("Required argument 'process' not set or invalid for paragraphs_process_on_value plugin");
     }
     $source_value = $row->getSourceProperty($this->configuration['source_value']);
+
     if (is_null($source_value)) {
-      throw new MigrateSkipRowException('Argument source_value is not valid for ProcessOnValue plugin');
+      // This is probably a migration that shouldn't be touched by Paragraphs.
+      // For example, throwing an exception here would prevent the migration of
+      // the comment field configurations.
+      return $value;
     }
+
     if ($source_value === $this->configuration['expected_value']) {
       $process = $this->configuration['process'];
 
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
index d96646be7b..50af07d341 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItem.php
@@ -50,6 +50,9 @@ public function query() {
     // bundles retrieved.
     if ($this->configuration['field_name']) {
       $query->condition('f.field_name', $this->configuration['field_name']);
+      $query->addField('fc', 'entity_type', 'parent_type');
+      $query->addField('fc', 'entity_id', 'parent_id');
+      $query->innerJoin('field_revision_' . $this->configuration['field_name'], 'fc', 'fc.' . $this->configuration['field_name'] . '_value = f.item_id and fc.' . $this->configuration['field_name'] . '_revision_id = f.revision_id');
     }
     return $query;
   }
@@ -85,6 +88,8 @@ public function fields() {
       'revision_id' => $this->t('The field_collection_item revision id'),
       'bundle' => $this->t('The field_collection bundle'),
       'field_name' => $this->t('The field_collection field_name'),
+      'parent_type' => $this->t('The type of the parent entity'),
+      'parent_id' => $this->t('The identifier of the parent entity'),
     ];
 
     return $fields;
@@ -94,14 +99,12 @@ public function fields() {
    * {@inheritdoc}
    */
   public function getIds() {
-    $ids = [
+    return [
       'item_id' => [
         'type' => 'integer',
         'alias' => 'f',
       ],
     ];
-
-    return $ids;
   }
 
 }
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItemRevision.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItemRevision.php
index d281f5c9ee..bbc2188505 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItemRevision.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/FieldCollectionItemRevision.php
@@ -25,14 +25,12 @@ class FieldCollectionItemRevision extends FieldCollectionItem {
    * {@inheritdoc}
    */
   public function getIds() {
-    $ids = [
+    return [
       'revision_id' => [
         'type' => 'integer',
         'alias' => 'fr',
       ],
     ];
-
-    return $ids;
   }
 
 }
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
index 5bd1f6f93f..ffacff662f 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItem.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\paragraphs\Plugin\migrate\source\d7;
 
+use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\migrate\Row;
 
 /**
@@ -20,9 +21,18 @@ class ParagraphsItem extends FieldableEntity {
 
   /**
    * Join string for getting current revisions.
+   *
+   * @var string
    */
   const JOIN = "p.revision_id = pr.revision_id";
 
+  /**
+   * The prefix of the field table that contains the entity properties.
+   *
+   * @var string
+   */
+  const PARENT_FIELD_TABLE_PREFIX = 'field_data_';
+
   /**
    * {@inheritdoc}
    */
@@ -38,7 +48,8 @@ public function defaultConfiguration() {
   public function query() {
     $query = $this->select('paragraphs_item', 'p')
       ->fields('p',
-        ['item_id',
+        [
+          'item_id',
           'bundle',
           'field_name',
           'archived',
@@ -58,13 +69,47 @@ public function query() {
    * {@inheritdoc}
    */
   public function prepareRow(Row $row) {
+    [
+      'item_id' => $paragraph_id,
+      'revision_id' => $paragraph_revision_id,
+      'field_name' => $paragraph_parent_field_name,
+      'bundle' => $bundle,
+    ] = $row->getSource();
+
+    if (!$paragraph_parent_field_name || !is_string($paragraph_parent_field_name)) {
+      return FALSE;
+    }
 
     // Get Field API field values.
-    $item_id = $row->getSourceProperty('item_id');
-    $revision_id = $row->getSourceProperty('revision_id');
+    foreach (array_keys($this->getFields('paragraphs_item', $bundle)) as $field_name) {
+      $row->setSourceProperty($field_name, $this->getFieldValues('paragraphs_item', $field_name, $paragraph_id, $paragraph_revision_id));
+    }
+
+    // We have to find the corresponding parent entity (which might be an
+    // another paragraph). Active revision only.
+    try {
+      $parent_data_query = $this->getDatabase()->select(static::PARENT_FIELD_TABLE_PREFIX . $paragraph_parent_field_name, 'fd');
+      $parent_data_query->addField('fd', 'entity_type', 'parent_type');
+      $parent_data_query->addField('fd', 'entity_id', 'parent_id');
+      $parent_data = $parent_data_query
+        ->condition("fd.{$paragraph_parent_field_name}_value", $paragraph_id)
+        ->condition("fd.{$paragraph_parent_field_name}_revision_id", $paragraph_revision_id)
+        ->execute()->fetchAssoc();
+    }
+    catch (DatabaseExceptionWrapper $e) {
+      // The paragraphs field data|revision table is missing, we cannot get
+      // the parent entity identifiers. This is a corrupted database.
+      // @todo Shouldn't we have to throw an exception instead?
+      return FALSE;
+    }
+
+    if (!is_iterable($parent_data)) {
+      // We cannot get the parent entity identifiers.
+      return FALSE;
+    }
 
-    foreach (array_keys($this->getFields('paragraphs_item', $row->getSourceProperty('bundle'))) as $field) {
-      $row->setSourceProperty($field, $this->getFieldValues('paragraphs_item', $field, $item_id, $revision_id));
+    foreach ($parent_data as $property_name => $property_value) {
+      $row->setSourceProperty($property_name, $property_value);
     }
 
     return parent::prepareRow($row);
@@ -88,14 +133,12 @@ public function fields() {
    * {@inheritdoc}
    */
   public function getIds() {
-    $ids = [
+    return [
       'item_id' => [
         'type' => 'integer',
         'alias' => 'p',
       ],
     ];
-
-    return $ids;
   }
 
 }
diff --git a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItemRevision.php b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItemRevision.php
index b15610dfe3..4713188175 100644
--- a/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItemRevision.php
+++ b/web/modules/paragraphs/src/Plugin/migrate/source/d7/ParagraphsItemRevision.php
@@ -17,22 +17,25 @@
 class ParagraphsItemRevision extends ParagraphsItem {
 
   /**
-   * Join string for getting all except the current revisions.
+   * {@inheritdoc}
    */
   const JOIN = "p.item_id=pr.item_id AND p.revision_id <> pr.revision_id";
 
+  /**
+   * {@inheritdoc}
+   */
+  const PARENT_FIELD_TABLE_PREFIX = 'field_revision_';
+
   /**
    * {@inheritdoc}
    */
   public function getIds() {
-    $ids = [
+    return [
       'revision_id' => [
         'type' => 'integer',
         'alias' => 'pr',
       ],
     ];
-
-    return $ids;
   }
 
 }
diff --git a/web/modules/paragraphs/templates/paragraphs-dropbutton-wrapper.html.twig b/web/modules/paragraphs/templates/paragraphs-dropbutton-wrapper.html.twig
index 38cff6739f..d647095f97 100644
--- a/web/modules/paragraphs/templates/paragraphs-dropbutton-wrapper.html.twig
+++ b/web/modules/paragraphs/templates/paragraphs-dropbutton-wrapper.html.twig
@@ -13,9 +13,9 @@
  */
 #}
 {% if children %}
-  {% spaceless %}
+  {% apply spaceless %}
     <div class="paragraphs-dropbutton-wrapper">
       {{ children }}
     </div>
-  {% endspaceless %}
+  {% endapply %}
 {% endif %}
diff --git a/web/modules/paragraphs/templates/paragraphs-summary.html.twig b/web/modules/paragraphs/templates/paragraphs-summary.html.twig
index b7f9330bbb..883a48dbf4 100644
--- a/web/modules/paragraphs/templates/paragraphs-summary.html.twig
+++ b/web/modules/paragraphs/templates/paragraphs-summary.html.twig
@@ -17,7 +17,7 @@
   'paragraphs-description',
   expanded ? 'paragraphs-expanded-description' : 'paragraphs-collapsed-description'
 ] %}
-{% spaceless %}
+{% apply spaceless %}
   {% if content is not empty or behaviors is not empty %}
     <div{{ attributes.addClass(classes) }}>
       {% if content is not empty %}
@@ -42,4 +42,4 @@
       {% endif %}
     </div>
   {% endif %}
-{% endspaceless %}
+{% endapply %}
diff --git a/web/modules/paragraphs/tests/fixtures/sites/default/files/Babylon5.txt b/web/modules/paragraphs/tests/fixtures/sites/default/files/Babylon5.txt
new file mode 100644
index 0000000000..6a7e452749
--- /dev/null
+++ b/web/modules/paragraphs/tests/fixtures/sites/default/files/Babylon5.txt
@@ -0,0 +1 @@
+***
diff --git a/web/modules/paragraphs/tests/fixtures/sites/default/files/cube.jpeg b/web/modules/paragraphs/tests/fixtures/sites/default/files/cube.jpeg
new file mode 100644
index 0000000000..652a7db77d
--- /dev/null
+++ b/web/modules/paragraphs/tests/fixtures/sites/default/files/cube.jpeg
@@ -0,0 +1 @@
+********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
\ No newline at end of file
diff --git a/web/modules/paragraphs/tests/fixtures/sites/default/files/ds9.txt b/web/modules/paragraphs/tests/fixtures/sites/default/files/ds9.txt
new file mode 100644
index 0000000000..b49b7f69a8
--- /dev/null
+++ b/web/modules/paragraphs/tests/fixtures/sites/default/files/ds9.txt
@@ -0,0 +1,79 @@
+                __                ___               ___
+              ,' ,'              |   |              `. `.
+            ,' ,'                |===|                `. `.
+           / //                  |___|                  \\ \
+          / //                   |___|                   \\ \
+         ////                    |___|                    \\\\
+        /  /                    ||   ||                    \  \
+       /  /                     ||   ||                     \  \
+      /| |                      ||   ||                      | |\
+      || |                     | : o : |                     | ||
+     |  \|                     | .===. |                     |/  |
+     |  |\                    /| (___) |\                    /|  |
+    |__||.\         .-.      // /,_._,\ \\      .-.         /.||__|
+    |__||_.\        `-.\    //_ [:(|):] _\\    /.-'        /._||__|
+ __/|  ||___`._____ ___\\__/___/_ ||| _\___\__//___ _____.'___||_ |\__
+/___//__________/.-/_____________|.-.|_____________\-.\__________\\___\
+\___\\__\\\_____\`-\__\\\\__\____|_-_|____/_//_____/-'/__//______//__//
+   \|__||__..'         //  \ _ \__|||__/ _ /  \\         `..__||__|/
+    |__||_./        .-'/    \\   |(|)|   //    \`-.        \..||__|
+    |  || /         `-'      \\   \'/   //      `-'         \ ||  |
+     |  |/                    \| :(-): |/                    \|  |
+     |  /|                     | : o : |                     |\  |
+      || |                     | |___| |                     | ||
+      \| |                      ||   ||                      | |/
+       \  \                     ||   ||                     /  /
+        \  \                    ||___||                    /  /
+         \\\\                    |___|                    ////
+          \ \\                   |___|                   // /
+           \ \\                  |   |                  // /
+            `. `.                |===|                ,' ,'
+              `._`.              |___|              ,'_,'
+
+
+                                _     _
+                       _____---' \_n_/ `---_____
+                  _   /  ...  -----------  ...  \   _
+                 ( )-' .  '::.\__  V  __/.::'  . `-( )
+             _  .-'  ':::.  ____ \   / ____  .:::'  `-.  _
+          ,-'.`'      __.--'    \ | | /    `--.__      `'.`-.
+         / ''::..     \          || ||          /     ..::'' \
+        /  .....  ,'\,'          ||_||          `./`.  .....  \
+       / :::::' ,'               |   |               `. '::::: \
+       | '::: ,'                 |   |                 `. :::' |
+      _/  :: /                   |___|                   \ ::  \_
+     (/     /                 ,-'     `-.                 \     \)
+    _/      `.             ,-' ooo    oo `-.             ,'      \_
+   |      /`./          ,-'\               /`-.          \.'\      |
+  |  .:  /             /  \ \_ __.---.__ _/ /  \             \  :.  |
+ .' :;: |           _ / o  \[ '  \   /  ` ]/    \ _           | ::: `.
+ | ':: |           ( `-.   /      | |      \   ,-' )           | ::' |
+ |: ': |            `-./  /       ___       \  \,-'            | :' :|
+.':: ' |           |     / `-. .-' . `-. .-' \   o |           | ' ::`.
+| ::. |           | o  ,| `-. / \`_|_'/ \ .-' |.  o |           | .:: |
+ \    |_          |____|     | ` /   \ ' |     |____|          _|    /
+ (|    _]         ]____[     |- ( (O) ) -|     ]____[         [_    |)
+ /.:  |           |    |     | . \_ _/ . |     |    |           |  :.\
+| :'  |           | o  `|-,-' \ /..|..\ / `-.-|'  o |           |. ': |
+`.  :: |           | o   \ .-' `-.___.-' `-. /   o |           | ::  .'
+ | .:: |          _.\     \|      | |      \/     /._          | ::. |
+ |  ': |      _.-'   \ o   \      | |      /   o /   `-._      | :'  |
+ `.  __ |__.-'_     _.\    /[_.__ | | __._]\  o /._     _`-.__| __  .'
+  | \  \_.--''.' .-'   \  / /    `---'    \ \  /   `-. `.``--__/  / |
+   |_\ __   ,',-'       `-./  o            \,-'       `-.`.   __ /_|
+     \\ / .','             `-. oo .-. oo ,-'             `.`. \ //
+     (\\  \ \                 `-._| |_,-'                 / /  //)
+       \\  ) \                    (_)                    / (  //
+       / \/   `.                                       ,'   \/ \
+       \  .::. `.                                     ,' .:::  /
+        \  ':::. `-./`.                         .'\.-' '''''' /
+         \    '''     /_           _           _\    ::..    /
+          `-.'::'       `--.______| |______.--'           ,-'
+             `-'`-._   ..                   .: .:   _,-'`'
+                  (_)-. ::. ''::::     ::::::  : ,-(_)
+                      \_____   '' _ _    ' _____/
+                            ---._/ u \_.---
+
+Used with permission from:
+Orbital Space Station (Terok Nor - Deep Space 9) - Joe Reiss
+https://startrekasciiart.blogspot.co.uk/2011/05/deep-space-nine.html
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
index 575b23ffe8..df33b7c071 100644
--- a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.info.yml
@@ -1,14 +1,13 @@
 name: Paragraphs test
 type: module
 description: Resources for Paragraphs tests
-core_version_requirement: ^8.7.7 || ^9
 hidden: true
-package: Paragraphs
+package: Testing
 
 dependencies:
   - paragraphs:paragraphs
 
-# Information added by Drupal.org packaging script on 2020-05-21
-version: '8.x-1.12'
+# Information added by Drupal.org packaging script on 2022-08-25
+version: '8.x-1.15'
 project: 'paragraphs'
-datestamp: 1590061337
+datestamp: 1661440900
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.module b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.module
index c5c345eb6d..38e1f8ec40 100644
--- a/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.module
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/paragraphs_test.module
@@ -43,10 +43,10 @@ function paragraphs_test_paragraph_view(array &$build, ParagraphInterface $entit
 }
 
 /**
- * Implements hook_field_widget_WIDGET_TYPE_form_alter().
+ * Implements hook_field_widget_single_element_WIDGET_TYPE_form_alter().
  */
-function paragraphs_test_field_widget_entity_reference_paragraphs_form_alter(&$element, &$form_state, $context) {
+function paragraphs_test_field_widget_single_element_entity_reference_paragraphs_form_alter(&$element, &$form_state, $context) {
   if ($element['#paragraph_type'] == 'altered_paragraph') {
     $element['subform']['field_text']['widget'][0]['#title'] = 'Altered title';
   }
-}
\ No newline at end of file
+}
diff --git a/web/modules/paragraphs/tests/modules/paragraphs_test/src/Form/TestEmbeddedEntityForm.php b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Form/TestEmbeddedEntityForm.php
new file mode 100644
index 0000000000..ea47736bdc
--- /dev/null
+++ b/web/modules/paragraphs/tests/modules/paragraphs_test/src/Form/TestEmbeddedEntityForm.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\paragraphs_test\Form;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Form\FormInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Form\SubformStateInterface;
+
+/**
+ * A class to build a form that embeds a content entity form.
+ *
+ * The logic of form processing is based on Layout Builder's InlineBlock
+ * form processing.
+ */
+class TestEmbeddedEntityForm implements FormInterface {
+
+  /**
+   * The entity of the embedded form.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityInterface
+   */
+  protected $entity;
+
+  /**
+   * TestEmbeddedEntityForm constructor.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The entity of the embedded form.
+   */
+  public function __construct(ContentEntityInterface $entity) {
+    $this->entity = $entity;
+  }
+
+  /**
+   * Get the entity of this form object.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface
+   *   The entity.
+   */
+  public function getEntity() {
+    return $this->entity;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'test_embedded_entity_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    // Based on the logic of Layout Builder's InlineBlock form processing,
+    // the entity form is being inserted via process callback.
+    return [
+      'embedded_entity_form' => [
+        '#type' => 'container',
+        '#process' => [[static::class, 'processEmbeddedEntityForm']],
+        '#entity' => $this->entity,
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, FormStateInterface $form_state) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $embedded_form = $form['embedded_entity_form'];
+    $this->entity = $embedded_form['#entity'];
+
+    $form_display = EntityFormDisplay::collectRenderDisplay($this->entity, 'default');
+    $complete_form_state = $form_state instanceof SubformStateInterface ? $form_state->getCompleteFormState() : $form_state;
+    $form_display->extractFormValues($this->entity, $embedded_form, $complete_form_state);
+    $this->entity->save();
+  }
+
+  /**
+   * Process callback to embed an entity form.
+   *
+   * @param array $element
+   *   The containing element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   *
+   * @return array
+   *   The containing element, with the entity form inserted.
+   */
+  public static function processEmbeddedEntityForm(array $element, FormStateInterface $form_state) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = $element['#entity'];
+    EntityFormDisplay::collectRenderDisplay($entity, 'default')->buildForm($entity, $element, $form_state);
+    return $element;
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php b/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
deleted file mode 100644
index 775b3cc47a..0000000000
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalReplicateEnableTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
-
-/**
- * Enables replicate module.
- *
- * @group paragraphs
- */
-
-class ParagraphsExperimentalReplicateEnableTest extends ParagraphsExperimentalDuplicateFeatureTest {
-
-  public static $modules = [
-    'replicate',
-  ];
-
-}
diff --git a/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTest.php b/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTest.php
new file mode 100644
index 0000000000..6f5e72c68a
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Functional\Migrate;
+
+use Drupal\Tests\paragraphs\Traits\ParagraphsNodeMigrationAssertionsTrait;
+
+/**
+ * Tests the migration of paragraph entities.
+ *
+ * @group paragraphs
+ *
+ * @group legacy
+ */
+class MigrateUiParagraphsTest extends MigrateUiParagraphsTestBase {
+
+  use ParagraphsNodeMigrationAssertionsTrait;
+
+  /**
+   * Tests the result of the paragraphs migration.
+   *
+   * @dataProvider providerParagraphsMigrate
+   */
+  public function testParagraphsMigrate($node_migrate_type_classic) {
+    // Drupal 8.8.x only has 'classic' node migrations.
+    // @see https://www.drupal.org/node/3105503
+    if (!$node_migrate_type_classic && version_compare(\Drupal::VERSION, '8.9', '<')) {
+      $this->pass("Drupal 8.8.x has only the 'classic' node migration.");
+      return;
+    }
+    $this->setClassicNodeMigration($node_migrate_type_classic);
+    $this->assertMigrateUpgradeViaUi();
+    $this->assertParagraphsMigrationResults();
+    $this->assertNode8Paragraphs();
+    $this->assertNode9Paragraphs();
+    $this->assertIcelandicNode9Paragraphs();
+  }
+
+  /**
+   * Provides data and expected results for testing paragraph migrations.
+   *
+   * @return bool[][]
+   *   Classic node migration type.
+   */
+  public function providerParagraphsMigrate() {
+    return [
+      ['node_migrate_type_classic' => TRUE],
+      ['node_migrate_type_classic' => FALSE],
+    ];
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTestBase.php b/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTestBase.php
new file mode 100644
index 0000000000..fcd1867e84
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Functional/Migrate/MigrateUiParagraphsTestBase.php
@@ -0,0 +1,569 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Functional\Migrate;
+
+use Behat\Mink\Exception\ExpectationException;
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Site\Settings;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\migrate\Plugin\MigrateIdMapInterface;
+use Drupal\Tests\migrate_drupal_ui\Functional\MigrateUpgradeTestBase;
+
+/**
+ * Provides a base class for testing Paragraphs migration via the UI.
+ */
+abstract class MigrateUiParagraphsTestBase extends MigrateUpgradeTestBase {
+
+  use StringTranslationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'content_translation',
+    'migrate_drupal_ui',
+    'paragraphs',
+    'telephone',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSourceBasePath() {
+    return \Drupal::service('extension.list.module')->getPath('paragraphs') . '/tests/fixtures';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSourcePrivateFilesPath() {
+    return \Drupal::service('extension.list.module')->getPath('paragraphs') . '/tests/fixtures';
+  }
+
+  /**
+   * Gets the expected entity IDs and labels per entity type after migration.
+   *
+   * @return string|null[][]
+   *   An array of expected entity labels keyed by IDs, grouped by entity type
+   *   ID. For some of the entities, label can be NULL.
+   */
+  protected function getExpectedEntities() {
+    $expected_entities = [
+      'entity_form_display' => [
+        'block_content.basic.default' => NULL,
+        'comment.comment.default' => NULL,
+        'comment.comment_forum.default' => NULL,
+        'comment.comment_node_article.default' => NULL,
+        'comment.comment_node_blog.default' => NULL,
+        'comment.comment_node_book.default' => NULL,
+        'comment.comment_node_page.default' => NULL,
+        'comment.comment_node_paragraphs_test.default' => NULL,
+        'comment.comment_node_test_content_type.default' => NULL,
+        'node.article.default' => NULL,
+        'node.blog.default' => NULL,
+        'node.book.default' => NULL,
+        'node.forum.default' => NULL,
+        'node.page.default' => NULL,
+        'node.paragraphs_test.default' => NULL,
+        'node.test_content_type.default' => NULL,
+        'paragraph.field_collection_test.default' => NULL,
+        'paragraph.nested_fc_inner.default' => NULL,
+        'paragraph.nested_fc_outer.default' => NULL,
+        'paragraph.paragraph_bundle_one.default' => NULL,
+        'paragraph.paragraph_bundle_two.default' => NULL,
+        'taxonomy_term.test_vocabulary.default' => NULL,
+        'user.user.default' => NULL,
+      ],
+      'entity_form_mode' => [
+        'user.register' => 'Register',
+      ],
+      'entity_view_display' => [
+        'block_content.basic.default' => NULL,
+        'comment.comment.default' => NULL,
+        'comment.comment_forum.default' => NULL,
+        'comment.comment_node_article.default' => NULL,
+        'comment.comment_node_blog.default' => NULL,
+        'comment.comment_node_book.default' => NULL,
+        'comment.comment_node_page.default' => NULL,
+        'comment.comment_node_paragraphs_test.default' => NULL,
+        'comment.comment_node_test_content_type.default' => NULL,
+        'node.article.custom' => NULL,
+        'node.article.default' => NULL,
+        'node.article.rss' => NULL,
+        'node.article.teaser' => NULL,
+        'node.blog.default' => NULL,
+        'node.blog.teaser' => NULL,
+        'node.book.default' => NULL,
+        'node.book.teaser' => NULL,
+        'node.forum.default' => NULL,
+        'node.forum.teaser' => NULL,
+        'node.page.default' => NULL,
+        'node.page.teaser' => NULL,
+        'node.paragraphs_test.default' => NULL,
+        'node.paragraphs_test.teaser' => NULL,
+        'node.test_content_type.default' => NULL,
+        'paragraph.field_collection_test.default' => NULL,
+        'paragraph.nested_fc_inner.default' => NULL,
+        'paragraph.nested_fc_outer.default' => NULL,
+        'paragraph.paragraph_bundle_one.default' => NULL,
+        'paragraph.paragraph_bundle_one.paragraphs_editor_preview' => NULL,
+        'paragraph.paragraph_bundle_two.default' => NULL,
+        'taxonomy_term.test_vocabulary.default' => NULL,
+        'user.user.compact' => NULL,
+        'user.user.default' => NULL,
+      ],
+      'entity_view_mode' => [
+        'block_content.full' => 'Full',
+        'comment.full' => 'Full',
+        'node.custom' => 'custom',
+        'node.full' => 'Full',
+        'node.rss' => 'RSS',
+        'node.search_index' => 'Search index',
+        'node.search_result' => 'Search result highlighting input',
+        'node.teaser' => 'Teaser',
+        'paragraph.full' => 'Full',
+        'paragraph.paragraphs_editor_preview' => 'paragraphs_editor_preview',
+        'paragraph.preview' => 'Preview',
+        'taxonomy_term.full' => 'Full',
+        'user.compact' => 'Compact',
+        'user.full' => 'Full',
+      ],
+      'field_storage_config' => [
+        'block_content.body' => 'block_content.body',
+        'comment.comment_body' => 'comment.comment_body',
+        'comment.field_integer' => 'comment.field_integer',
+        'node.body' => 'node.body',
+        'node.comment' => 'node.comment',
+        'node.comment_forum' => 'node.comment_forum',
+        'node.comment_node_article' => 'node.comment_node_article',
+        'node.comment_node_blog' => 'node.comment_node_blog',
+        'node.comment_node_book' => 'node.comment_node_book',
+        'node.comment_node_page' => 'node.comment_node_page',
+        'node.comment_node_paragraphs_test' => 'node.comment_node_paragraphs_test',
+        'node.comment_node_test_content_type' => 'node.comment_node_test_content_type',
+        'node.field_any_paragraph' => 'node.field_any_paragraph',
+        'node.field_boolean' => 'node.field_boolean',
+        'node.field_date' => 'node.field_date',
+        'node.field_date_with_end_time' => 'node.field_date_with_end_time',
+        'node.field_date_without_time' => 'node.field_date_without_time',
+        'node.field_datetime_without_time' => 'node.field_datetime_without_time',
+        'node.field_email' => 'node.field_email',
+        'node.field_field_collection_test' => 'node.field_field_collection_test',
+        'node.field_file' => 'node.field_file',
+        'node.field_float' => 'node.field_float',
+        'node.field_image' => 'node.field_image',
+        'node.field_images' => 'node.field_images',
+        'node.field_integer' => 'node.field_integer',
+        'node.field_integer_list' => 'node.field_integer_list',
+        'node.field_link' => 'node.field_link',
+        'node.field_long_text' => 'node.field_long_text',
+        'node.field_nested_fc_outer' => 'node.field_nested_fc_outer',
+        'node.field_node_entityreference' => 'node.field_node_entityreference',
+        'node.field_paragraph_one_only' => 'node.field_paragraph_one_only',
+        'node.field_phone' => 'node.field_phone',
+        'node.field_private_file' => 'node.field_private_file',
+        'node.field_tags' => 'node.field_tags',
+        'node.field_term_entityreference' => 'node.field_term_entityreference',
+        'node.field_term_reference' => 'node.field_term_reference',
+        'node.field_text' => 'node.field_text',
+        'node.field_text_filtered' => 'node.field_text_filtered',
+        'node.field_text_list' => 'node.field_text_list',
+        'node.field_text_long_filtered' => 'node.field_text_long_filtered',
+        'node.field_text_long_plain' => 'node.field_text_long_plain',
+        'node.field_text_plain' => 'node.field_text_plain',
+        'node.field_text_sum_filtered' => 'node.field_text_sum_filtered',
+        'node.field_user_entityreference' => 'node.field_user_entityreference',
+        'node.taxonomy_forums' => 'node.taxonomy_forums',
+        'paragraph.field_email' => 'paragraph.field_email',
+        'paragraph.field_integer_list' => 'paragraph.field_integer_list',
+        'paragraph.field_nested_fc_inner' => 'paragraph.field_nested_fc_inner',
+        'paragraph.field_text' => 'paragraph.field_text',
+        'paragraph.field_text_list' => 'paragraph.field_text_list',
+        'taxonomy_term.field_integer' => 'taxonomy_term.field_integer',
+        'taxonomy_term.field_term_reference' => 'taxonomy_term.field_term_reference',
+        'user.field_file' => 'user.field_file',
+        'user.field_integer' => 'user.field_integer',
+        'user.user_picture' => 'user.user_picture',
+      ],
+      'field_config' => [
+        'block_content.basic.body' => 'Body',
+        'comment.comment.comment_body' => 'Comment',
+        'comment.comment_forum.comment_body' => 'Comment',
+        'comment.comment_node_article.comment_body' => 'Comment',
+        'comment.comment_node_blog.comment_body' => 'Comment',
+        'comment.comment_node_book.comment_body' => 'Comment',
+        'comment.comment_node_page.comment_body' => 'Comment',
+        'comment.comment_node_paragraphs_test.comment_body' => 'Comment',
+        'comment.comment_node_test_content_type.comment_body' => 'Comment',
+        'comment.comment_node_test_content_type.field_integer' => 'Integer',
+        'node.article.body' => 'Body',
+        'node.article.comment' => 'Comments',
+        'node.article.comment_node_article' => 'Comments',
+        'node.article.field_image' => 'Image',
+        'node.article.field_link' => 'Link',
+        'node.article.field_tags' => 'Tags',
+        'node.article.field_text_filtered' => 'Text filtered',
+        'node.article.field_text_long_filtered' => 'Text long filtered',
+        'node.article.field_text_long_plain' => 'Text long plain',
+        'node.article.field_text_plain' => 'Text plain',
+        'node.article.field_text_sum_filtered' => 'Text summary filtered',
+        'node.blog.body' => 'Body',
+        'node.blog.comment_node_blog' => 'Comments',
+        'node.blog.field_link' => 'Link',
+        'node.book.body' => 'Body',
+        'node.book.comment_node_book' => 'Comments',
+        'node.forum.body' => 'Body',
+        'node.forum.comment_forum' => 'Comments',
+        'node.forum.taxonomy_forums' => 'Forums',
+        'node.page.body' => 'Body',
+        'node.page.comment_node_page' => 'Comments',
+        'node.page.field_text_filtered' => 'Text filtered',
+        'node.page.field_text_long_filtered' => 'Text long filtered',
+        'node.page.field_text_long_plain' => 'Text long plain',
+        'node.page.field_text_plain' => 'Text plain',
+        'node.page.field_text_sum_filtered' => 'Text summary filtered',
+        'node.paragraphs_test.body' => 'Body',
+        'node.paragraphs_test.comment_node_paragraphs_test' => 'Comments',
+        'node.paragraphs_test.field_any_paragraph' => 'Any Paragraph',
+        'node.paragraphs_test.field_field_collection_test' => 'Field Collection Test',
+        'node.paragraphs_test.field_nested_fc_outer' => 'Nested FC Outer',
+        'node.paragraphs_test.field_paragraph_one_only' => 'Paragraph One Only',
+        'node.test_content_type.field_boolean' => 'Boolean',
+        'node.test_content_type.comment_node_test_content_type' => 'Comments',
+        'node.test_content_type.field_date' => 'Date',
+        'node.test_content_type.field_date_with_end_time' => 'Date With End Time',
+        'node.test_content_type.field_date_without_time' => 'Date without time',
+        'node.test_content_type.field_datetime_without_time' => 'Datetime without time',
+        'node.test_content_type.field_email' => 'Email',
+        'node.test_content_type.field_file' => 'File',
+        'node.test_content_type.field_float' => 'Float',
+        'node.test_content_type.field_images' => 'Images',
+        'node.test_content_type.field_integer' => 'Integer',
+        'node.test_content_type.field_integer_list' => 'Integer List',
+        'node.test_content_type.field_link' => 'Link',
+        'node.test_content_type.field_long_text' => 'Long text',
+        'node.test_content_type.field_node_entityreference' => 'Node Entity Reference',
+        'node.test_content_type.field_phone' => 'Phone',
+        'node.test_content_type.field_private_file' => 'Private file',
+        'node.test_content_type.field_term_entityreference' => 'Term Entity Reference',
+        'node.test_content_type.field_term_reference' => 'Term Reference',
+        'node.test_content_type.field_text' => 'Text',
+        'node.test_content_type.field_text_list' => 'Text List',
+        'node.test_content_type.field_user_entityreference' => 'User Entity Reference',
+        'paragraph.field_collection_test.field_integer_list' => 'Integer List',
+        'paragraph.field_collection_test.field_text' => 'Text',
+        'paragraph.nested_fc_inner.field_text' => 'Text',
+        'paragraph.nested_fc_outer.field_nested_fc_inner' => 'Nested FC Inner',
+        'paragraph.paragraph_bundle_one.field_text' => 'Text',
+        'paragraph.paragraph_bundle_one.field_text_list' => 'Text List',
+        'paragraph.paragraph_bundle_two.field_email' => 'Email',
+        'paragraph.paragraph_bundle_two.field_text' => 'Text',
+        'taxonomy_term.test_vocabulary.field_integer' => 'Integer',
+        'taxonomy_term.test_vocabulary.field_term_reference' => 'Term Reference',
+        'user.user.field_file' => 'File',
+        'user.user.field_integer' => 'Integer',
+        'user.user.user_picture' => 'Picture',
+      ],
+      'node_type' => [
+        'article' => 'Article',
+        'blog' => 'Blog entry',
+        'book' => 'Book page',
+        'forum' => 'Forum topic',
+        'page' => 'Basic page',
+        'paragraphs_test' => 'Paragraphs Test',
+        'test_content_type' => 'Test content type',
+      ],
+      'node' => [
+        1 => 'A Node',
+        2 => 'The thing about Deep Space 9',
+        4 => 'is - The thing about Firefly',
+        6 => 'Comments are closed :-(',
+        7 => 'Comments are open :-)',
+        8 => 'Paragraph Migration Test Content UND',
+        9 => 'Paragraph Migration Test Content EN',
+      ],
+      'paragraphs_type' => [
+        'field_collection_test' => 'Field collection test',
+        'nested_fc_inner' => 'Nested fc inner',
+        'nested_fc_outer' => 'Nested fc outer',
+        'paragraph_bundle_one' => 'Paragraph Bundle One',
+        'paragraph_bundle_two' => 'Paragraph Bundle Two',
+      ],
+      // Paragraph IDs and labels with 'complete' migration, where node
+      // revisions (even the active one) and node translations are migrated in a
+      // single, complete node migration. The final IDs of the paragraph
+      // entities aren't the same as the ones migrated with the 'classic'
+      // migration.
+      // @see https://www.drupal.org/node/3105503
+      'paragraph' => [
+        1 => 'Paragraph Migration Test Content UND > Field Collection Test',
+        2 => 'Paragraph Migration Test Content UND > Field Collection Test',
+        3 => 'Paragraph Migration Test Content EN > Field Collection Test',
+        4 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        5 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        6 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        7 => 'Paragraph Migration Test Content UND > Nested FC Outer > Nested FC Inner',
+        8 => 'Paragraph Migration Test Content UND > Nested FC Outer',
+        9 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+        10 => 'Paragraph Migration Test Content UND > Any Paragraph',
+        11 => 'Paragraph Migration Test Content UND > Paragraph One Only',
+        12 => 'Paragraph Migration Test Content EN > Any Paragraph',
+        13 => 'Paragraph Migration Test Content EN > Paragraph One Only',
+        14 => 'Paragraph Migration Test Content EN > Paragraph One Only (previous revision)',
+        15 => 'Paragraph Migration Test Content UND > Any Paragraph',
+        16 => 'Paragraph Migration Test Content EN > Any Paragraph',
+        17 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+        18 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+      ],
+    ];
+
+    // Paragraph IDs and labels with 'classic' node migration (core 8.8.x has
+    // only this), where nodes, node revisions and node translations are
+    // migrated separately.
+    if (Settings::get('migrate_node_migrate_type_classic', FALSE)) {
+      $expected_entities['paragraph'] = [
+        1 => 'Paragraph Migration Test Content UND > Field Collection Test (previous revision)',
+        2 => 'Paragraph Migration Test Content UND > Field Collection Test (previous revision)',
+        3 => 'Paragraph Migration Test Content EN > Field Collection Test',
+        4 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        5 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        6 => 'Paragraph Migration Test Content EN > Field Collection Test (previous revision)',
+        7 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+        8 => 'Paragraph Migration Test Content UND > Any Paragraph (previous revision)',
+        9 => 'Paragraph Migration Test Content UND > Paragraph One Only (previous revision)',
+        10 => 'Paragraph Migration Test Content EN > Any Paragraph',
+        11 => 'Paragraph Migration Test Content EN > Paragraph One Only',
+        12 => 'Paragraph Migration Test Content EN > Paragraph One Only (previous revision)',
+        13 => 'Paragraph Migration Test Content UND > Any Paragraph (previous revision)',
+        14 => 'Paragraph Migration Test Content EN > Any Paragraph',
+        15 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+        16 => 'Paragraph Migration Test Content EN > Any Paragraph (previous revision)',
+        17 => 'Paragraph Migration Test Content UND > Nested FC Outer > Nested FC Inner',
+        18 => 'Paragraph Migration Test Content UND > Nested FC Outer',
+      ];
+    }
+
+    return $expected_entities;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCounts() {
+    // This is not used.
+    $entity_counts = [];
+
+    foreach ($this->getExpectedEntities() as $entity_type_id => $expected_entities) {
+      $entity_counts[$entity_type_id] = count($expected_entities);
+    }
+
+    return $entity_counts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCountsIncremental() {
+    // Unused.
+    return $this->getEntityCounts();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getAvailablePaths() {
+    // Unused.
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getMissingPaths() {
+    // Unused.
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->loadFixture(\Drupal::service('extension.list.module')->getPath('paragraphs') . '/tests/fixtures/drupal7.php');
+  }
+
+  /**
+   * Executes the upgrade process by the UI and asserts basic expectations.
+   */
+  protected function assertMigrateUpgradeViaUi() {
+    $connection_options = $this->sourceDatabase->getConnectionOptions();
+    $this->drupalGet('/upgrade');
+    $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->submitForm([], $this->t('Continue'));
+    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
+
+    $driver = $connection_options['driver'];
+    if (floatval(\Drupal::VERSION) < 9.3) {
+      $connection_options['prefix'] = $connection_options['prefix']['default'];
+    }
+
+    // Use the driver connection form to get the correct options out of the
+    // database settings. This supports all of the databases we test against.
+    $drivers = drupal_get_database_types();
+    $form = $drivers[$driver]->getFormOptions($connection_options);
+    $connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
+    $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
+    $edit = [
+      $driver => $connection_options,
+      'source_private_file_path' => $this->getSourcePrivateFilesPath(),
+      'version' => $version,
+      'source_base_path' => $this->getSourceBasePath(),
+    ];
+
+    if (count($drivers) !== 1) {
+      $edit['driver'] = $driver;
+    }
+    $edits = $this->translatePostValues($edit);
+
+    $this->submitForm($edits, $this->t('Review upgrade'));
+    $session->pageTextNotContains('Resolve all issues below to continue the upgrade.');
+
+    // ID conflict form.
+    $session->buttonExists($this->t('I acknowledge I may lose data. Continue anyway.'));
+    $this->submitForm([], $this->t('I acknowledge I may lose data. Continue anyway.'));
+    $session->statusCodeEquals(200);
+
+    // Perform the upgrade.
+    $this->submitForm([], $this->t('Perform upgrade'));
+    $session->pageTextContains($this->t('Congratulations, you upgraded Drupal!'));
+
+    // Have to reset all the statics after migration to ensure entities are
+    // loadable.
+    $this->resetAll();
+  }
+
+  /**
+   * Checks that migrations have been performed successfully.
+   */
+  protected function assertParagraphsMigrationResults() {
+    $version = $this->getLegacyDrupalVersion($this->sourceDatabase);
+
+    $this->assertEntities();
+
+    $plugin_manager = $this->container->get('plugin.manager.migration');
+    /** @var \Drupal\migrate\Plugin\Migration[] $all_migrations */
+    $all_migrations = $plugin_manager->createInstancesByTag('Drupal ' . $version);
+
+    foreach ($all_migrations as $migration) {
+      $id_map = $migration->getIdMap();
+      foreach ($id_map as $source_id => $map) {
+        // Convert $source_id into a keyless array so that
+        // \Drupal\migrate\Plugin\migrate\id_map\Sql::getSourceHash() works as
+        // expected.
+        $source_id_values = array_values(unserialize($source_id));
+        $row = $id_map->getRowBySource($source_id_values);
+        $destination = serialize($id_map->currentDestination());
+        $message = "Migration of $source_id to $destination as part of the {$migration->id()} migration. The source row status is " . $row['source_row_status'];
+        // A completed migration should have maps with
+        // MigrateIdMapInterface::STATUS_IGNORED or
+        // MigrateIdMapInterface::STATUS_IMPORTED.
+        $this->assertNotSame(MigrateIdMapInterface::STATUS_FAILED, $row['source_row_status'], $message);
+        $this->assertNotSame(MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $row['source_row_status'], $message);
+      }
+    }
+  }
+
+  /**
+   * Pass if the page HTML title is the given string.
+   *
+   * @param string $expected_title
+   *   The string the page title should be.
+   *
+   * @throws \Behat\Mink\Exception\ExpectationException
+   *   Thrown when element doesn't exist, or the title is a different one.
+   */
+  protected function assertPageTitle($expected_title) {
+    $page_title_element = $this->getSession()->getPage()->find('css', 'h1.page-title');
+    if (!$page_title_element) {
+      throw new ExpectationException('No page title element found on the page', $this->getSession()->getDriver());
+    }
+    $actual_title = $page_title_element->getText();
+    $this->assertSame($expected_title, $actual_title, 'The page title is not the same as expected.');
+  }
+
+  /**
+   * Asserts that the expected entities exist.
+   */
+  protected function assertEntities() {
+    foreach ($this->getExpectedEntities() as $entity_type_id => $expected_entity_labels) {
+      if ($storage = $this->getEntityStorage($entity_type_id)) {
+        $entities = $storage->loadMultiple();
+        $actual_labels = array_reduce($entities, function ($carry, EntityInterface $entity) {
+          $carry[$entity->id()] = (string) $entity->label();
+          return $carry;
+        });
+        if (\Drupal::database()->driver() === 'pgsql') {
+          // On PostgreSQL the entity IDs are not the same so only compare the
+          // labels to ensure we've migrated the expected number of entities.
+          $this->assertEqualsCanonicalizing($expected_entity_labels, $actual_labels, sprintf('The expected %s entities are not matching the actual ones.', $entity_type_id));
+        }
+        else {
+          $this->assertEquals($expected_entity_labels, $actual_labels, sprintf('The expected %s entities are not matching the actual ones.', $entity_type_id));
+        }
+      }
+      else {
+        $this->fail(sprintf('The expected %s entity type is missing.', $entity_type_id));
+      }
+    }
+  }
+
+  /**
+   * Returns the specified entity's storage when the entity definition exists.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   *
+   * @return \Drupal\Core\Entity\EntityStorageInterface|null
+   *   The embed button's entity storage, or NULL if it does not exist.
+   */
+  protected function getEntityStorage(string $entity_type_id) {
+    $entity_type_manager = $this->container->get('entity_type.manager');
+    assert($entity_type_manager instanceof EntityTypeManagerInterface);
+
+    try {
+      $storage = $entity_type_manager->getStorage($entity_type_id);
+    }
+    catch (PluginNotFoundException $e) {
+      // The entity type does not exist.
+      return NULL;
+    }
+
+    return $storage;
+  }
+
+  /**
+   * Sets the type of the node migration.
+   *
+   * @param bool $classic_node_migration
+   *   Whether nodes should be migrated with the 'classic' way. If this is
+   *   FALSE, and the current Drupal instance has the 'complete' migration, then
+   *   the complete node migration will be used.
+   */
+  protected function setClassicNodeMigration(bool $classic_node_migration) {
+    $current_method = Settings::get('migrate_node_migrate_type_classic', FALSE);
+
+    if ($current_method !== $classic_node_migration) {
+      $settings['settings']['migrate_node_migrate_type_classic'] = (object) [
+        'value' => $classic_node_migration,
+        'required' => TRUE,
+      ];
+      $this->writeSettings($settings);
+    }
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsBehaviorsTest.php
similarity index 90%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php
rename to web/modules/paragraphs/tests/src/Functional/ParagraphsBehaviorsTest.php
index f7a83d2d54..a2371e25b6 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalBehaviorsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsBehaviorsTest.php
@@ -2,21 +2,21 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetStable\ParagraphsTestBase;
 
 /**
  * Tests support for Paragraphs behavior plugins.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsBehaviorsTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var string[]
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
   ];
@@ -45,7 +45,7 @@ public function testBehaviorPluginsSettingsFiltering() {
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSame(['test_bold_text' => ['enabled' => TRUE]], \Drupal::config("paragraphs.paragraphs_type.$paragraph_type")->get('behavior_plugins'));
 
     // Add a note that uses the behavior plugin give it an empty setting.
@@ -55,7 +55,7 @@ public function testBehaviorPluginsSettingsFiltering() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Non-bold text',
       'field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $bolded_elements = $this->getSession()->getPage()->findAll('css', '.bold_plugin_text');
     $this->assertEmpty(count($bolded_elements), 'Test plugin did not add a CSS class.');
 
@@ -73,7 +73,7 @@ public function testBehaviorPluginsSettingsFiltering() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Bold text',
       'field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $bolded_elements = $this->getSession()->getPage()->findAll('css', '.bold_plugin_text');
     $this->assertGreaterThan(0, count($bolded_elements), 'Test plugin added a CSS class.');
 
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsUiTest.php
similarity index 78%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php
rename to web/modules/paragraphs/tests/src/Functional/ParagraphsUiTest.php
index 45f0ba9d86..86efb3bfc2 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsUiTest.php
@@ -2,21 +2,21 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetStable\ParagraphsTestBase;
 
 /**
  * Tests the Paragraphs user interface.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
+class ParagraphsUiTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var string[]
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs',
     'field',
@@ -65,7 +65,7 @@ public function testSummary() {
       'title[0][value]' => 'Llama test',
       'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck"></iframe>',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Llama test has been created.');
     // Assert that the summary contains the html text.
     $node = $this->getNodeByTitle('Llama test');
@@ -77,7 +77,7 @@ public function testSummary() {
     $edit = [
       'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe>',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Llama test has been updated.');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->pageTextContains('<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-');
@@ -88,9 +88,38 @@ public function testSummary() {
     $edit = [
       'paragraphs[0][subform][field_text_demo][0][value]' => '<iframe src="https://www.llamatest.neck" class="this-is-a-pretty-long-class-that-needs-to-be-really-long-for-testing-purposes-so-we-have-a-better-summary-test-and-it-has-exactly-144-characters"></iframe><h1>This is a title</h1>',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a title');
   }
 
+  /**
+   * Test the default paragraphs widget used.
+   */
+  public function testDefaultWidget() {
+    $this->loginAsAdmin();
+
+    // Create a new content type.
+    $this->drupalGet('admin/structure/types/add');
+    $this->submitForm([
+      'name' => 'Test',
+      'type' => 'test',
+    ], 'Save and manage fields');
+
+    // Add a new paragraphs field to the content type.
+    $this->clickLink('Add field');
+    $this->submitForm([
+      'new_storage_type' => 'field_ui:entity_reference_revisions:paragraph',
+      'label' => 'Paragraph',
+      'field_name' => 'paragraph',
+    ], 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+
+    // Visit the "Manage form display" page of the new content type.
+    $this->drupalGet('admin/structure/types/manage/test/form-display');
+
+    // The selected widget should be "paragraphs".
+    $this->assertSession()->fieldValueEquals('fields[field_paragraph][type]', 'paragraphs');
+  }
+
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
index 37e98bdd78..0c3478d535 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsUninstallTest.php
@@ -16,7 +16,7 @@ class ParagraphsUninstallTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = array('paragraphs_demo');
+  protected static $modules = array('paragraphs_demo');
 
   /**
    * {@inheritdoc}
@@ -26,7 +26,7 @@ class ParagraphsUninstallTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     $admin_user = $this->drupalCreateUser(array(
@@ -42,28 +42,31 @@ public function setUp() {
   public function testUninstall() {
 
     // Uninstall the module paragraphs_demo.
-    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs_demo]' => TRUE], t('Uninstall'));
-    $this->drupalPostForm(NULL, [], t('Uninstall'));
+    $this->drupalGet('admin/modules/uninstall');
+    $this->submitForm(['uninstall[paragraphs_demo]' => TRUE], 'Uninstall');
+    $this->submitForm([], 'Uninstall');
 
     // Delete library data.
     $this->clickLink('Remove Paragraphs library items');
-    $this->drupalPostForm(NULL, [], t('Delete all Paragraphs library items'));
+    $this->submitForm([], 'Delete all Paragraphs library items');
 
     // Uninstall the library module.
-    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs_library]' => TRUE], t('Uninstall'));
-    $this->drupalPostForm(NULL, [], t('Uninstall'));
+    $this->drupalGet('admin/modules/uninstall');
+    $this->submitForm(['uninstall[paragraphs_library]' => TRUE], 'Uninstall');
+    $this->submitForm([], 'Uninstall');
 
     // Delete paragraphs data.
     $this->clickLink('Remove Paragraphs');
-    $this->drupalPostForm(NULL, [], t('Delete all Paragraphs'));
+    $this->submitForm([], 'Delete all Paragraphs');
 
     // Uninstall the module paragraphs.
-    $this->drupalPostForm('admin/modules/uninstall', ['uninstall[paragraphs]' => TRUE], t('Uninstall'));
-    $this->drupalPostForm(NULL, [], t('Uninstall'));
-    $this->assertSession()->pageTextContains(t('The selected modules have been uninstalled.'));
-    $this->assertSession()->pageTextNotContains(t('Paragraphs demo'));
-    $this->assertSession()->pageTextNotContains(t('Paragraphs library'));
-    $this->assertSession()->pageTextNotContains(t('Paragraphs'));
+    $this->drupalGet('admin/modules/uninstall');
+    $this->submitForm(['uninstall[paragraphs]' => TRUE], 'Uninstall');
+    $this->submitForm([], 'Uninstall');
+    $this->assertSession()->pageTextContains('The selected modules have been uninstalled.');
+    $this->assertSession()->pageTextNotContains('Paragraphs demo');
+    $this->assertSession()->pageTextNotContains('Paragraphs library');
+    $this->assertSession()->pageTextNotContains('Paragraphs');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/ParagraphsWidgetButtonsTest.php
similarity index 96%
rename from web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php
rename to web/modules/paragraphs/tests/src/Functional/ParagraphsWidgetButtonsTest.php
index 3af2a108d6..b50de5531c 100644
--- a/web/modules/paragraphs/tests/src/Functional/ParagraphsExperimentalWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/ParagraphsWidgetButtonsTest.php
@@ -2,23 +2,23 @@
 
 namespace Drupal\Tests\paragraphs\Functional;
 
-use Drupal\Tests\paragraphs\Functional\Experimental\ParagraphsExperimentalTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetStable\ParagraphsTestBase;
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\node\Entity\Node;
 
 /**
- * Tests paragraphs experimental widget buttons.
+ * Tests paragraphs stable widget buttons.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsWidgetButtonsTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var string[]
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs_test',
     'node',
     'paragraphs',
@@ -52,7 +52,7 @@ public function testAutocollapse() {
     // Add another Paragraph type so that there is no default Paragraphs type.
     $this->addParagraphsType('another_paragraph');
 
-    // Check that the paragraphs field uses the experimental widget.
+    // Check that the paragraphs field uses the stable widget.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $option = $this->assertSession()->optionExists('fields[field_paragraphs][type]', 'paragraphs');
     $this->assertTrue($option->isSelected());
@@ -69,7 +69,7 @@ public function testAutocollapse() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Fist paragraph',
       'field_paragraphs[1][subform][field_text][0][value]' => 'Second paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('Autocollapse test node');
 
     // Set the settings to "Open" edit mode without autocollapse.
@@ -241,7 +241,7 @@ public function testClosedExtendNestedEditMode() {
 
     $this->setParagraphsWidgetSettings('paragraphed_test', 'field_paragraphs', $settings);
 
-    // Check that the paragraphs field uses the experimental widget on the
+    // Check that the paragraphs field uses the stable widget on the
     // paragraphed_test content type.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $option = $this->assertSession()->optionExists('fields[field_paragraphs][type]', 'paragraphs');
@@ -250,7 +250,7 @@ public function testClosedExtendNestedEditMode() {
     // Check if the edit mode is set to "Closed, show nested".
     $this->assertSession()->pageTextContains('Edit mode: Closed, show nested');
 
-    // Check that the paragraphs field uses the experimental widget on the
+    // Check that the paragraphs field uses the stable widget on the
     // container_paragraph paragraph type.
     $this->drupalGet('admin/structure/paragraphs_type/container_paragraph/form-display');
     $option = $this->assertSession()->optionExists('fields[field_paragraphs][type]', 'paragraphs');
@@ -492,7 +492,8 @@ public function testAddModeSelect() {
       'settings[handler_settings][negate]' => 0,
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
     ];
-    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs', $edit, 'Save settings');
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs');
+    $this->submitForm($edit, 'Save settings');
 
     $this->drupalGet('node/add/paragraphed_test');
     $this->assertSession()->fieldNotExists('paragraphs[add_more][add_more_select]');
@@ -501,7 +502,7 @@ public function testAddModeSelect() {
       'title[0][value]' => 'Demo text title',
       'paragraphs[0][subform][field_text_demo][0][value]' => 'Demo text for the detail page',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Demo text for the detail page');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAccessTest.php
similarity index 85%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAccessTest.php
index 90530233e3..8dacd53c6b 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAccessTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\image\Entity\ImageStyle;
@@ -22,7 +22,7 @@ class ParagraphsAccessTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'image',
     'field',
@@ -35,7 +35,7 @@ class ParagraphsAccessTest extends ParagraphsTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -70,7 +70,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     $view_display = \Drupal::service('entity_display.repository')->getViewDisplay('paragraph', 'images');
     $view_display->setComponent('field_images_demo', ['settings' => ['image_style' => 'medium']]);
@@ -103,9 +104,10 @@ public function testParagraphAccessCheck() {
     $edit = array(
       'settings[uri_scheme]' => 'private',
     );
-    $this->drupalPostForm('admin/structure/paragraphs_type/images/fields/paragraph.images.field_images_demo/storage', $edit, t('Save field settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/images/fields/paragraph.images.field_images_demo/storage');
+    $this->submitForm($edit, 'Save field settings');
 
-    // Set the form display to classic.
+    // Set the form display to legacy.
     $form_display = EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', ['type' => 'entity_reference_paragraphs']);
     $form_display->save();
@@ -114,7 +116,7 @@ public function testParagraphAccessCheck() {
     $this->drupalGet('node/add/paragraphed_content_demo');
 
     // Add a new paragraphs images item.
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->submitForm([], 'Add images');
 
     $images = $this->getTestFiles('image');
 
@@ -134,19 +136,19 @@ public function testParagraphAccessCheck() {
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path,
     );
 
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
 
     $edit = array(
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2,
     );
 
-    $this->drupalPostForm(NULL,  $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     $image_style = ImageStyle::load('medium');
     $img1_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage.jpg');
-    $image_url = file_url_transform_relative($img1_url);
+    $image_url = \Drupal::service('file_url_generator')->transformRelative($img1_url);
     $this->assertSession()->responseContains($image_url);
-    $this->clickLink(t('Back to content editing'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->clickLink('Back to content editing');
+    $this->submitForm([], 'Save');
 
     $node = $this->drupalGetNodeByTitle('Security test node');
 
@@ -164,7 +166,7 @@ public function testParagraphAccessCheck() {
     // @todo Requesting the same $img_url again triggers a caching problem on
     // drupal.org test bot, thus we request a different file here.
     $img_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage2.jpg');
-    $image_url = file_url_transform_relative($img_url);
+    $image_url = \Drupal::service('file_url_generator')->transformRelative($img_url);
     // Check the text and image after publish. Anonymous should not see content.
     $this->assertSession()->responseNotContains($image_url);
 
@@ -175,21 +177,21 @@ public function testParagraphAccessCheck() {
     $this->loginAsAdmin($admin_user);
     // Create a new demo node.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->pageTextContains('Text');
     $edit = [
       'title[0][value]' => 'delete_permissions',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Edit the node.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     // Check the remove button is present.
     $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]'));
     // Delete the Paragraph and save.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_confirm_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_demo_0_remove');
+    $this->submitForm([], 'field_paragraphs_demo_0_confirm_remove');
+    $this->submitForm([], 'Save');
     $node = $this->getNodeByTitle('delete_permissions');
     $this->assertSession()->addressEquals('node/' . $node->id());
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAddModesTest.php
similarity index 95%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAddModesTest.php
index 4829e60e24..f3c13c3fa2 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAddModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAddModesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -20,11 +20,11 @@ public function testNoDefaultValue() {
 
     // Edit the field.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields');
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
 
     // Check that the current field does not allow to add default values.
     $this->assertSession()->pageTextContains('No widget available for: paragraphs_field.');
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->submitForm([], 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs_field configuration.');
     $this->assertSession()->statusCodeEquals(200);
   }
@@ -38,8 +38,8 @@ public function testEmptyAllowedTypes() {
 
     // Edit the field and save when there are no Paragraphs types available.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields');
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->clickLink('Edit');
+    $this->submitForm([], 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
   }
 
@@ -55,7 +55,7 @@ public function testDropDownMode() {
     $this->addParagraphedContentType('paragraphed_test', 'paragraphs', 'entity_reference_paragraphs');
     // Enter to the field config since the weight is set through the form.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs');
-    $this->drupalPostForm(NULL, [], 'Save settings');
+    $this->submitForm([], 'Save settings');
 
     $this->setAddMode('paragraphed_test', 'paragraphs', 'dropdown');
 
@@ -89,7 +89,7 @@ public function testSelectMode() {
     $this->addParagraphedContentType('paragraphed_test', 'paragraphs', 'entity_reference_paragraphs');
     // Enter to the field config since the weight is set through the form.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs');
-    $this->drupalPostForm(NULL, [], 'Save settings');
+    $this->submitForm([], 'Save settings');
 
     $this->setAddMode('paragraphed_test', 'paragraphs', 'select');
 
@@ -187,7 +187,7 @@ public function testSettingDefaultParagraphType() {
     $this->setDefaultParagraphType('paragraphed_test', 'paragraphs', 'paragraphs_settings_edit', 'text_image');
     $this->removeDefaultParagraphType('paragraphed_test');
     $edit = ['title[0][value]' => 'New Host'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/1/edit');
     $this->assertSession()->pageTextContains('No Paragraph added yet.');
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAdministrationTest.php
similarity index 72%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAdministrationTest.php
index 30e8ba6496..6244c048cd 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsAdministrationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsAdministrationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\paragraphs\Entity\Paragraph;
 
@@ -16,7 +16,7 @@ class ParagraphsAdministrationTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'image',
     'file',
     'views'
@@ -25,7 +25,7 @@ class ParagraphsAdministrationTest extends ParagraphsTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs content type.
     $this->drupalCreateContentType(array('type' => 'paragraphs', 'name' => 'Paragraphs'));
@@ -57,20 +57,20 @@ public function testParagraphsRevisions() {
     ));
     // Configure article fields.
     $this->drupalGet('admin/structure/types/manage/paragraphs/fields');
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'entity_reference_paragraphs'), t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm(array('fields[field_paragraphs][type]' => 'entity_reference_paragraphs'), 'Save');
 
     // Create node with our paragraphs.
     $this->drupalGet('node/add/paragraphs');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     $edit = [
       'title[0][value]' => 'TEST TITEL',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1',
       'field_paragraphs[1][subform][field_text][0][value]' => 'Test text 2',
       'status[value]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $node = $this->drupalGetNodeByTitle('TEST TITEL');
     $paragraph1 = $node->field_paragraphs[0]->target_id;
@@ -84,7 +84,8 @@ public function testParagraphsRevisions() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Foo Bar 1',
       'revision' => FALSE,
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm($edit, 'Save');
 
     $this->countRevisions($node, $paragraph1, $paragraph2, 1);
 
@@ -95,7 +96,8 @@ public function testParagraphsRevisions() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Foo Bar 2',
       'revision' => TRUE,
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm($edit, 'Save');
 
     $this->countRevisions($node, $paragraph1, $paragraph2, 2);
 
@@ -111,8 +113,8 @@ public function testParagraphsRevisions() {
     // Make sure two revisions available.
     $this->assertEquals(count($rows), 2);
     // Revert to the old version.
-    $this->clickLink(t('Revert'));
-    $this->drupalPostForm(NULL, [], t('Revert'));
+    $this->clickLink('Revert');
+    $this->submitForm([], 'Revert');
     $this->drupalGet('node/' . $node->id());
     // Assert the node has been reverted.
     $this->assertSession()->pageTextNotContains('Foo Bar 2');
@@ -148,14 +150,14 @@ public function testParagraphsCreation() {
       'label' => 'Paragraph',
       'field_name' => 'paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save and continue');
-    $this->drupalPostForm(NULL, [], 'Save field settings');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
     $this->assertSession()->linkByHrefExists('admin/structure/paragraphs_type/add');
     $this->clickLink('here');
     $this->assertSession()->addressEquals('admin/structure/paragraphs_type/add');
 
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Add paragraph type'));
+    $this->clickLink('Add paragraph type');
     $this->assertSession()->titleEquals('Add Paragraphs type | Drupal');
     // Create paragraph type text + image.
     $this->addParagraphsType('text_image');
@@ -176,10 +178,10 @@ public function testParagraphsCreation() {
     ), array());
 
     // Change the add more button to select mode.
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm(['fields[field_paragraphs][type]' => 'entity_reference_paragraphs'], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], 'Update');
+    $this->submitForm([], 'Save');
 
     // Create paragraph type image.
     $this->addParagraphsType('image');
@@ -194,7 +196,7 @@ public function testParagraphsCreation() {
     $this->assertSession()->pageTextContains('text_image');
     $this->assertSession()->pageTextContains('image');
     // Make sure there is an edit link for each type.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     // Make sure the field UI appears.
     $this->assertSession()->linkExists('Manage fields');
     $this->assertSession()->linkExists('Manage form display');
@@ -206,17 +208,17 @@ public function testParagraphsCreation() {
     $field_name = 'field_paragraphs';
 
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
+    $this->submitForm(array(), $field_name . "_settings_edit");
 
     // Enable setting.
     $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check if the setting is stored.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->assertSession()->pageTextContains('Add mode: Buttons', 'Checking the settings value.');
+    $this->assertSession()->pageTextContains('Add mode: Buttons');
 
-    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
+    $this->submitForm(array(), $field_name . "_settings_edit");
     // Assert the 'Buttons' option is selected.
     $add_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button');
     $this->assertTrue($add_mode_option->hasAttribute('selected'), 'Updated value correctly.');
@@ -225,10 +227,10 @@ public function testParagraphsCreation() {
     $this->drupalGet('node/add/article');
 
     // Checking changes on article.
-    $this->assertSession()->responseContains('<div class="paragraphs-dropbutton-wrapper"><input', 'Updated value in article.');
+    $this->assertSession()->responseContains('<div class="paragraphs-dropbutton-wrapper"><input');
 
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_image_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_image_add_more');
 
     // Upload some images.
     $files = $this->getTestFiles('image');
@@ -241,34 +243,32 @@ public function testParagraphsCreation() {
       'field_paragraphs[1][subform][field_text][0][value]' => 'Test text 2',
       'files[field_paragraphs_1_subform_field_image_0]' => $file_system->realpath($files[1]->uri),
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('article Test article has been created.');
 
     $node = $this->drupalGetNodeByTitle('Test article');
-    $img1_url = file_create_url(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[0]->filename));
-    $img2_url = file_create_url(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[1]->filename));
-    $img1_size = filesize($files[0]->uri);
-    $img2_size = filesize($files[1]->uri);
-    $img1_mime = \Drupal::service('file.mime_type.guesser')->guess($files[0]->uri);
-    $img2_mime = \Drupal::service('file.mime_type.guesser')->guess($files[1]->uri);
+    $img1_url = \Drupal::service('file_url_generator')->generateString(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[0]->filename));
+    $img2_url = \Drupal::service('file_url_generator')->generateString(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[1]->filename));
+    $img1_mime = \Drupal::service('file.mime_type.guesser')->guessMimeType($files[0]->uri);
+    $img2_mime = \Drupal::service('file.mime_type.guesser')->guessMimeType($files[1]->uri);
 
     // Check the text and image after publish.
     $this->assertSession()->pageTextContains('Test text 1');
-    $this->assertSession()->responseContains('<img src="' . file_url_transform_relative($img1_url));
+    $this->assertSession()->elementExists('css', 'img[src="' . $img1_url . '"]');
     $this->assertSession()->pageTextContains('Test text 2');
-    $this->assertSession()->responseContains('<img src="' . file_url_transform_relative($img2_url));
+    $this->assertSession()->elementExists('css', 'img[src="' . $img2_url . '"]');
 
     // Tests for "Edit mode" settings.
     // Test for closed setting.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Enable setting.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check if the setting is stored.
-    $this->assertSession()->pageTextContains('Edit mode: Closed', 'Checking the settings value.');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->assertSession()->pageTextContains('Edit mode: Closed');
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Assert the 'Closed' option is selected.
     $edit_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed');
     $this->assertTrue($edit_mode_option->hasAttribute('selected'), 'Updated value correctly.');
@@ -281,10 +281,10 @@ public function testParagraphsCreation() {
 
     // Test for preview option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains('Edit mode: Preview', 'Checking the settings value.');
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Edit mode: Preview');
     $this->drupalGet('node/1/edit');
     // The texts in the paragraphs should be visible.
     $this->assertSession()->responseNotContains('field_paragraphs[0][subform][field_text][0][value]');
@@ -294,13 +294,13 @@ public function testParagraphsCreation() {
 
     // Test for open option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Assert the 'Preview' option is selected.
     $edit_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'preview');
     $this->assertTrue($edit_mode_option->hasAttribute('selected'), 'Updated value correctly.');
     // Restore the value to Open for next test.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'open');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/1/edit');
     // The textareas for paragraphs should be visible.
     $this->assertSession()->responseContains('field_paragraphs[0][subform][field_text][0][value]');
@@ -313,34 +313,34 @@ public function testParagraphsCreation() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check both paragraphs in edit page.
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', 'Test text 1');
-    $this->assertSession()->responseContains('<a href="' . $img1_url . '" type="' . $img1_mime . '; length=' . $img1_size . '">' . $files[0]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img1_url . '"][type^="' . $img1_mime . '"]', $files[0]->filename);
     $this->assertSession()->fieldValueEquals('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2');
-    $this->assertSession()->responseContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]', $files[1]->filename);
     // Remove 2nd paragraph.
     $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
     // Confirm the removal.
-    $this->drupalPostForm(NULL, [], t('Confirm removal'));
+    $this->submitForm([], 'Confirm removal');
     $this->assertSession()->fieldNotExists('field_paragraphs[1][subform][field_text][0][value]');
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
     // Assert the paragraph is not deleted unless the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertSession()->responseContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]', $files[1]->filename);
     // Remove the second paragraph.
     $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
     // Confirm the removal.
-    $this->drupalPostForm(NULL, [], t('Confirm removal'));
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->submitForm([], 'Confirm removal');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Assert the paragraph is deleted after the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
 
     // Delete the node.
-    $this->clickLink(t('Delete'));
-    $this->drupalPostForm(NULL, NULL, t('Delete'));
+    $this->clickLink('Delete');
+    $this->submitForm([], 'Delete');
     $this->assertSession()->pageTextContains('Test article has been deleted.');
 
     // Check if the publish/unpublish option works.
@@ -350,38 +350,38 @@ public function testParagraphsCreation() {
       'fields[status][region]' => 'content',
     ];
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $this->assertSession()->responseContains('edit-field-paragraphs-0-subform-status-value');
     $edit = [
       'title[0][value]' => 'Example publish/unpublish',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Example published and unpublished',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains(t('Example published and unpublished'));
-    $this->clickLink(t('Edit'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Example published and unpublished');
+    $this->clickLink('Edit');
     $edit = [
       'field_paragraphs[0][subform][status][value]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextNotContains(t('Example published and unpublished'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextNotContains('Example published and unpublished');
 
     // Set the fields as required.
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->clickLink('Edit', 1);
-    $this->drupalPostForm(NULL, ['preview_mode' => '1'], t('Save content type'));
+    $this->submitForm(['preview_mode' => '1'], 'Save content type');
     $this->drupalGet('admin/structure/paragraphs_type/nested_test/fields');
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, ['required' => TRUE], t('Save settings'));
+    $this->submitForm(['required' => TRUE], 'Save settings');
 
     // Add a new article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more');
+    $this->submitForm([], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->submitForm($edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
     // Test the new field is displayed.
     $this->assertSession()->fieldExists('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]');
 
@@ -390,11 +390,11 @@ public function testParagraphsCreation() {
       'title[0][value]' => 'test required',
       'files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]' => $file_system->realpath($files[2]->uri),
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][0][subform][field_image_only][0][alt]' => 'Alternative_text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('test required has been created.');
     $this->assertSession()->responseNotContains('This value should not be null.');
 
@@ -412,43 +412,45 @@ public function testParagraphsCreation() {
       'label' => 'unsupported field',
       'field_name' => 'unsupportedfield',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
+    $this->submitForm($edit, 'Save and continue');
     $this->assertSession()->optionNotExists('edit-settings-target-type', 'paragraph');
 
     // Test that all Paragraph types can be referenced if none is selected.
     $this->addParagraphsType('nested_double_test');
     static::fieldUIAddExistingField('admin/structure/paragraphs_type/nested_double_test', 'field_paragraphs', 'paragraphs_1');
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, [], 'Save');
-    //$this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'entity_reference_revisions_entity_view'), t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm([], 'Save');
+    //$this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'entity_reference_revisions_entity_view'), 'Save');
     static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_double_test', 'paragraphs_2', 'paragraphs_2', 'entity_reference_revisions', array(
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ), array());
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, [], 'Save');
-    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
+    $this->clickLink('Manage form display');
+    $this->submitForm([], 'Save');
+    $this->drupalGet('node/add/article');
+    $this->submitForm([], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
+    $this->submitForm($edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
     $edit = array(
       'title[0][value]' => 'Nested twins',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Nested twins has been created.');
     $this->assertSession()->pageTextNotContains('This entity (paragraph: ) cannot be referenced.');
 
     // Set the fields as not required.
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->clickLink('Edit', 1);
-    $this->drupalPostForm(NULL, ['required' => FALSE], t('Save settings'));
+    $this->submitForm(['required' => FALSE], 'Save settings');
 
     // Set the Paragraph field edit mode to 'Closed'.
-    $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'], t('Update'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->drupalGet('admin/structure/types/manage/article/form-display');
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'], 'Update');
+    $this->submitForm([], 'Save');
 
     $this->addParagraphsType('node_test');
 
@@ -463,17 +465,18 @@ public function testParagraphsCreation() {
     $node = $this->drupalGetNodeByTitle('Nested twins');
 
     // Create a node with a reference in a Paragraph.
-    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
+    $this->drupalGet('node/add/article');
+    $this->submitForm([], 'field_paragraphs_node_test_add_more');
     \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
     $edit = [
       'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')',
       'title[0][value]' => 'choke test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Delete the referenced node.
     $node->delete();
     // Edit the node with the reference.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     // Since we have validation error (reference to deleted node), paragraph is
     // by default in edit mode.
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_entity_reference][0][target_id]');
@@ -481,49 +484,51 @@ public function testParagraphsCreation() {
     // Assert the validation error message.
     $this->assertSession()->pageTextContains('The referenced entity (node: 4) does not exist');
     // Triggering unrelated button, assert that error message is still present.
-    $this->drupalPostForm(NULL, [], t('Add another item'));
+    $this->submitForm([], 'Add another item');
     $this->assertSession()->pageTextContains('The referenced entity (node: 4) does not exist');
     $this->assertSession()->pageTextContains('Entity reference (value 1) field is required.');
     // Try to collapse with an invalid reference.
-    $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
+    $this->submitForm(['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
     // Paragraph should be still in edit mode.
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_entity_reference][0][target_id]');
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_entity_reference][1][target_id]');
-    $this->drupalPostForm(NULL, [], t('Add another item'));
+    $this->submitForm([], 'Add another item');
     // Assert the validation message.
-    $this->assertSession()->pageTextContains('There are no entities matching "foo".');
+    $this->assertSession()->pageTextMatches('/There are no (entities|content items) matching "foo"./');
     // Attempt to remove the Paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'field_paragraphs_0_remove');
     $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]');
     $this->assertNotEmpty($elements, "'Confirm removal' button appears.");
     // Restore the Paragraph and fix the broken reference.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore');
+    $this->submitForm([], 'field_paragraphs_0_restore');
     $node = $this->drupalGetNodeByTitle('Example publish/unpublish');
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('choke test has been updated.');
     $this->assertSession()->linkExists('Example publish/unpublish');
     // Delete the new referenced node.
     $node->delete();
 
     // Set the Paragraph field edit mode to 'Preview'.
-    $this->drupalPostForm('admin/structure/types/manage/article/form-display', [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview'], t('Update'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->drupalGet('admin/structure/types/manage/article/form-display');
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'preview'], 'Update');
+    $this->submitForm([], 'Save');
 
     $node = $this->drupalGetNodeByTitle('choke test');
     // Attempt to edit the Paragraph.
-    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_edit');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->SubmitForm([], 'field_paragraphs_0_edit');
     // Try to save with an invalid reference.
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains('There are no entities matching "foo".');
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextMatches('/There are no (entities|content items) matching "foo"./');
     // Remove the Paragraph and save the node.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'field_paragraphs_0_remove');
     $elements = $this->xpath('//*[@name="field_paragraphs_0_confirm_remove"]');
     $this->assertNotEmpty($elements, "'Confirm removal' button appears.");
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_confirm_remove');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('choke test has been updated.');
 
     // Verify that the text displayed is correct when no paragraph has been
@@ -541,10 +546,27 @@ public function testParagraphsCreation() {
    * Helper function for revision counting.
    */
   private function countRevisions($node, $paragraph1, $paragraph2, $revisions_count) {
-    $node_revisions_count = \Drupal::entityQuery('node')->condition('nid', $node->id())->allRevisions()->count()->execute();
-    $this->assertEquals($node_revisions_count, $revisions_count);
-    $this->assertEquals(\Drupal::entityQuery('paragraph')->condition('id', $paragraph1)->allRevisions()->count()->execute(), $revisions_count);
-    $this->assertEquals(\Drupal::entityQuery('paragraph')->condition('id', $paragraph2)->allRevisions()->count()->execute(), $revisions_count);
+    $node_revisions_count = \Drupal::entityQuery('node')
+      ->condition('nid', $node->id())
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $node_revisions_count);
+    $paragraph1_revisions_count =\Drupal::entityQuery('paragraph')
+      ->condition('id', $paragraph1)
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $paragraph1_revisions_count);
+    $paragraph2_revisions_count =\Drupal::entityQuery('paragraph')
+      ->condition('id', $paragraph2)
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $paragraph2_revisions_count);
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsConfigTest.php
similarity index 85%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsConfigTest.php
index e0cfb8f994..c4e8aba8cd 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsConfigTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsConfigTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\NodeType;
@@ -17,7 +17,7 @@ class ParagraphsConfigTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
   );
 
@@ -48,19 +48,21 @@ public function testFieldTranslationDisabled() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][paragraphs_field]' => FALSE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Create a node with a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'paragraphs_field_paragraph_type_test_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'paragraphs_field_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'paragraphed_title'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Attempt to add a translation.
     $node = $this->drupalGetNodeByTitle('paragraphed_title');
     $this->drupalGet('node/' . $node->id() . '/translations');
-    $this->clickLink(t('Add'));
+    $this->clickLink('Add');
     // Save the translation.
-   $this->drupalPostForm(NULL, [], t('Save (this translation)'));
+   $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_test paragraphed_title has been updated.');
   }
 
@@ -95,7 +97,8 @@ public function testContentTranslationForm() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][paragraphs_field]' => FALSE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check error message is still not displayed.
     $this->drupalGet('admin/config/regional/content-language');
@@ -112,7 +115,8 @@ public function testContentTranslationForm() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][paragraphs_field]' => TRUE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check content type field management error.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs_field');
@@ -126,8 +130,8 @@ public function testContentTranslationForm() {
       'label' => 'new_no_paragraphs_field',
       'field_name' => 'new_no_paragraphs_field',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
     $this->assertSession()->pageTextNotContains('Paragraphs fields do not support translation.');
     $this->assertSession()->responseNotContains('<div class="messages messages--warning');
   }
@@ -148,7 +152,7 @@ public function testRequiredParagraphsField() {
     $edit = [
       'required' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
 
     // Assert that the field is displayed in the form as required.
@@ -157,10 +161,10 @@ public function testRequiredParagraphsField() {
     $edit = [
       'title[0][value]' => 'test_title',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphs field is required.');
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm([], 'paragraphs_paragraph_type_test_add_more');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test test_title has been created.');
   }
 
@@ -206,12 +210,12 @@ public function testIncludedParagraphTypes() {
       'settings[handler_settings][negate]' => 0,
       'settings[handler_settings][target_bundles_drag_drop][paragraph_type_test][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->assertSession()->pageTextContains('Add paragraph_type_test');
-    $this->assertSession()->pageTextNotContains('Add text');
+    $this->assertSession()->buttonExists('Add paragraph_type_test');
+    $this->assertSession()->responseNotContains('Add text');
   }
 
   /**
@@ -229,12 +233,12 @@ public function testExcludedParagraphTypes() {
       'settings[handler_settings][negate]' => 1,
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->assertSession()->pageTextContains('Add paragraph_type_test');
-    $this->assertSession()->pageTextNotContains('Add text');
+    $this->assertSession()->buttonExists('Add paragraph_type_test');
+    $this->assertSession()->responseNotContains('Add text');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsContactTest.php
similarity index 83%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsContactTest.php
index cc19084ea2..6d11b75605 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsContactTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsContactTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\contact\Entity\ContactForm;
 
@@ -16,7 +16,7 @@ class ParagraphsContactTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'contact',
   );
 
@@ -40,10 +40,10 @@ public function testContactForm() {
 
     // Add a paragraph to the contact form.
     $this->drupalGet('contact/test_contact_form');
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
+    $this->submitForm([], 'paragraphs_paragraphs_contact_add_more');
     // Check that the paragraph is displayed.
     $this->assertSession()->pageTextContains('paragraphs_contact');
-    $this->drupalPostForm(NULL, [], 'paragraphs_0_remove');
+    $this->submitForm([], 'paragraphs_0_remove');
     $this->assertSession()->pageTextContains('Deleted Paragraph: paragraphs_contact');
   }
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEditModesTest.php
similarity index 76%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEditModesTest.php
index 724a35ea99..e67b0bb9c4 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEditModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEditModesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests paragraphs edit modes.
@@ -14,7 +14,7 @@ class ParagraphsEditModesTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'image',
     'block_field',
   ];
@@ -38,13 +38,14 @@ public function testCollapsedSummary() {
 
     // Set edit mode to closed.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit");
+    $this->submitForm([], "field_paragraphs_settings_edit");
     $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Add a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_image_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_title_add_more');
 
     $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
@@ -56,29 +57,29 @@ public function testCollapsedSummary() {
       'files[field_paragraphs_0_subform_field_image_0]' => $file_system->realpath($files[0]->uri),
       'field_paragraphs[1][subform][field_title][0][value]' => 'Title example',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Assert the summary is correctly generated.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>');
     $this->assertSession()->responseContains('<span class="summary-content">Title example');
 
     // Edit and remove alternative text.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     // Assert the summary is correctly generated.
     $this->assertSession()->responseContains('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>');
 
     // Remove image.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_image_0_remove_button');
+    $this->submitForm([], 'Save');
 
     // Assert the summary is correctly generated.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">text_summary');
 
     // Add a Block Paragraphs type.
@@ -87,13 +88,13 @@ public function testCollapsedSummary() {
 
     // Test the summary of a Block field.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_block_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'Node with a Block Paragraph',
       'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'system_breadcrumb_block',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->clickLink(t('Edit'));
+    $this->submitForm($edit, 'Save');
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">Breadcrumbs');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
similarity index 74%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
index 2a0e2edb5d..fa1b9afce4 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests the translation of heavily nested / specialized setup.
@@ -14,7 +14,7 @@ class ParagraphsEntityTranslationWithNonTranslatableParagraphs extends Paragraph
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'language',
     'content_translation',
   ];
@@ -22,7 +22,7 @@ class ParagraphsEntityTranslationWithNonTranslatableParagraphs extends Paragraph
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     $this->admin_user = $this->drupalCreateUser([], NULL, TRUE);
@@ -32,11 +32,13 @@ protected function setUp() {
     $edit = array(
       'predefined_langcode' => 'de',
     );
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->drupalGet('admin/config/regional/language/add');
+    $this->submitForm($edit, 'Add language');
     $edit = array(
       'predefined_langcode' => 'fr',
     );
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->drupalGet('admin/config/regional/language/add');
+    $this->submitForm($edit, 'Add language');
 
     // Create article content type with a paragraphs field.
     $this->addParagraphedContentType('article', 'field_paragraphs');
@@ -45,7 +47,8 @@ protected function setUp() {
     $edit = array(
       'language_configuration[content_translation]' => TRUE,
     );
-    $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
+    $this->drupalGet('admin/structure/types/manage/article');
+    $this->submitForm($edit, 'Save content type');
     $this->drupalGet('admin/structure/types/manage/article');
 
     // Ensue the paragraphs field itself isn't translatable - this would be a
@@ -53,7 +56,8 @@ protected function setUp() {
     $edit = array(
       'translatable' => FALSE,
     );
-    $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_paragraphs', $edit, t('Save settings'));
+    $this->drupalGet('admin/structure/types/manage/article/fields/node.article.field_paragraphs');
+    $this->submitForm($edit, 'Save settings');
 
     // Add Paragraphs type.
     $this->addParagraphsType('test_paragraph_type');
@@ -79,30 +83,30 @@ public function testParagraphsIEFTranslation() {
     $edit = [
       'title[0][value]' => 'Title English',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Title English');
 
     $edit = array(
       'title[0][value]' => 'Title French',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('article Title French has been updated.');
 
     // Add german translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'));
+    $this->clickLink('Translate');
+    $this->clickLink('Add');
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Title English');
 
     $edit = array(
       'title[0][value]' => 'Title German',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('article Title German has been updated.');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsFieldGroupTest.php
similarity index 74%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsFieldGroupTest.php
index b7e5d30dd4..6107edaa53 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsFieldGroupTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsFieldGroupTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests the field group on node.
@@ -15,7 +15,7 @@ class ParagraphsFieldGroupTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'field_group',
   ];
 
@@ -40,22 +40,25 @@ public function testFieldGroup() {
       'label' => 'paragraph_field_group_title',
       'group_name' => 'field'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display/add-group', $edit, t('Save and continue'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display/add-group');
+    $this->submitForm($edit, 'Save and continue');
     $edit = [
       'format_settings[label]' => 'field_group'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Create group'));
+    $this->submitForm($edit, 'Create group');
 
     // Put the text field into the field group.
     $edit = [
       'fields[group_field][region]' => 'content',
       'fields[field_text][parent]' => 'group_field'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display');
+    $this->submitForm($edit, 'Save');
 
     // Create a node with a paragraph.
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalGet('node/add/' . $content_type);
+    $this->submitForm([], 'field_paragraphs_paragraph_type_test_add_more');
 
     // Test if the new field group is displayed.
     $this->assertSession()->pageTextContains('field_group');
@@ -66,6 +69,6 @@ public function testFieldGroup() {
       'title[0][value]' => 'paragraphed_title',
       'field_paragraphs[0][subform][field_text][0][value]' => 'paragraph_value',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
   }
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsInlineEntityFormTest.php
similarity index 85%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsInlineEntityFormTest.php
index 4f07699de4..3f91a7e52c 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsInlineEntityFormTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsInlineEntityFormTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests the configuration of paragraphs in relation to ief.
@@ -14,7 +14,7 @@ class ParagraphsInlineEntityFormTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'inline_entity_form',
   ];
 
@@ -45,28 +45,28 @@ public function testParagraphsIEFPreview() {
     $edit = [
       'fields[field_article][type]' => 'inline_entity_form_simple',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Set the paragraphs widget mode to preview.
     $this->setParagraphsWidgetMode('article', 'field_paragraphs', 'preview');
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
       'title[0][value]' => 'Dummy1',
       'field_paragraphs[0][subform][field_article][0][inline_entity_form][title][0][value]' => 'Dummy2',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Go back into edit page.
     $node = $this->getNodeByTitle('Dummy1');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Try to open the previewed paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
   }
 
   /**
@@ -98,21 +98,21 @@ public function testParagraphsIEFChangeOrder() {
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save field settings'));
+    $this->submitForm($edit, 'Save field settings');
 
     // Enable IEF simple widget.
     $this->drupalGet('admin/structure/paragraphs_type/simple/form-display');
     $edit = [
       'fields[field_article][type]' => 'inline_entity_form_simple',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Set the paragraphs widget mode to preview.
     $this->setParagraphsWidgetMode('article', 'field_paragraphs', 'preview');
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -120,14 +120,14 @@ public function testParagraphsIEFChangeOrder() {
       'field_paragraphs[0][subform][field_article][0][inline_entity_form][title][0][value]' => 'Basic page 1',
     ];
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Go back into edit page.
     $node = $this->getNodeByTitle('Article 1');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Create second paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values of second paragraph and change the order.
     $edit = [
@@ -135,7 +135,7 @@ public function testParagraphsIEFChangeOrder() {
       'field_paragraphs[0][_weight]' => -1,
       'field_paragraphs[1][_weight]' => -2,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsLegacyContentModerationTranslationsTest.php
similarity index 97%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsLegacyContentModerationTranslationsTest.php
index 0d42db68a7..49faac07f2 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsClassicContentModerationTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsLegacyContentModerationTranslationsTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
@@ -10,7 +10,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsClassicContentModerationTranslationsTest extends ParagraphsTestBase {
+class ParagraphsLegacyContentModerationTranslationsTest extends ParagraphsTestBase {
 
   use ParagraphsLastEntityQueryTrait;
 
@@ -19,7 +19,7 @@ class ParagraphsClassicContentModerationTranslationsTest extends ParagraphsTestB
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -41,13 +41,9 @@ class ParagraphsClassicContentModerationTranslationsTest extends ParagraphsTestB
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs', 'entity_reference_paragraphs');
 
@@ -114,7 +110,7 @@ protected function setUp() {
       'settings[paragraph][text][fields][field_untranslatable]' => FALSE,
       'settings[paragraph][container][fields][field_paragraphs]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsPreviewTest.php
similarity index 87%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsPreviewTest.php
index c147aed92f..3b45028aad 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsPreviewTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsPreviewTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests the configuration of paragraphs.
@@ -14,7 +14,7 @@ class ParagraphsPreviewTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'image',
   );
 
@@ -41,14 +41,14 @@ public function testParagraphsPreview() {
     $test_text_2 = 'dummy_preview_text_2';
     // Create node with two paragraphs.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     // Set the value of the paragraphs.
     $edit = [
       'title[0][value]' => 'Page_title',
       'field_paragraphs[0][subform][field_text][0][value]' => $test_text_1,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     // Check if the text is displayed.
     $this->assertSession()->responseContains($test_text_1);
 
@@ -64,15 +64,15 @@ public function testParagraphsPreview() {
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
     $this->assertEquals($paragraph_1->getValue(), $test_text_1);
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     $edit = [
       'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($test_text_2);
 
@@ -84,7 +84,7 @@ public function testParagraphsPreview() {
       'field_paragraphs[1][subform][field_text][0][value]' => $new_test_text_2,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($new_test_text_2);
 
@@ -100,7 +100,7 @@ public function testParagraphsPreview() {
     $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0];
     $this->assertEquals($paragraph_1->getValue(), $test_text_1);
     $this->assertEquals($paragraph_2->getValue(), $new_test_text_2);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($new_test_text_2);
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsSummaryFormatterTest.php
similarity index 81%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsSummaryFormatterTest.php
index e7709e3550..9bb7c7b307 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsSummaryFormatterTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsSummaryFormatterTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests the paragraphs summary formatter.
@@ -14,7 +14,7 @@ class ParagraphsSummaryFormatterTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'image',
   ];
 
@@ -42,10 +42,11 @@ public function testParagraphsSummaryFormatter() {
     // Set display format to paragraphs summary.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/display');
     $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Add a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_title_add_more');
 
     // Create a node with a text.
     $edit = [
@@ -53,13 +54,13 @@ public function testParagraphsSummaryFormatter() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'text_summary',
       'field_paragraphs[1][subform][field_title][0][value]' => 'Title example',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, [], t('Add user_paragraph'));
+    $this->submitForm($edit, 'Save');
+    $this->clickLink('Edit');
+    $this->submitForm([], 'Add user_paragraph');
     $edit = [
       'field_paragraphs[2][subform][field_user][0][target_id]' => $this->admin_user->label() . ' (' . $this->admin_user->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Assert the summary is correctly generated.
     $this->assertSession()->pageTextContains($this->admin_user->label());
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTestBase.php
similarity index 82%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTestBase.php
index 10c2c6424e..2295be321b 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTestBase.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTestBase.php
@@ -1,12 +1,13 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
+use Drupal\user\Entity\Role;
 
 /**
  * Base class for tests.
@@ -34,7 +35,7 @@ abstract class ParagraphsTestBase extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs',
     'field',
@@ -51,13 +52,9 @@ abstract class ParagraphsTestBase extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     $this->admin_permissions = [
       'administer content types',
@@ -66,6 +63,7 @@ protected function setUp() {
       'administer node form display',
       'administer paragraph fields',
       'administer paragraph form display',
+      'bypass node access',
     ];
   }
 
@@ -133,7 +131,7 @@ protected function setAllowedParagraphsTypes($content_type, $paragraphs_types, $
     foreach ($paragraphs_types as $paragraphs_type) {
       $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][enabled]'] = $selected;
     }
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+    $this->submitForm($edit, 'Save settings');
   }
 
   /**
@@ -151,7 +149,7 @@ protected function setAllowedParagraphsTypes($content_type, $paragraphs_types, $
   protected function setParagraphsTypeWeight($content_type, $paragraphs_type, $weight, $paragraphs_field) {
     $this->drupalGet('admin/structure/types/manage/' . $content_type . '/fields/node.' . $content_type . '.' . $paragraphs_field);
     $edit['settings[handler_settings][target_bundles_drag_drop][' . $paragraphs_type . '][weight]'] = $weight;
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+    $this->submitForm($edit, 'Save settings');
   }
 
   /**
@@ -168,9 +166,9 @@ protected function setParagraphsTypeWeight($content_type, $paragraphs_type, $wei
    */
   protected function setDefaultParagraphType($content_type, $paragraphs_name, $paragraphs_field_name, $default_type) {
     $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display');
-    $this->drupalPostForm(NULL, [], $paragraphs_field_name);
-    $this->drupalPostForm(NULL, ['fields[' . $paragraphs_name . '][settings_edit_form][settings][default_paragraph_type]' => $default_type], t('Update'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], $paragraphs_field_name);
+    $this->submitForm(['fields[' . $paragraphs_name . '][settings_edit_form][settings][default_paragraph_type]' => $default_type], 'Update');
+    $this->submitForm([], 'Save');
   }
 
   /**
@@ -181,8 +179,8 @@ protected function setDefaultParagraphType($content_type, $paragraphs_name, $par
    */
   protected function removeDefaultParagraphType($content_type) {
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostForm(NULL, [], 'Remove');
-    $this->drupalPostForm(NULL, [], 'Confirm removal');
+    $this->submitForm([], 'Remove');
+    $this->submitForm([], 'Confirm removal');
     $this->assertSession()->pageTextNotContains('No paragraphs added yet.');
   }
 
@@ -195,14 +193,14 @@ protected function removeDefaultParagraphType($content_type) {
    *   Paragraphs field to change the mode.
    * @param string $mode
    *   Mode to be set. ('closed', 'preview' or 'open').
-   *   'preview' is only allowed in the classic widget. Use
-   *   setParagraphsWidgetSettings for the experimental widget, instead.
+   *   'preview' is only allowed in the legacy widget. Use
+   *   setParagraphsWidgetSettings for the stable widget, instead.
    */
   protected function setParagraphsWidgetMode($content_type, $paragraphs_field, $mode) {
     $this->drupalGet('admin/structure/types/manage/' . $content_type . '/form-display');
-    $this->drupalPostForm(NULL, [], $paragraphs_field . '_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[' . $paragraphs_field . '][settings_edit_form][settings][edit_mode]' => $mode], t('Update'));
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], $paragraphs_field . '_settings_edit');
+    $this->submitForm(['fields[' . $paragraphs_field . '][settings_edit_form][settings][edit_mode]' => $mode], 'Update');
+    $this->submitForm([], 'Save');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTranslationTest.php
similarity index 84%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTranslationTest.php
index ff7c84bd60..f55ea0c496 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTranslationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTranslationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -22,7 +22,7 @@ class ParagraphsTranslationTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'link',
     'image',
@@ -43,7 +43,7 @@ class ParagraphsTranslationTest extends ParagraphsTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -84,8 +84,9 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
-    // Set the form display to classic.
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
+    // Set the form display to legacy.
     EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', ['type' => 'entity_reference_paragraphs'])
       ->save();
@@ -125,26 +126,26 @@ public function testParagraphTranslation() {
       'fields[status][region]' => 'content',
     );
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $this->assertSession()->responseContains('edit-field-paragraphs-demo-0-subform-status-value');
     $edit = [
       'title[0][value]' => 'example_publish_unpublish',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Example published and unpublished',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains(t('Example published and unpublished'));
-    $this->clickLink(t('Edit'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Example published and unpublished');
+    $this->clickLink('Edit');
 
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'field_paragraphs_demo[0][subform][status][value]' => FALSE,
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text'
     ];
-    $this->drupalPostForm(NULL, $edit + ['status[value]' => FALSE], t('Save'));
-    $this->assertSession()->pageTextNotContains(t('Example published and unpublished'));
+    $this->submitForm($edit + ['status[value]' => FALSE], 'Save');
+    $this->assertSession()->pageTextNotContains('Example published and unpublished');
 
     // Check the parent fields are set properly. Get the node.
     $node = $this->drupalGetNodeByTitle('example_publish_unpublish');
@@ -167,26 +168,26 @@ public function testParagraphTranslation() {
 
     // Add paragraphed content.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $edit = array(
       'title[0][value]' => 'Title in english',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Text in english',
     );
     // The button to remove a paragraph is present.
-    $this->assertSession()->responseContains(t('Remove'));
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->assertSession()->responseContains('Remove');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('Title in english');
     // The text is present when editing again.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in english');
     $this->assertSession()->pageTextContains('Text in english');
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure the Add / Remove paragraph buttons are hidden.
-    $this->assertSession()->responseNotContains(t('Remove'));
-    $this->assertSession()->responseNotContains(t('Add text_image'));
+    $this->assertSession()->responseNotContains('Remove');
+    $this->assertSession()->responseNotContains('Add text_image');
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Text in english');
 
@@ -196,7 +197,7 @@ public function testParagraphTranslation() {
       'revision' => TRUE,
       'revision_log[0][value]' => 'french 1',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in french has been updated.');
 
     // Check the english translation.
@@ -212,7 +213,7 @@ public function testParagraphTranslation() {
     $this->assertSession()->pageTextContains('Text in french');
     $this->assertSession()->pageTextNotContains('Title in english');
     // The translation is still present when editing again.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in french');
     $this->assertSession()->pageTextContains('Text in french');
     $edit = array(
@@ -221,35 +222,35 @@ public function testParagraphTranslation() {
       'revision' => TRUE,
       'revision_log[0][value]' => 'french 2',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title Change in french');
     $this->assertSession()->pageTextContains('New text in french');
 
     // Back to the source language.
     $this->drupalGet('node/' . $node->id());
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in english');
     $this->assertSession()->pageTextContains('Text in english');
     // Save the original content on second request.
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in english has been updated.');
 
     // Test if reverting to old paragraphs revisions works, make sure that
     // the reverted node can be saved again.
     $this->drupalGet('fr/node/' . $node->id() . '/revisions');
-    $this->clickLink(t('Revert'));
-    $this->drupalPostForm(NULL, ['revert_untranslated_fields' => TRUE], t('Revert'));
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Revert');
+    $this->submitForm(['revert_untranslated_fields' => TRUE], 'Revert');
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('Title in french');
     $this->assertSession()->pageTextContains('Text in french');
-    $this->drupalPostForm(NULL, [], t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->responseNotContains('The content has either been modified by another user, or you have already submitted modifications');
     $this->assertSession()->pageTextContains('Text in french');
 
     //Add paragraphed content with untranslatable language
     $this->drupalGet('node/add/paragraphed_content_demo');
     $edit = array('langcode[0][value]' => LanguageInterface::LANGCODE_NOT_SPECIFIED);
-    $this->drupalPostForm(NULL, $edit, t('Add text_image'));
+    $this->submitForm($edit, 'Add text_image');
     $this->assertSession()->statusCodeEquals(200);
 
     // Make 'Images' paragraph field translatable, enable alt and title fields.
@@ -260,41 +261,41 @@ public function testParagraphTranslation() {
       'settings[alt_field]' => 1,
       'settings[title_field]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+    $this->submitForm($edit, 'Save settings');
 
     // Create a node with an image paragraph, its alt and title text.
     $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
     $file_path = $file_system->realpath($file_system->realpath($files[0]->uri));
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add images'));
-    $this->drupalPostForm(NULL, ['files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path], t('Upload'));
+    $this->submitForm([], 'Add images');
+    $this->submitForm(['files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path], 'Upload');
     $edit = [
       'title[0][value]' => 'Title EN',
       'field_paragraphs_demo[0][subform][field_images_demo][0][alt]' => 'Image alt',
       'field_paragraphs_demo[0][subform][field_images_demo][0][title]' => 'Image title',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Translate the node with the image paragraph.
     $this->clickLink('Translate');
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Add', 1);
     $edit = [
       'title[0][value]' => 'Title FR',
       'field_paragraphs_demo[0][subform][field_images_demo][0][alt]' => 'Image alt FR',
       'field_paragraphs_demo[0][subform][field_images_demo][0][title]' => 'Image title FR',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->responseContains('Title FR');
 
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add text'));
+    $this->submitForm([], 'Add text');
     $edit = [
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'texto',
       'title[0][value]' => 'titulo',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('titulo');
     $this->assertParagraphsLangcode($node->id(), 'de');
 
@@ -327,7 +328,7 @@ public function testParagraphTranslation() {
       'field_paragraphs_demo' => [$paragraph_1, $translated_paragraph],
     ]);
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo ' . $node->label() . ' has been updated.');
     // Check that first paragraph langcode has been updated.
     \Drupal::entityTypeManager()->getStorage('paragraph')->resetCache([$paragraph_1->id(), $paragraph_2->id()]);
@@ -345,25 +346,26 @@ public function testParagraphTranslation() {
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'english_translation_1',
       'field_paragraphs_demo[1][subform][field_text_demo][0][value]' => 'english_translation_2',
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/translations/add/de/en', $edit, t('Save (this translation)'));
+    $this->drupalGet('node/' . $node->id() . '/translations/add/de/en');
+    $this->submitForm($edit, 'Save (this translation)');
     // Attempt to create a french translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
     // Check that the german translation of the paragraphs is displayed.
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[0][subform][field_text_demo][0][value]', 'english_text_1');
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[1][subform][field_text_demo][0][value]', 'german_text_2');
-    $this->drupalPostForm(NULL, ['source_langcode[source]' => 'en'], t('Change'));
+    $this->submitForm(['source_langcode[source]' => 'en'], 'Change');
     // Check that the english translation of the paragraphs is displayed.
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[0][subform][field_text_demo][0][value]', 'english_translation_1');
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[1][subform][field_text_demo][0][value]', 'english_translation_2');
 
     // Create a node with empty Paragraphs.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add nested_paragraph'));
+    $this->submitForm([], 'Add nested_paragraph');
     $edit = ['title[0][value]' => 'empty_node'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Attempt to translate it.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'));
+    $this->clickLink('Translate');
+    $this->clickLink('Add');
     // Check the add button is not displayed.
     $this->assertEquals(count($this->xpath('//*[@name="field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more"]')), 0);
 
@@ -373,9 +375,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_field',
       'field_name' => 'untranslatable_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm([], 'Save settings');
 
     // Add a non translatable reference field.
     $edit = [
@@ -383,9 +386,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_ref_field',
       'field_name' => 'untranslatable_ref_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, ['settings[handler_settings][target_bundles][paragraphed_content_demo]' => TRUE], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm(['settings[handler_settings][target_bundles][paragraphed_content_demo]' => TRUE], 'Save settings');
 
     // Add a non translatable link field.
     $edit = [
@@ -393,9 +397,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_link_field',
       'field_name' => 'untranslatable_link_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm([], 'Save settings');
 
     // Attempt to add a translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
@@ -408,8 +413,10 @@ public function testParagraphTranslation() {
     $edit = [
       'translatable' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_ref_field', $edit, t('Save settings'));
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_link_field', $edit, t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_ref_field');
+    $this->submitForm($edit, 'Save settings');
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_link_field');
+    $this->submitForm($edit, 'Save settings');
 
     // Attempt to add a translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
@@ -432,7 +439,7 @@ public function testParagraphTranslationMultilingual() {
 
     // Add 'Images' paragraph and check the paragraphs buttons are displayed.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->submitForm([], 'Add images');
     $this->assertParagraphsButtons(1);
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
@@ -440,24 +447,24 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in english');
     $node = $this->drupalGetNodeByTitle('Title in english');
     // Check the paragraph langcode is 'en'.
     $this->assertParagraphsLangcode($node->id());
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure the host entity and its paragraphs have valid source language
     // and check that the paragraphs buttons are hidden.
     $this->assertNoParagraphsButtons(1);
     $edit = [
       'title[0][value]' => 'Title in french',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertParagraphsLangcode($node->id(), 'en', 'fr');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in french has been updated.');
     $this->assertSession()->pageTextContains('Title in french');
@@ -468,14 +475,14 @@ public function testParagraphTranslationMultilingual() {
     // Edit the french translation and upload a new image.
     $this->clickLink('Edit');
     $images = $this->getTestFiles('image')[1];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'en', 'fr');
     $this->assertNoParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title in french');
     $this->assertSession()->pageTextNotContains('Title in english');
 
@@ -494,23 +501,23 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add nested_paragraph'));
+    $this->submitForm($edit, 'Add nested_paragraph');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Add an 'Images' paragraph inside the nested one, check the paragraphs
     // langcode are still 'en' and the paragraphs buttons are still displayed.
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Upload a new image, check the paragraphs langcode are still 'en' and the
     // paragraphs buttons are displayed.
     $images = $this->getTestFiles('image')[2];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title in english (de)');
     $this->assertSession()->pageTextNotContains('Title in french');
     // Check the original node and the paragraphs langcode are now 'de'.
@@ -530,9 +537,10 @@ public function testParagraphTranslationMultilingual() {
     // node langcode to EN.
 
     // Change the site langcode to french.
-    $this->drupalPostForm('admin/config/regional/language', [
+    $this->drupalGet('admin/config/regional/language');
+    $this->submitForm([
       'site_default_language' => 'fr',
-    ], t('Save configuration'));
+    ], 'Save configuration');
 
     // Check the original node and its paragraphs langcode are still 'de'
     // and the paragraphs buttons are still displayed.
@@ -542,21 +550,21 @@ public function testParagraphTranslationMultilingual() {
 
     // Go to the french translation.
     $this->drupalGet('node/' . $node->id() . '/translations');
-    $this->clickLink(t('Edit'), 1);
+    $this->clickLink('Edit', 1);
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
     // Upload another image.
     $images = $this->getTestFiles('image')[3];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     // Check the paragraphs langcode are still 'de' after saving the translation.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertSession()->pageTextContains('Title in french');
@@ -577,18 +585,18 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id(), 'de');
     $this->assertParagraphsButtons(3);
     // Upload a new image, check the paragraphs langcode are still 'de' and the
     // paragraphs buttons are displayed.
     $images = $this->getTestFiles('image')[4];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node->id(), 'de');
     $this->assertParagraphsButtons(3);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in english has been updated.');
     // Check the original node and the paragraphs langcode are now 'en'.
     $this->assertParagraphsLangcode($node->id());
@@ -616,25 +624,25 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in german',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add nested_paragraph'));
+    $this->submitForm($edit, 'Add nested_paragraph');
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in german');
     $node1 = $this->getNodeByTitle('Title in german');
 
     // Check the paragraph langcode is 'de' and its buttons are displayed.
     // @todo check for the nested children paragraphs buttons and langcode
     // when it's supported.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'english' and upload another image.
@@ -644,16 +652,16 @@ public function testParagraphsMultilingualWorkflow() {
       'langcode[0][value]' => 'en',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     // Check the paragraph langcode is still 'de' and its buttons are shown.
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraph langcode is now 'en' after saving.
     $this->assertParagraphsLangcode($node1->id());
 
     // Check the paragraph langcode is 'en' and its buttons are still shown.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node1->id());
     $this->assertParagraphsButtons(1);
 
@@ -665,27 +673,27 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the node langcode is 'english' and add a 'Nested Paragraph'.
     $langcode_option = $this->assertSession()->optionExists('edit-langcode-0-value', 'en');
     $this->assertTrue($langcode_option->hasAttribute('selected'));
-    $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
+    $this->submitForm([], 'Add nested_paragraph');
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in english');
     $node2 = $this->drupalGetNodeByTitle('Title in english');
 
     // Check the paragraph langcode is 'en' and its buttons are displayed.
     // @todo check for the nested children paragraphs buttons and langcode
     // when it's supported.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'german' and add another 'Images' paragraph.
@@ -693,29 +701,29 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[1];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are now 'de' after saving.
     $this->assertParagraphsLangcode($node2->id(), 'de');
 
     // Change node langcode back to 'english' and save.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $edit = [
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check the paragraphs langcode are now 'en' after saving.
     $this->assertParagraphsLangcode($node2->id());
 
@@ -725,7 +733,8 @@ public function testParagraphsMultilingualWorkflow() {
     $edit = [
       'site_default_language' => 'de',
     ];
-    $this->drupalPostForm('admin/config/regional/language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/language');
+    $this->submitForm( $edit, 'Save configuration');
 
     // Check the original node and the paragraphs langcode are still 'en' and
     // check that the paragraphs buttons are still displayed.
@@ -733,24 +742,24 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Add another 'Images' paragraph with node langcode as 'english'.
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_images_add_more');
     // Check the paragraph langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[2];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are still 'en' after saving.
     $this->assertParagraphsLangcode($node2->id());
 
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Change node langcode to 'german' and add another 'Images' paragraph.
@@ -758,19 +767,19 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[3];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are now 'de' after saving.
     $this->assertParagraphsLangcode($node2->id(), 'de');
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTypesTest.php
similarity index 91%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTypesTest.php
index 71ec3fbef3..4ba56ba618 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsTypesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsTypesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -24,20 +24,20 @@ public function testRemoveTypesWithContent() {
 
     // Attempt to delete the content type not used yet.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Delete'));
+    $this->clickLink('Delete');
     $this->assertSession()->pageTextContains('This action cannot be undone.');
-    $this->clickLink(t('Cancel'));
+    $this->clickLink('Cancel');
 
     // Add a test node with a Paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->submitForm([], 'paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'test_node'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test test_node has been created.');
 
     // Attempt to delete the paragraph type already used.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Delete'));
+    $this->clickLink('Delete');
     $this->assertSession()->pageTextContains('paragraph_type_test Paragraphs type is used by 1 piece of content on your site. You can not remove this paragraph_type_test Paragraphs type until you have removed all from the content.');
 
   }
@@ -68,7 +68,7 @@ public function testParagraphTypeIcon() {
       'id' => 'test_paragraph_type_icon',
       'files[icon_file]' => $fileSystem->realpath($test_files[0]->uri),
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $this->submitForm($edit, 'Save and manage fields');
     $this->assertSession()->pageTextContains('Saved the Test paragraph type Paragraphs type.');
 
     // Check if the icon has been saved.
@@ -90,8 +90,8 @@ public function testParagraphTypeIcon() {
 
     // Delete the icon.
     $this->drupalGet('admin/structure/paragraphs_type/test_paragraph_type_icon');
-    $this->drupalPostForm(NULL, [], 'icon_file_remove_button');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'icon_file_remove_button');
+    $this->submitForm([], 'Save');
 
     // Check that the icon file usage has been deregistered.
     $usages = $file_usage->listUsage($file);
@@ -120,7 +120,7 @@ public function testParagraphTypeDefaultIcon() {
       'id' => 'test_paragraph_type_icon',
       'files[icon_file]' => $fileSystem->realpath($test_files[0]->uri),
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $this->submitForm($edit, 'Save and manage fields');
     $this->assertSession()->pageTextContains('Saved the Test paragraph type Paragraphs type.');
 
     // Check if the icon is created from defaults if not exists.
@@ -155,7 +155,7 @@ public function testParagraphTypeDescription() {
       'id' => 'test_paragraph_type_description',
       'description' => $description_markup,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and manage fields'));
+    $this->submitForm($edit, 'Save and manage fields');
     $this->assertSession()->pageTextContains("Saved the $label Paragraphs type.");
 
     // Check if the description has been saved.
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsUiTest.php
similarity index 87%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsUiTest.php
index dfe62893aa..822390292e 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsUiTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 
@@ -16,7 +16,7 @@ class ParagraphsUiTest extends ParagraphsTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'content_translation',
     'image',
     'field',
@@ -29,7 +29,7 @@ class ParagraphsUiTest extends ParagraphsTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -64,7 +64,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
@@ -93,22 +94,23 @@ public function testEmptyRequiredField() {
     $form_display_edit = [
       'fields[field_content][type]' => 'entity_reference_paragraphs',
     ];
-    $this->drupalPostForm($bundle_path . '/form-display', $form_display_edit, t('Save'));
+    $this->drupalGet($bundle_path . '/form-display');
+    $this->submitForm($form_display_edit, 'Save');
 
     // Attempt to create a paragraphed node with an empty required field.
     $title = 'Empty';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->submitForm(['title[0][value]' => $title], 'Save');
     $this->assertSession()->pageTextContains($field_title . ' field is required');
 
     // Attempt to create a paragraphed node with only a paragraph in the
     // "remove" mode in the required field.
     $title = 'Remove mode';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostForm(NULL, [], 'field_content_0_remove');
+    $this->submitForm([], 'field_content_text_image_add_more');
+    $this->submitForm([], 'field_content_0_remove');
     $this->assertSession()->pageTextNotContains($field_title . ' field is required');
-    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->submitForm(['title[0][value]' => $title], 'Save');
     $this->assertSession()->pageTextContains($field_title . ' field is required');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsWidgetButtonsTest.php
similarity index 78%
rename from web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsWidgetButtonsTest.php
index 220af02df0..28f05ae1d8 100644
--- a/web/modules/paragraphs/tests/src/Functional/Classic/ParagraphsWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetLegacy/ParagraphsWidgetButtonsTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Classic;
+namespace Drupal\Tests\paragraphs\Functional\WidgetLegacy;
 
 /**
  * Tests paragraphs widget buttons.
@@ -23,7 +23,8 @@ public function testWidgetButtons() {
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -31,35 +32,35 @@ public function testWidgetButtons() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     // Test the 'Open' mode.
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains($text);
 
     // Test the 'Closed' mode.
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_1_edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $text);
     $closed_mode_text = 'closed_mode_text';
     // Click "Collapse" button on both paragraphs.
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse');
+    $this->submitForm($edit, 'field_paragraphs_1_collapse');
     // Verify that we have warning message for each paragraph.
     $page_text = $this->getSession()->getPage()->getText();
     $nr_found = substr_count($page_text, 'You have unsaved changes on this Paragraph item.');
     $this->assertGreaterThan(1, $nr_found);
     $this->assertSession()->responseContains('<span class="summary-content">' . $closed_mode_text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextContains($closed_mode_text);
 
@@ -67,15 +68,15 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'preview');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text);
     $preview_mode_text = 'preview_mode_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text];
     // Click "Collapse" button.
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     $this->assertSession()->pageTextContains('You have unsaved changes on this Paragraph item.');
     $this->assertSession()->pageTextContains($preview_mode_text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextContains($preview_mode_text);
 
@@ -83,14 +84,14 @@ public function testWidgetButtons() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->pageTextContains($preview_mode_text);
     // Click "Remove" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'field_paragraphs_0_remove');
     $this->assertSession()->pageTextContains('Deleted Paragraph: text_paragraph');
     // Click "Restore" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_restore');
+    $this->submitForm([], 'field_paragraphs_0_restore');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $preview_mode_text);
     $restore_text = 'restore_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $restore_text];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextContains($restore_text);
 
@@ -98,11 +99,11 @@ public function testWidgetButtons() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->pageTextContains($restore_text);
     // Click "Remove" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'field_paragraphs_0_remove');
     $this->assertSession()->pageTextContains('Deleted Paragraph: text_paragraph');
     // Click "Confirm Removal" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_confirm_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_confirm_remove');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextNotContains($restore_text);
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAccessTest.php
similarity index 83%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAccessTest.php
index afd218c053..422d7ec8cb 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAccessTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\filter\Entity\FilterFormat;
@@ -15,7 +15,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAccessTest extends ParagraphsExperimentalTestBase {
+class ParagraphsAccessTest extends ParagraphsTestBase {
 
   use FieldUiTestTrait;
 
@@ -24,7 +24,7 @@ class ParagraphsExperimentalAccessTest extends ParagraphsExperimentalTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'image',
     'field',
@@ -37,7 +37,7 @@ class ParagraphsExperimentalAccessTest extends ParagraphsExperimentalTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -72,7 +72,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     $view_display = \Drupal::service('entity_display.repository')->getViewDisplay('paragraph', 'images');
     $view_display->setComponent('field_images_demo', ['settings' => ['image_style' => 'medium']]);
@@ -105,9 +106,10 @@ public function testParagraphAccessCheck() {
     $edit = array(
       'settings[uri_scheme]' => 'private',
     );
-    $this->drupalPostForm('admin/structure/paragraphs_type/images/fields/paragraph.images.field_images_demo/storage', $edit, t('Save field settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/images/fields/paragraph.images.field_images_demo/storage');
+    $this->submitForm($edit, 'Save field settings');
 
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', ['type' => 'paragraphs']);
     $form_display->save();
@@ -115,7 +117,7 @@ public function testParagraphAccessCheck() {
     $this->drupalGet('node/add/paragraphed_content_demo');
 
     // Add a new Paragraphs images item.
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->submitForm([], 'Add images');
 
     $images = $this->getTestFiles('image');
 
@@ -135,27 +137,27 @@ public function testParagraphAccessCheck() {
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path,
     );
 
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
 
     $edit = array(
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $file_path_2,
     );
 
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
-    $this->drupalPostForm(NULL,  [], t('Preview'));
+    $this->submitForm($edit, 'Upload');
+    $this->submitForm([], 'Preview');
     $image_style = ImageStyle::load('medium');
     $img1_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage.jpg');
-    $image_url = file_url_transform_relative($img1_url);
-    $this->assertSession()->responseContains($image_url, 'Image was found in preview');
-    $this->clickLink(t('Back to content editing'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $image_url = \Drupal::service('file_url_generator')->transformRelative($img1_url);
+    $this->assertSession()->responseContains($image_url);
+    $this->clickLink('Back to content editing');
+    $this->submitForm([], 'Save');
 
     $node = $this->drupalGetNodeByTitle('Security test node');
 
     $this->drupalGet('node/' . $node->id());
 
     // Check the text and image after publish.
-    $this->assertSession()->responseContains($image_url, 'Image was found in content');
+    $this->assertSession()->responseContains($image_url);
 
     $this->drupalGet($img1_url);
     $this->assertSession()->statusCodeEquals(200);
@@ -166,9 +168,9 @@ public function testParagraphAccessCheck() {
     // @todo Requesting the same $img_url again triggers a caching problem on
     // drupal.org test bot, thus we request a different file here.
     $img_url = $image_style->buildUrl('private://' . date('Y-m') . '/privateImage2.jpg');
-    $image_url = file_url_transform_relative($img_url);
+    $image_url = \Drupal::service('file_url_generator')->transformRelative($img_url);
     // Check the text and image after publish. Anonymous should not see content.
-    $this->assertSession()->responseNotContains($image_url, 'Image was not found in content');
+    $this->assertSession()->responseNotContains($image_url);
 
     $this->drupalGet($img_url);
     $this->assertSession()->statusCodeEquals(403);
@@ -177,20 +179,20 @@ public function testParagraphAccessCheck() {
     $this->loginAsAdmin($permissions);
     // Create a new demo node.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->pageTextContains('Text');
     $edit = [
       'title[0][value]' => 'delete_permissions',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Edit the node.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     // Check the remove button is present.
     $this->assertNotNull($this->xpath('//*[@name="field_paragraphs_demo_0_remove"]'));
     // Delete the Paragraph and save.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_demo_0_remove');
+    $this->submitForm([], 'Save');
     $node = $this->getNodeByTitle('delete_permissions');
     $this->assertSession()->addressEquals('node/' . $node->id());
 
@@ -207,16 +209,17 @@ public function testParagraphAccessCheck() {
       'fields[status][region]' => 'content',
       'fields[status][type]' => 'boolean_checkbox'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/form-display', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/text/form-display');
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->pageTextContains('Text');
     $edit = [
       'title[0][value]' => 'unpublished_permissions',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'recognizable_test',
       'field_paragraphs_demo[0][subform][status][value]' => FALSE
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('recognizable_test');
     $this->assertSession()->responseContains('paragraph--unpublished');
     $this->drupalLogout();
@@ -242,14 +245,16 @@ public function testParagraphAccessCheck() {
     // Grant to the user the administer Paragraphs settings permission.
     $this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), ['administer paragraphs settings']);
     // Disable the show unpublished Paragraphs setting.
-    $this->drupalPostForm('admin/config/content/paragraphs', ['show_unpublished' => FALSE], 'Save configuration');
+    $this->drupalGet('admin/config/content/paragraphs');
+    $this->submitForm(['show_unpublished' => FALSE], 'Save configuration');
     // Assert that the Paragraph is not displayed even if the user has the
     // permission to do so.
     $this->drupalGet('node/' . $node->id());
     $this->assertSession()->pageTextNotContains('recognizable_test');
     $this->assertSession()->responseNotContains('paragraph--unpublished');
     // Enable the show unpublished Paragraphs setting.
-    $this->drupalPostForm('admin/config/content/paragraphs', ['show_unpublished' => TRUE], 'Save configuration');
+    $this->drupalGet('admin/config/content/paragraphs');
+    $this->submitForm(['show_unpublished' => TRUE], 'Save configuration');
     // Assert that the Paragraph is displayed when the user has the permission
     // to do so.
     $this->drupalGet('node/' . $node->id());
@@ -274,13 +279,13 @@ public function testParagraphsTextFormatValidation() {
     $this->loginAsAdmin($permissions);
     // Create a node with a Text Paragraph using the filtered html format.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->pageTextContains('Text');
     $edit = [
       'title[0][value]' => 'access_validation_test',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo access_validation_test has been created.');
     $this->drupalLogout();
     // Login as an user without the Text Format permission.
@@ -291,11 +296,11 @@ public function testParagraphsTextFormatValidation() {
     $this->drupalLogin($user);
     $node = $this->getNodeByTitle('access_validation_test');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo access_validation_test has been updated.');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_demo_0_collapse');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_demo_0_collapse');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo access_validation_test has been updated.');
     $this->assertSession()->pageTextNotContains('The value you selected is not a valid choice.');
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAddModesTest.php
similarity index 94%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAddModesTest.php
index baa1cdcd8c..4ee2055e7f 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAddModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAddModesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\paragraphs\Entity\ParagraphsType;
 
@@ -9,7 +9,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAddModesTest extends ParagraphsExperimentalTestBase {
+class ParagraphsAddModesTest extends ParagraphsTestBase {
 
   /**
    * Tests that paragraphs field does not allow default values.
@@ -19,11 +19,11 @@ public function testNoDefaultValue() {
     $this->addParagraphedContentType('paragraphed_test');
     // Edit the field.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields');
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
 
     // Check that the current field does not allow to add default values.
     $this->assertSession()->pageTextContains('No widget available for: field_paragraphs.');
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->submitForm([], 'Save settings');
     $this->assertSession()->pageTextContains('Saved field_paragraphs configuration.');
     $this->assertSession()->statusCodeEquals(200);
   }
@@ -37,8 +37,8 @@ public function testEmptyAllowedTypes() {
 
     // Edit the field and save when there are no Paragraphs types available.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields');
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->clickLink('Edit');
+    $this->submitForm([], 'Save settings');
     $this->assertSession()->pageTextContains('Saved field_paragraphs configuration.');
   }
 
@@ -54,7 +54,7 @@ public function testDropDownMode() {
     $this->addParagraphedContentType('paragraphed_test', 'paragraphs');
     // Enter to the field config since the weight is set through the form.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs');
-    $this->drupalPostForm(NULL, [], 'Save settings');
+    $this->submitForm([], 'Save settings');
 
     $this->setAddMode('paragraphed_test', 'paragraphs', 'dropdown');
 
@@ -88,7 +88,7 @@ public function testSelectMode() {
     $this->addParagraphedContentType('paragraphed_test', 'paragraphs');
     // Enter to the field config since the weight is set through the form.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.paragraphs');
-    $this->drupalPostForm(NULL, [], 'Save settings');
+    $this->submitForm([], 'Save settings');
 
     $this->setAddMode('paragraphed_test', 'paragraphs', 'select');
 
@@ -118,7 +118,7 @@ public function testSelectMode() {
    */
   protected function assertAddButtons($options) {
     $this->drupalGet('node/add/paragraphed_test');
-    $buttons = $this->xpath('//input[@class="field-add-more-submit button js-form-submit form-submit"]');
+    $buttons = $this->xpath('//input[@class="field-add-more-submit button--small button js-form-submit form-submit"]');
     // Check if the buttons are in the same order as the given array.
     foreach ($buttons as $key => $button) {
       $this->assertEquals($button->getValue(), $options[$key]);
@@ -189,7 +189,7 @@ public function testSettingDefaultParagraphType() {
     $this->setDefaultParagraphType('paragraphed_test', 'paragraphs', 'paragraphs_settings_edit', 'text_image');
     $this->removeDefaultParagraphType('paragraphed_test');
     $edit = ['title[0][value]' => 'New Host'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/1/edit');
     $elements = $this->xpath('//table[@id="paragraphs-values"]/tbody');
     $header = $this->xpath('//table[@id="paragraphs-values"]/thead');
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAdministrationTest.php
similarity index 74%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAdministrationTest.php
index 7d3bf6d61f..e32de40e9e 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAdministrationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAdministrationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\paragraphs\Entity\Paragraph;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
@@ -10,7 +10,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTestBase {
+class ParagraphsAdministrationTest extends ParagraphsTestBase {
 
   use ParagraphsTestBaseTrait;
 
@@ -19,7 +19,7 @@ class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTes
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'image',
     'file',
     'views'
@@ -28,7 +28,7 @@ class ParagraphsExperimentalAdministrationTest extends ParagraphsExperimentalTes
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs content type.
     $this->drupalCreateContentType(array('type' => 'paragraphs', 'name' => 'Paragraphs'));
@@ -61,19 +61,19 @@ public function testParagraphsRevisions() {
     ));
     // Configure article fields.
     $this->drupalGet('admin/structure/types/manage/paragraphs/fields');
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'paragraphs'), t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm(array('fields[field_paragraphs][type]' => 'paragraphs'), 'Save');
 
     // Create node with our paragraphs.
     $this->drupalGet('node/add/paragraphs');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     $edit = [
       'title[0][value]' => 'TEST TITEL',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Test text 1',
       'field_paragraphs[1][subform][field_text][0][value]' => 'Test text 2',
     ];
-    $this->drupalPostForm(NULL, $edit + ['status[value]' => TRUE], t('Save'));
+    $this->submitForm($edit + ['status[value]' => TRUE], 'Save');
 
     $node = $this->drupalGetNodeByTitle('TEST TITEL');
     $paragraph1 = $node->field_paragraphs[0]->target_id;
@@ -87,7 +87,8 @@ public function testParagraphsRevisions() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Foo Bar 1',
       'revision' => FALSE,
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm($edit, 'Save');
 
     $this->countRevisions($node, $paragraph1, $paragraph2, 1);
 
@@ -98,7 +99,8 @@ public function testParagraphsRevisions() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'Foo Bar 2',
       'revision' => TRUE,
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm($edit, 'Save');
 
     $this->countRevisions($node, $paragraph1, $paragraph2, 2);
 
@@ -114,8 +116,8 @@ public function testParagraphsRevisions() {
     // Make sure two revisions available.
     $this->assertEquals(count($rows), 2);
     // Revert to the old version.
-    $this->clickLink(t('Revert'));
-    $this->drupalPostForm(NULL, [], t('Revert'));
+    $this->clickLink('Revert');
+    $this->submitForm([], 'Revert');
     $this->drupalGet('node/' . $node->id());
     // Assert the node has been reverted.
     $this->assertSession()->pageTextNotContains('Foo Bar 2');
@@ -151,14 +153,14 @@ public function testParagraphsCreation() {
       'label' => 'Paragraph',
       'field_name' => 'paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save and continue');
-    $this->drupalPostForm(NULL, [], 'Save field settings');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
     $this->assertSession()->linkByHrefExists('admin/structure/paragraphs_type/add');
     $this->clickLink('here');
     $this->assertSession()->addressEquals('admin/structure/paragraphs_type/add');
 
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Add paragraph type'));
+    $this->clickLink('Add paragraph type');
     $this->assertSession()->titleEquals('Add Paragraphs type | Drupal');
     // Create paragraph type text + image.
     $this->addParagraphsType('text_image');
@@ -179,10 +181,10 @@ public function testParagraphsCreation() {
     ), array());
 
     // Change the add more button to select mode.
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], t('Update'));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm(['fields[field_paragraphs][type]' => 'paragraphs'], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'select'], 'Update');
+    $this->submitForm([], 'Save');
 
     // Create paragraph type image.
     $this->addParagraphsType('image');
@@ -197,7 +199,7 @@ public function testParagraphsCreation() {
     $this->assertSession()->pageTextContains('text_image');
     $this->assertSession()->pageTextContains('image');
     // Make sure there is an edit link for each type.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     // Make sure the field UI appears.
     $this->assertSession()->linkExists('Manage fields');
     $this->assertSession()->linkExists('Manage form display');
@@ -209,25 +211,25 @@ public function testParagraphsCreation() {
     $field_name = 'field_paragraphs';
 
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit");
+    $this->submitForm(['fields[field_paragraphs][type]' => 'paragraphs'], $field_name . "_settings_edit");
 
     // Enable setting.
     $edit = array('fields[' . $field_name . '][settings_edit_form][settings][add_mode]' => 'button');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check if the setting is stored.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->assertSession()->pageTextContains('Add mode: Buttons', 'Checking the settings value.');
+    $this->assertSession()->pageTextContains('Add mode: Buttons');
 
-    $this->drupalPostForm(NULL, array(), $field_name . "_settings_edit");
+    $this->submitForm(array(), $field_name . "_settings_edit");
     // Assert the 'Buttons' option is selected.
     $add_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-add-mode', 'button');
     $this->assertTrue($add_mode_option->hasAttribute('selected'), 'Updated value is correct!.');
 
     // Add two Text + Image paragraphs in article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_image_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_image_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_image_add_more');
 
     // Upload some images.
     $files = $this->getTestFiles('image');
@@ -240,34 +242,32 @@ public function testParagraphsCreation() {
       'field_paragraphs[1][subform][field_text][0][value]' => 'Test text 2',
       'files[field_paragraphs_1_subform_field_image_0]' => $file_system->realpath($files[1]->uri),
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('article Test article has been created.');
 
     $node = $this->drupalGetNodeByTitle('Test article');
-    $img1_url = file_create_url(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[0]->filename));
-    $img2_url = file_create_url(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[1]->filename));
-    $img1_size = filesize($files[0]->uri);
-    $img2_size = filesize($files[1]->uri);
-    $img1_mime = \Drupal::service('file.mime_type.guesser')->guess($files[0]->uri);
-    $img2_mime = \Drupal::service('file.mime_type.guesser')->guess($files[1]->uri);
+    $img1_url = \Drupal::service('file_url_generator')->generateString(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[0]->filename));
+    $img2_url = \Drupal::service('file_url_generator')->generateString(\Drupal::token()->replace('public://[date:custom:Y]-[date:custom:m]/' . $files[1]->filename));
+    $img1_mime = \Drupal::service('file.mime_type.guesser')->guessMimeType($files[0]->uri);
+    $img2_mime = \Drupal::service('file.mime_type.guesser')->guessMimeType($files[1]->uri);
 
     // Check the text and image after publish.
     $this->assertSession()->pageTextContains('Test text 1');
-    $this->assertSession()->responseContains('<img src="' . file_url_transform_relative($img1_url));
+    $this->assertSession()->elementExists('css', 'img[src="' . $img1_url . '"]');
     $this->assertSession()->pageTextContains('Test text 2');
-    $this->assertSession()->responseContains('<img src="' . file_url_transform_relative($img2_url));
+    $this->assertSession()->elementExists('css', 'img[src="' . $img2_url . '"]');
 
     // Tests for "Edit mode" settings.
     // Test for closed setting.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
     // Click on the widget settings button to open the widget settings form.
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Enable setting.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check if the setting is stored.
-    $this->assertSession()->pageTextContains('Edit mode: Closed', 'Checking the settings value.');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->assertSession()->pageTextContains('Edit mode: Closed');
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Assert the 'Closed' option is selected.
     $edit_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed');
     $this->assertTrue($edit_mode_option->hasAttribute('selected'), 'Updated value correctly.');
@@ -280,14 +280,14 @@ public function testParagraphsCreation() {
 
     // Test for preview option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     $edit = [
       'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
       'fields[field_paragraphs][settings_edit_form][settings][closed_mode]' => 'preview',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains('Edit mode: Closed', 'Checking the "Edit mode" setting value.');
-    $this->assertSession()->pageTextContains('Closed mode: Preview', 'Checking the "Closed mode" settings value.');
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Edit mode: Closed');
+    $this->assertSession()->pageTextContains('Closed mode: Preview');
     $this->drupalGet('node/1/edit');
     // The texts in the paragraphs should be visible.
     $this->assertSession()->responseNotContains('field_paragraphs[0][subform][field_text][0][value]');
@@ -297,7 +297,7 @@ public function testParagraphsCreation() {
 
     // Test for open option.
     $this->drupalGet('admin/structure/types/manage/article/form-display');
-    $this->drupalPostForm(NULL, array(), "field_paragraphs_settings_edit");
+    $this->submitForm(array(), "field_paragraphs_settings_edit");
     // Assert the "Closed" and "Preview" options are selected.
     $edit_mode_option = $this->assertSession()->optionExists('edit-fields-field-paragraphs-settings-edit-form-settings-edit-mode', 'closed');
     $this->assertTrue($edit_mode_option->hasAttribute('selected'), 'Correctly updated the "Edit mode" value.');
@@ -305,7 +305,7 @@ public function testParagraphsCreation() {
     $this->assertTrue($closed_mode_option->hasAttribute('selected'),'Correctly updated the "Closed mode" value.');
     // Restore the value to Open for next test.
     $edit = array('fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'open');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/1/edit');
     // The textareas for paragraphs should be visible.
     $this->assertSession()->responseContains('field_paragraphs[0][subform][field_text][0][value]');
@@ -318,30 +318,30 @@ public function testParagraphsCreation() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check both paragraphs in edit page.
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', 'Test text 1');
-    $this->assertSession()->responseContains('<a href="' . $img1_url . '" type="' . $img1_mime . '; length=' . $img1_size . '">' . $files[0]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img1_url . '"][type^="' . $img1_mime . '"]', $files[0]->filename);
     $this->assertSession()->fieldValueEquals('field_paragraphs[1][subform][field_text][0][value]', 'Test text 2');
-    $this->assertSession()->responseContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]', $files[1]->filename);
     // Remove 2nd paragraph.
     $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
     $this->assertSession()->fieldNotExists('field_paragraphs[1][subform][field_text][0][value]');
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
     // Assert the paragraph is not deleted unless the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertSession()->responseContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementTextContains('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]', $files[1]->filename);
     // Remove the second paragraph.
     $this->getSession()->getPage()->find('css', '[name="field_paragraphs_1_remove"]')->press();
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'test_alt',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Assert the paragraph is deleted after the user saves the node.
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertSession()->responseNotContains('<a href="' . $img2_url . '" type="' . $img2_mime . '; length=' . $img2_size . '">' . $files[1]->filename . '</a>');
+    $this->assertSession()->elementNotExists('css', 'A[href="' . $img2_url . '"][type^="' . $img2_mime . '"]');
 
     // Delete the node.
-    $this->clickLink(t('Delete'));
-    $this->drupalPostForm(NULL, NULL, t('Delete'));
+    $this->clickLink('Delete');
+    $this->submitForm([], 'Delete');
     $this->assertSession()->pageTextContains('Test article has been deleted.');
 
     // Check if the publish/unpublish option works.
@@ -351,34 +351,34 @@ public function testParagraphsCreation() {
       'fields[status][region]' => 'content',
     ];
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $this->assertSession()->responseContains('edit-field-paragraphs-0-subform-status-value');
     $edit = [
       'title[0][value]' => 'Example publish/unpublish',
       'field_paragraphs[0][subform][field_text][0][value]' => 'Example published and unpublished',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains(t('Example published and unpublished'));
-    $this->clickLink(t('Edit'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Example published and unpublished');
+    $this->clickLink('Edit');
     $edit = [
       'field_paragraphs[0][subform][status][value]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextNotContains(t('Example published and unpublished'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextNotContains('Example published and unpublished');
 
     // Set the fields as required.
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->clickLink('Edit', 1);
-    $this->drupalPostForm(NULL, ['preview_mode' => '1'], t('Save content type'));
+    $this->submitForm(['preview_mode' => '1'], 'Save content type');
     $this->drupalGet('admin/structure/paragraphs_type/nested_test/fields');
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, ['required' => TRUE], t('Save settings'));
+    $this->submitForm(['required' => TRUE], 'Save settings');
 
     // Add a new article.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_test_add_more');
+    $this->submitForm([], 'field_paragraphs_nested_test_add_more');
 
     // Ensure that nested header actions do not add a visible weight field.
     $this->assertSession()->fieldNotExists('field_paragraphs[0][subform][field_paragraphs][header_actions][_weight]');
@@ -386,7 +386,7 @@ public function testParagraphsCreation() {
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'image',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->submitForm($edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
     // Test the new field is displayed.
     $this->assertSession()->fieldExists('files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]');
 
@@ -395,11 +395,11 @@ public function testParagraphsCreation() {
       'title[0][value]' => 'test required',
       'files[field_paragraphs_0_subform_field_paragraphs_0_subform_field_image_only_0]' => $file_system->realpath($files[2]->uri),
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][0][subform][field_image_only][0][alt]' => 'Alternative_text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('test required has been created.');
     $this->assertSession()->responseNotContains('This value should not be null.');
 
@@ -417,38 +417,39 @@ public function testParagraphsCreation() {
       'label' => 'unsupported field',
       'field_name' => 'unsupportedfield',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
+    $this->submitForm($edit, 'Save and continue');
     $this->assertSession()->optionNotExists('edit-settings-target-type', 'paragraph');
 
     // Test that all Paragraph types can be referenced if none is selected.
     $this->addParagraphsType('nested_double_test');
     static::fieldUIAddExistingField('admin/structure/paragraphs_type/nested_double_test', 'field_paragraphs', 'paragraphs_1');
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, [], 'Save');
-    //$this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'entity_reference_revisions_entity_view'), t('Save'));
+    $this->clickLink('Manage form display');
+    $this->submitForm([], 'Save');
+    //$this->drupalPostForm(NULL, array('fields[field_paragraphs][type]' => 'entity_reference_revisions_entity_view'), 'Save');
     static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_double_test', 'paragraphs_2', 'paragraphs_2', 'entity_reference_revisions', array(
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ), array());
-    $this->clickLink(t('Manage form display'));
-    $this->drupalPostForm(NULL, [], 'Save');
-    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_nested_test_add_more');
+    $this->clickLink('Manage form display');
+    $this->submitForm([], 'Save');
+    $this->drupalGet('node/add/article');
+    $this->submitForm([], 'field_paragraphs_nested_test_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_paragraphs][add_more][add_more_select]' => 'nested_double_test',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
+    $this->submitForm($edit, 'field_paragraphs_0_subform_field_paragraphs_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_paragraphs_0_subform_field_paragraphs_image_add_more');
     $edit = array(
       'title[0][value]' => 'Nested twins',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Nested twins has been created.');
     $this->assertSession()->pageTextNotContains('This entity (paragraph: ) cannot be referenced.');
 
     // Set the fields as not required.
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->clickLink('Edit', 1);
-    $this->drupalPostForm(NULL, ['required' => FALSE], t('Save settings'));
+    $this->submitForm(['required' => FALSE], 'Save settings');
 
     // Set the Paragraph field edit mode to "Closed" and the closed mode to
     // "Summary".
@@ -471,42 +472,43 @@ public function testParagraphsCreation() {
     $node = $this->drupalGetNodeByTitle('Nested twins');
 
     // Create a node with a reference in a Paragraph.
-    $this->drupalPostForm('node/add/article', [], 'field_paragraphs_node_test_add_more');
+    $this->drupalGet('node/add/article');
+    $this->submitForm([], 'field_paragraphs_node_test_add_more');
     \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
     $edit = [
       'field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')',
       'title[0][value]' => 'choke test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Delete the referenced node.
     $node->delete();
     // Edit the node with the reference.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
 
     // Adding another required paragraph and deleting that again should not
     // validate closed paragraphs but trying to save the node should.
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_node_test_add_more');
+    $this->submitForm(array(), 'field_paragraphs_node_test_add_more');
     $this->assertSession()->pageTextNotContains('The referenced entity (node: ' . $node->id() . ') does not exist.');
     $this->assertSession()->fieldExists('field_paragraphs[1][subform][field_entity_reference][0][target_id]');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_1_remove');
+    $this->submitForm(array(), 'field_paragraphs_1_remove');
     $this->assertSession()->pageTextNotContains('The referenced entity (node: ' . $node->id() . ') does not exist.');
     $this->assertSession()->fieldNotExists('field_paragraphs[1][subform][field_entity_reference][0][target_id]');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Validation error on collapsed paragraph field_entity_reference.0.target_id: The referenced entity (node: ' . $node->id() . ') does not exist.');
 
     // Attempt to edit the Paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     // Try to collapse with an invalid reference.
-    $this->drupalPostForm(NULL, ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
+    $this->submitForm(['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'], 'field_paragraphs_0_collapse');
     // Paragraph should be still in edit mode.
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_entity_reference][0][target_id]');
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_entity_reference][1][target_id]');
     // Assert the validation message.
-    $this->assertSession()->pageTextContains('There are no entities matching "foo".');
+    $this->assertSession()->pageTextMatches('/There are no (entities|content items) matching "foo"./');
     // Fix the broken reference.
     $node = $this->drupalGetNodeByTitle('Example publish/unpublish');
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('choke test has been updated.');
     $this->assertSession()->linkExists('Example publish/unpublish');
     // Delete the new referenced node.
@@ -523,19 +525,19 @@ public function testParagraphsCreation() {
     // Attempt to edit the Paragraph.
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Attempt to edit the Paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     // Try to save with an invalid reference.
     $edit = ['field_paragraphs[0][subform][field_entity_reference][0][target_id]' => 'foo'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains('There are no entities matching "foo".');
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextMatches('/There are no (entities|content items) matching "foo"./');
     // Remove the Paragraph and save the node.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('choke test has been updated.');
 
     $this->drupalGet('admin/structure/types/manage/article/fields');
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, ['description' => 'This is the description of the field.'], 'Save settings');
+    $this->submitForm(['description' => 'This is the description of the field.'], 'Save settings');
     // Verify that the text displayed is correct when no paragraph has been
     // added yet.
     $this->drupalGet('node/add/article');
@@ -555,10 +557,27 @@ public function testParagraphsCreation() {
    * Helper function for revision counting.
    */
   private function countRevisions($node, $paragraph1, $paragraph2, $revisions_count) {
-    $node_revisions_count = \Drupal::entityQuery('node')->condition('nid', $node->id())->allRevisions()->count()->execute();
-    $this->assertEquals($node_revisions_count, $revisions_count);
-    $this->assertEquals(\Drupal::entityQuery('paragraph')->condition('id', $paragraph1)->allRevisions()->count()->execute(), $revisions_count);
-    $this->assertEquals(\Drupal::entityQuery('paragraph')->condition('id', $paragraph2)->allRevisions()->count()->execute(), $revisions_count);
+    $node_revisions_count = \Drupal::entityQuery('node')
+      ->condition('nid', $node->id())
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $node_revisions_count);
+    $paragraph1_revisions_count = \Drupal::entityQuery('paragraph')
+      ->condition('id', $paragraph1)
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $paragraph1_revisions_count);
+    $paragraph2_revisions_count =\Drupal::entityQuery('paragraph')
+      ->condition('id', $paragraph2)
+      ->accessCheck(TRUE)
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals($revisions_count, $paragraph2_revisions_count);
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAlterByTypeTest.php
similarity index 81%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAlterByTypeTest.php
index ad78b8cc33..21bc4a3e97 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalAlterByTypeTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsAlterByTypeTest.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
- * Tests paragraphs experimental alter widget by type.
+ * Tests paragraphs stable alter widget by type.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAlterByTypeTest extends ParagraphsExperimentalTestBase {
+class ParagraphsAlterByTypeTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs_test',
   ];
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsBehaviorsTest.php
similarity index 83%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsBehaviorsTest.php
index c320af2fc6..4bdf79ecd5 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalBehaviorsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsBehaviorsTest.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests paragraphs behavior plugins.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalBehaviorsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsBehaviorsTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = ['image', 'file', 'views'];
+  protected static $modules = ['image', 'file', 'views'];
 
   /**
    * Tests the behavior plugins for paragraphs.
@@ -34,14 +34,14 @@ public function testBehaviorPluginsFields() {
     $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
     $this->assertSession()->fieldValueEquals('behavior_plugins[test_text_color][settings][default_color]', 'blue');
 
-    $this->assertSession()->pageTextContains('Behavior plugins are only supported by the EXPERIMENTAL paragraphs widget');
+    $this->assertSession()->pageTextContains('Behavior plugins are only supported by the stable paragraphs widget');
     // Enable the test plugins, with an invalid configuration value.
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
       'behavior_plugins[test_text_color][enabled]' => TRUE,
       'behavior_plugins[test_text_color][settings][default_color]' => 'red',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Red can not be used as the default color.');
 
     // Ensure the form can be saved with an invalid configuration value when
@@ -51,7 +51,7 @@ public function testBehaviorPluginsFields() {
       'behavior_plugins[test_text_color][enabled]' => FALSE,
       'behavior_plugins[test_text_color][settings][default_color]' => 'red',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Saved the text_paragraph Paragraphs type.');
 
     // Ensure it can be saved with a valid value and that the defaults are
@@ -66,7 +66,8 @@ public function testBehaviorPluginsFields() {
       'behavior_plugins[test_text_color][enabled]' => TRUE,
       'behavior_plugins[test_text_color][settings][default_color]' => 'green',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('Saved the text_paragraph Paragraphs type.');
 
     $this->drupalGet('node/add/paragraphed_test');
@@ -95,7 +96,7 @@ public function testBehaviorPluginsFields() {
     $behavior_xpath = $this->xpath("//div[@id = 'edit-field-paragraphs-0-top']/following-sibling::*[1][@id = 'edit-field-paragraphs-0-behavior-plugins-test-bold-text']");
     $this->assertNotEquals($behavior_xpath, FALSE, 'Behavior form position incorrect');
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Asserting that the error message is shown.
     $this->assertSession()->pageTextContains('The only allowed values are blue and red.');
     // Updating the text color to an allowed value.
@@ -103,7 +104,7 @@ public function testBehaviorPluginsFields() {
     $edit = [
       'field_paragraphs[0][behavior_plugins][test_text_color][text_color]' => $plugin_text,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Assert that the class has been added to the element.
     $this->assertSession()->responseContains('class="red_plugin_text');
 
@@ -117,7 +118,7 @@ public function testBehaviorPluginsFields() {
       'field_paragraphs[0][behavior_plugins][test_text_color][text_color]' => $updated_text,
       'field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->responseNotContains('class="red_plugin_text');
     $this->assertSession()->responseContains('class="bold_plugin_text blue_plugin_text');
     $this->clickLink('Edit');
@@ -135,7 +136,7 @@ public function testBehaviorPluginsFields() {
     $this->assertSession()->fieldNotExists('field_paragraphs[0][behavior_plugins][test_text_color][text_color]');
     $this->assertSession()->fieldNotExists('field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]');
 
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     // Make sure that values don't change if a user without the 'edit behavior
     // plugin settings' permission saves a node with paragraphs and enabled
@@ -156,46 +157,51 @@ public function testBehaviorPluginsFields() {
     $this->assertSession()->fieldExists('behavior_plugins[test_field_selection][enabled]');
     $this->assertSession()->pageTextContains('Choose paragraph field to be applied.');
     // Assert that Field Selection Filter plugin properly filters field types.
-    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection-filter', t('Image'));
+    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection-filter', 'Image');
     // Check that Field Selection Plugin does not filter any field types.
-    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection', t('Image'));
-    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection', t('Text'));
+    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection', 'Image');
+    $this->assertSession()->optionExists('edit-behavior-plugins-test-field-selection-settings-field-selection', 'Text');
 
     // Test a plugin without behavior fields.
     $edit = [
       'behavior_plugins[test_dummy_behavior][enabled]' => TRUE,
       'behavior_plugins[test_text_color][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_test_add_more');
     $edit = [
       'title[0][value]' => 'paragraph with no fields',
       'field_paragraphs[0][subform][field_text_test][0][value]' => 'my behavior plugin does not have any field',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->responseContains('dummy_plugin_text');
 
     // Tests behavior plugin on paragraph type with no fields.
     $this->addParagraphsType('fieldless');
-    $this->drupalPostForm('admin/structure/paragraphs_type/fieldless', ['behavior_plugins[test_dummy_behavior][enabled]' => TRUE], t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/fieldless');
+    $this->submitForm(['behavior_plugins[test_dummy_behavior][enabled]' => TRUE], 'Save');
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_fieldless_add_more');
-    $edit = ['title[0][value]' => t('Fieldless')];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm([], 'field_paragraphs_fieldless_add_more');
+    $edit = ['title[0][value]' => 'Fieldless'];
+    $this->submitForm($edit, 'Save');
 
     $this->assertSession()->statusCodeEquals(200);
 
     // Add a paragraphed content.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_test_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_test_add_more');
     $edit = [
       'title[0][value]' => 'field_override_test',
       'field_paragraphs[0][subform][field_text_test][0][value]' => 'This is a test',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     // Check that the summary does not have the user displayed.
     $node = $this->getNodeByTitle('field_override_test');
-    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_collapse');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm([], 'field_paragraphs_0_collapse');
     $this->assertSession()->responseContains('class="paragraphs-description paragraphs-collapsed-description"><div class="paragraphs-content-wrapper"><span class="summary-content">This is a test');
   }
 
@@ -220,7 +226,8 @@ public function testCollapsedSummary() {
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
       'behavior_plugins[test_text_color][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
 
     // Add a nested Paragraph type.
     $paragraph_type = 'nested_paragraph';
@@ -230,11 +237,13 @@ public function testCollapsedSummary() {
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
 
     // Add a node and enabled plugins.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_1_subform_paragraphs_text_paragraph_add_more');
 
     $this->assertSession()->fieldExists('field_paragraphs[0][behavior_plugins][test_bold_text][bold_text]');
     $this->assertSession()->fieldExists('field_paragraphs[1][behavior_plugins][test_bold_text][bold_text]');
@@ -246,7 +255,7 @@ public function testCollapsedSummary() {
       'field_paragraphs[1][subform][paragraphs][0][subform][field_text][0][value]' => 'nested_paragraph',
       'field_paragraphs[1][behavior_plugins][test_bold_text][bold_text]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $this->clickLink('Edit');
 
@@ -260,11 +269,12 @@ public function testCollapsedSummary() {
     $this->assertSession()->responseContains('nested_paragraph</span></div><div class="paragraphs-plugin-wrapper"><span class="summary-plugin"><span class="summary-plugin-label">Bold</span>Yes</span></div></div>');
 
     // Add an empty nested paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'collapsed_test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check an empty nested paragraph summary.
     $this->clickLink('Edit');
@@ -292,7 +302,8 @@ public function testBehaviorSubform() {
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
       'behavior_plugins[test_text_color][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
 
     // Add a nested Paragraph type.
     $paragraph_type = 'nested_paragraph';
@@ -305,12 +316,14 @@ public function testBehaviorSubform() {
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
 
     // Add a node and enabled plugins.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_text_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'collapsed_test',
       'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => 'nested text paragraph',
@@ -318,7 +331,7 @@ public function testBehaviorSubform() {
       'field_paragraphs[1][subform][field_text][0][value]' => 'first_paragraph',
       'field_paragraphs[1][behavior_plugins][test_bold_text][bold_text]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $this->clickLink('Edit');
     $edit = [
@@ -327,7 +340,7 @@ public function testBehaviorSubform() {
       'field_paragraphs[1][behavior_plugins][test_text_color][text_color]' => 'red',
       'field_paragraphs[1][_weight]' => 0,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->clickLink('Edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][behavior_plugins][test_text_color][text_color]', 'red');
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsConfigTest.php
similarity index 85%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsConfigTest.php
index 1e044b26d9..5f3e124926 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalConfigTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsConfigTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\NodeType;
@@ -10,14 +10,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalConfigTest extends ParagraphsExperimentalTestBase {
+class ParagraphsConfigTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
   );
 
@@ -49,19 +49,21 @@ public function testFieldTranslationDisabled() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][field_paragraphs]' => FALSE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Create a node with a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'paragraphed_title'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Attempt to add a translation.
     $node = $this->drupalGetNodeByTitle('paragraphed_title');
     $this->drupalGet('node/' . $node->id() . '/translations');
-    $this->clickLink(t('Add'));
+    $this->clickLink('Add');
     // Save the translation.
-    $this->drupalPostForm(NULL, [], t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_test paragraphed_title has been updated.');
   }
 
@@ -95,7 +97,8 @@ public function testContentTranslationForm() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][field_paragraphs]' => FALSE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check error message is still not displayed.
     $this->drupalGet('admin/config/regional/content-language');
@@ -112,7 +115,8 @@ public function testContentTranslationForm() {
       'settings[node][paragraphed_test][translatable]' => TRUE,
       'settings[node][paragraphed_test][fields][field_paragraphs]' => TRUE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check content type field management error.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/fields/node.paragraphed_test.field_paragraphs');
@@ -126,8 +130,8 @@ public function testContentTranslationForm() {
       'label' => 'new_no_field_paragraphs',
       'field_name' => 'new_no_field_paragraphs',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
     $this->assertSession()->pageTextNotContains('Paragraphs fields do not support translation.');
     $this->assertSession()->responseNotContains('<div class="messages messages--warning');
   }
@@ -174,16 +178,16 @@ public function testIncludedParagraphTypes() {
       'settings[handler_settings][negate]' => 0,
       'settings[handler_settings][target_bundles_drag_drop][paragraph_type_test][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->assertSession()->pageTextContains('Add paragraph_type_test');
-    $this->assertSession()->pageTextNotContains('Add text');
+    $this->assertSession()->buttonExists('Add paragraph_type_test');
+    $this->assertSession()->responseNotContains('Add text');
     $edit = [
       'title[0][value]' => 'Testing included types'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Testing included types has been created.');
 
     // Include all types.
@@ -193,7 +197,7 @@ public function testIncludedParagraphTypes() {
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
       'settings[handler_settings][target_bundles_drag_drop][paragraph_type_test][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->drupalGet('node/add/paragraphed_test');
     $button_paragraphed_type_test = $this->xpath('//input[@id=:id]', [':id' => 'paragraphs-paragraph-type-test-add-more']);
     $button_text = $this->xpath('//input[@id=:id]', [':id' => 'paragraphs-text-add-more']);
@@ -202,7 +206,7 @@ public function testIncludedParagraphTypes() {
     $edit = [
       'title[0][value]' => 'Testing all excluded types'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Testing all excluded types has been created.');
   }
 
@@ -221,16 +225,16 @@ public function testExcludedParagraphTypes() {
       'settings[handler_settings][negate]' => 1,
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->assertSession()->pageTextContains('Saved paragraphs configuration.');
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->assertSession()->pageTextContains('Add paragraph_type_test');
-    $this->assertSession()->pageTextNotContains('Add text');
+    $this->assertSession()->buttonExists('Add paragraph_type_test');
+    $this->assertSession()->responseNotContains('Add text');
     $edit = [
       'title[0][value]' => 'Testing excluded types'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Testing excluded types has been created.');
 
     // Exclude all types.
@@ -240,13 +244,13 @@ public function testExcludedParagraphTypes() {
       'settings[handler_settings][target_bundles_drag_drop][text][enabled]' => 1,
       'settings[handler_settings][target_bundles_drag_drop][paragraph_type_test][enabled]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save settings');
+    $this->submitForm($edit, 'Save settings');
     $this->drupalGet('node/add/paragraphed_test');
     $this->assertSession()->pageTextContains('You are not allowed to add any of the Paragraph types.');
     $edit = [
       'title[0][value]' => 'Testing all excluded types'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Testing all excluded types has been created.');
   }
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContactTest.php
similarity index 80%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContactTest.php
index 23c1ac1721..136754447c 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContactTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContactTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\contact\Entity\ContactForm;
 
@@ -9,14 +9,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalContactTest extends ParagraphsExperimentalTestBase {
+class ParagraphsContactTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'contact',
   );
 
@@ -39,10 +39,10 @@ public function testContactForm() {
     $this->addParagraphsField($contact_form->id(), 'paragraphs', 'contact_message');
     // Add a paragraph to the contact form.
     $this->drupalGet('contact/test_contact_form');
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraphs_contact_add_more');
+    $this->submitForm([], 'paragraphs_paragraphs_contact_add_more');
     // Check that the paragraph is displayed.
     $this->assertSession()->pageTextContains('paragraphs_contact');
-    $this->drupalPostForm(NULL, [], 'paragraphs_0_remove');
+    $this->submitForm([], 'paragraphs_0_remove');
     $elements = $this->xpath('//table[starts-with(@id, :id)]/tbody', [':id' => 'paragraphs-values']);
     $header = $this->xpath('//table[starts-with(@id, :id)]/thead', [':id' => 'paragraphs-values']);
     $this->assertEquals($elements, []);
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContentModerationTranslationsTest.php
similarity index 97%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContentModerationTranslationsTest.php
index fed2b6e0a6..b0ed7eb169 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalContentModerationTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsContentModerationTranslationsTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -10,16 +11,16 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalContentModerationTranslationsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsContentModerationTranslationsTest extends ParagraphsTestBase {
 
-  use ParagraphsLastEntityQueryTrait;
+  use ParagraphsLastEntityQueryTrait, ParagraphsCoreVersionUiTestTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -41,13 +42,9 @@ class ParagraphsExperimentalContentModerationTranslationsTest extends Paragraphs
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     $this->addParagraphedContentType('paragraphed_test');
 
@@ -94,7 +91,7 @@ protected function setUp() {
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/text', 'text', 'Text', 'text_long', [], []);
@@ -121,7 +118,7 @@ protected function setUp() {
       'settings[paragraph][text][fields][field_untranslatable]' => FALSE,
       'settings[paragraph][container][fields][field_paragraphs]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDragAndDropModeTest.php
similarity index 95%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDragAndDropModeTest.php
index c99d382fc9..e2aaaacbb2 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDragAndDropModeTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDragAndDropModeTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\node\Entity\Node;
@@ -11,12 +11,12 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalDragAndDropModeTest extends ParagraphsExperimentalTestBase {
+class ParagraphsDragAndDropModeTest extends ParagraphsTestBase {
 
   /**
    * Modules to be enabled.
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs',
     'field'
@@ -25,7 +25,7 @@ class ParagraphsExperimentalDragAndDropModeTest extends ParagraphsExperimentalTe
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
     $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs');
     $this->addParagraphsType('paragraphs_container');
@@ -110,7 +110,7 @@ public function testChangeParagraphParentWeight() {
     $this->assertEquals($text_paragraph_2->get('parent_type')->value, 'paragraph');
 
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     $assert_session = $this->assertSession();
     $assert_session->hiddenFieldValueEquals('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]', 'field_paragraphs][0][paragraphs_container_paragraphs');
@@ -133,8 +133,8 @@ public function testChangeParagraphParentWeight() {
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][1][_weight]')
       ->setValue(0);
 
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Complete drag & drop');
+    $this->submitForm([], 'Save');
 
     // Check the new structure of the node and its paragraphs.
     \Drupal::entityTypeManager()->getStorage('node')->resetCache();
@@ -210,7 +210,7 @@ public function testChangeParagraphContainerMove() {
     // Change the path of the text paragraph to the empty container as its
     // parent.
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     // Ensure that the summary is displayed correctly.
     $this->assertSession()->elementTextContains('css', '.paragraphs-dragdrop-wrapper li:nth-of-type(1)', 'Test text 1');
@@ -219,7 +219,7 @@ public function testChangeParagraphContainerMove() {
     $this->assertSession()
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]')
       ->setValue('field_paragraphs][1][paragraphs_container_paragraphs');
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
+    $this->submitForm([], 'Complete drag & drop');
 
     // Ensure the summary is displayed correctly for the collapsed paragraphs.
     $this->assertSession()->elementTextNotContains('css', '.field--name-field-paragraphs tbody tr:nth-of-type(1) .paragraph-summary', 'Test text 1');
@@ -227,12 +227,12 @@ public function testChangeParagraphContainerMove() {
 
     // Ensure that the summary was updated correctly when going back to drag and
     // drop mode.
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
     $this->assertSession()->elementTextNotContains('css', '.paragraphs-dragdrop-wrapper li:nth-of-type(1)', 'Test text 1');
     $this->assertSession()->elementTextContains('css', '.paragraphs-dragdrop-wrapper li:nth-of-type(2)', 'Test text 1');
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
+    $this->submitForm([], 'Complete drag & drop');
 
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the parent of the text paragraph is the second paragraph
     // container.
@@ -337,7 +337,7 @@ public function testMultipleChangesParagraphs() {
     $edit = [
       'field_paragraphs[2][subform][paragraphs_container_paragraphs][0][subform][field_text][0][value]' => 'new paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Drag & drop');
+    $this->submitForm($edit, 'Drag & drop');
 
     // Change the structure of the node, third text paragraph goes to first
     // container, the first text paragraph goes to the second container (child
@@ -370,7 +370,7 @@ public function testMultipleChangesParagraphs() {
       ->setValue(1);
 
     // Save immediately, without separately confirming the widget changes.
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Reset the cache to make sure that the loaded parents are the new ones.
     \Drupal::entityTypeManager()->getStorage('paragraph')->resetCache();
@@ -450,7 +450,7 @@ public function testChangeParagraphContainerMultipleFields() {
     // Change the path of the text paragraph to the empty container as its
     // parent.
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     // Make sure that the second paragraph field is still displayed normally by
     // checking that it displays the edit button, as it is closed by default.
@@ -462,7 +462,7 @@ public function testChangeParagraphContainerMultipleFields() {
     $this->assertSession()
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]')
       ->setValue('field_paragraphs][1][paragraphs_container_paragraphs');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the parent of the text paragraph is the second paragraph
     // container.
@@ -548,16 +548,16 @@ public function testChangeParagraphMoveBeforeReorder() {
       'field_paragraphs[1][_weight]' => 2,
       'field_paragraphs[2][_weight]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Drag & drop');
+    $this->submitForm($edit, 'Drag & drop');
 
     // Change the path of the text paragraph to the empty container as its
     // parent.
     $this->assertSession()
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]')
       ->setValue('field_paragraphs][1][paragraphs_container_paragraphs');
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
+    $this->submitForm([], 'Complete drag & drop');
 
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
 
     // Check that the parent of the text paragraph is the second paragraph
     // container.
@@ -633,7 +633,7 @@ public function testChangeParagraphMoveAfterDelete() {
     // Delete the first container, move the text 2 paragraph into the second
     // container.
     $this->getSession()->getPage()->pressButton('field_paragraphs_0_remove');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     $assert_session = $this->assertSession();
 
@@ -649,8 +649,8 @@ public function testChangeParagraphMoveAfterDelete() {
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][1][_weight]')
       ->setValue(0);
 
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Complete drag & drop');
+    $this->submitForm([], 'Save');
 
     // Check that the parent of the text paragraph is the second paragraph
     // container.
@@ -715,7 +715,7 @@ public function testChangeParagraphMoveAllFromTopLevelContainer() {
     $this->assertEquals($text_paragraph_2->get('parent_type')->value, 'paragraph');
 
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     $assert_session = $this->assertSession();
     $assert_session->hiddenFieldValueEquals('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]', 'field_paragraphs][0][paragraphs_container_paragraphs');
@@ -738,8 +738,8 @@ public function testChangeParagraphMoveAllFromTopLevelContainer() {
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][_weight]')
       ->setValue(2);
 
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Complete drag & drop');
+    $this->submitForm([], 'Save');
 
     // Check the new structure of the node and its paragraphs.
     \Drupal::entityTypeManager()->getStorage('node')->resetCache();
@@ -818,7 +818,7 @@ public function testChangeParagraphMoveAllFromNestedContainer() {
     $this->assertEquals($text_paragraph_2->get('parent_type')->value, 'paragraph');
 
     $this->drupalGet('/node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     $assert_session = $this->assertSession();
     $assert_session->hiddenFieldValueEquals('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][_path]', 'field_paragraphs][0][paragraphs_container_paragraphs][0][paragraphs_container_paragraphs');
@@ -842,8 +842,8 @@ public function testChangeParagraphMoveAllFromNestedContainer() {
       ->hiddenFieldExists('field_paragraphs[dragdrop][field_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][0][dragdrop][paragraphs_container_paragraphs][list][1][_weight]')
       ->setValue(2);
 
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Complete drag & drop');
+    $this->submitForm([], 'Save');
 
     // Check the new structure of the node and its paragraphs.
     \Drupal::entityTypeManager()->getStorage('node')->resetCache();
@@ -884,10 +884,10 @@ public function testEmptyNodeTitle() {
     $this->getSession()->getPage()->pressButton('Add text');
 
     // Enable drag and drop.
-    $this->drupalPostForm(NULL, [], 'Drag & drop');
+    $this->submitForm([], 'Drag & drop');
 
     // Complete drag and drop.
-    $this->drupalPostForm(NULL, [], 'Complete drag & drop');
+    $this->submitForm([], 'Complete drag & drop');
     $this->assertSession()->fieldExists('field_paragraphs[0][subform][field_text][0][value]');
     $this->assertSession()->pageTextNotContains('Title field is required.');
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDuplicateFeatureTest.php
similarity index 80%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDuplicateFeatureTest.php
index bf13604b20..513df79715 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalDuplicateFeatureTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsDuplicateFeatureTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\field\Entity\FieldStorageConfig;
 
@@ -9,9 +9,9 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalDuplicateFeatureTest extends ParagraphsExperimentalTestBase {
+class ParagraphsDuplicateFeatureTest extends ParagraphsTestBase {
 
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs',
     'field',
@@ -33,8 +33,9 @@ public function testDuplicateButton() {
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $edit = [
@@ -43,14 +44,14 @@ public function testDuplicateButton() {
       'field_paragraphs[1][subform][field_text][0][value]' => 'B',
       'field_paragraphs[2][subform][field_text][0][value]' => 'C',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Click "Duplicate" button on A and move C to the first position.
     $edit = ['field_paragraphs[2][_weight]' => -1];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_duplicate');
+    $this->submitForm($edit, 'field_paragraphs_0_duplicate');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', 'A');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][_weight]', 1);
     $this->assertSession()->fieldValueEquals('field_paragraphs[1][subform][field_text][0][value]', 'B');
@@ -69,7 +70,7 @@ public function testDuplicateButton() {
     ];
 
     // Save and check if all paragraphs are present in the correct order.
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', 'A');
     $this->assertSession()->fieldValueEquals('field_paragraphs[1][subform][field_text][0][value]', 'A');
@@ -77,9 +78,9 @@ public function testDuplicateButton() {
     $this->assertSession()->fieldValueEquals('field_paragraphs[3][subform][field_text][0][value]', 'B');
 
     // Delete the second A, then duplicate C.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_remove');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_2_duplicate');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_1_remove');
+    $this->submitForm([], 'field_paragraphs_2_duplicate');
+    $this->submitForm([], 'Save');
 
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', 'A');
@@ -92,10 +93,10 @@ public function testDuplicateButton() {
     // Disable show duplicate action.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $this->assertSession()->pageTextContains('Features: Duplicate, Collapse / Edit all');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => FALSE], t('Update'));
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => FALSE], 'Update');
     $this->assertSession()->pageTextContains('Features: Collapse / Edit all');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check that the duplicate action is not present.
     $this->assertSession()->buttonNotExists('field_paragraphs_0_duplicate');
@@ -104,10 +105,10 @@ public function testDuplicateButton() {
     // Enable show duplicate action.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
     $this->assertSession()->pageTextContains('Features: Collapse / Edit all');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => TRUE], t('Update'));
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][features][duplicate]' => TRUE], 'Update');
     $this->assertSession()->pageTextContains('Features: Duplicate, Collapse / Edit all');
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check that the duplicate action is present.
     $this->assertSession()->buttonExists('field_paragraphs_0_duplicate');
@@ -136,30 +137,32 @@ public function testDuplicateButtonWithNesting() {
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ], []);
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $edit = [
       'title[0][value]' => 'paragraphs_mode_test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     // Add a text field to nested paragraph.
     $text = 'recognizable_text';
-    $this->drupalPostForm('node/' . $node->id() . '/edit', [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->drupalGet('node/' . $node->id() . '/edit');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Switch mode to closed.
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Click "Duplicate" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_duplicate');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_duplicate');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]', $text);
     $this->assertSession()->fieldValueEquals('field_paragraphs[1][subform][field_nested][0][subform][field_text][0][value]', $text);
 
@@ -171,7 +174,7 @@ public function testDuplicateButtonWithNesting() {
 
     // Save and check if the changed text paragraph value of the duplicated
     // paragraph is not the same as in the original paragraph.
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $page_text = $this->getSession()->getPage()->getText();
     $text_nr_found = substr_count($page_text, $text);
@@ -199,19 +202,20 @@ public function testDuplicateButtonWithLimitedCardinality() {
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'text', 'Text', 'text_long', [], []);
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
 
     $edit = [
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => 'A',
       'field_paragraphs[1][subform][field_text][0][value]' => 'B',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->assertNoField('field_paragraphs_0_duplicate');
-    $this->assertNoField('field_paragraphs_1_duplicate');
+    $this->assertSession()->fieldNotExists('field_paragraphs_0_duplicate');
+    $this->assertSession()->fieldNotExists('field_paragraphs_1_duplicate');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEditModesTest.php
similarity index 74%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEditModesTest.php
index 6db5857c76..83ad6406c5 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEditModesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEditModesTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\block_content\Entity\BlockContent;
 
@@ -9,14 +9,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalEditModesTest extends ParagraphsExperimentalTestBase {
+class ParagraphsEditModesTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'image',
     'block_field',
     'block_content',
@@ -48,12 +48,13 @@ public function testCollapsedSummary() {
 
     // Set edit mode to closed.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostForm(NULL, [], "field_paragraphs_settings_edit");
+    $this->submitForm([], "field_paragraphs_settings_edit");
     $edit = ['fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Add a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_image_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_image_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_title_add_more');
 
     $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
@@ -65,61 +66,61 @@ public function testCollapsedSummary() {
       'files[field_paragraphs_0_subform_field_image_0]' => $file_system->realpath($files[0]->uri),
       'field_paragraphs[1][subform][field_title][0][value]' => 'Title example',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, [], t('Add user_paragraph'));
+    $this->submitForm($edit, 'Save');
+    $this->clickLink('Edit');
+    $this->submitForm([], 'Add user_paragraph');
     $edit = [
       'field_paragraphs[2][subform][field_user][0][target_id]' => $this->admin_user->label() . ' (' . $this->admin_user->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Assert the summary is correctly generated.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">' . $files[0]->filename . '</span>, <span class="summary-content">text_summary</span>');
     $this->assertSession()->responseContains('<span class="summary-content">' . $this->admin_user->label());
     $this->assertSession()->responseContains('<span class="summary-content">Title example');
 
     // Edit and remove alternative text.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_image][0][alt]' => 'alternative_text_summary',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     // Assert the summary is correctly generated.
     $this->assertSession()->responseContains('<span class="summary-content">alternative_text_summary</span>, <span class="summary-content">text_summary</span>');
 
     // Remove image.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_image_0_remove_button');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_image_0_remove_button');
+    $this->submitForm([], 'Save');
 
     // Assert the summary is correctly generated.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">text_summary');
 
     $this->addParagraphsType('nested_paragraph');
     static::fieldUIAddNewField('admin/structure/paragraphs_type/nested_paragraph', 'nested_content', 'Nested Content', 'entity_reference_revisions', ['settings[target_type]' => 'paragraph'], []);
     $this->drupalGet('admin/structure/paragraphs_type/nested_paragraph/form-display');
-    $this->drupalPostForm(NULL, ['fields[field_nested_content][type]' => 'entity_reference_paragraphs'], t('Save'));
+    $this->submitForm(['fields[field_nested_content][type]' => 'entity_reference_paragraphs'], 'Save');
 
     $test_user = $this->drupalCreateUser([]);
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
-    $this->drupalPostForm(NULL, NULL, t('field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more'));
+    $this->submitForm([], 'Add nested_paragraph');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_content_user_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'Node title',
       'field_paragraphs[0][subform][field_nested_content][0][subform][field_user][0][target_id]' => $test_user->label() . ' (' . $test_user->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Create an orphaned ER field item by deleting the target entity.
     $test_user->delete();
 
     $nodes = \Drupal::entityTypeManager()->getStorage('node')->loadByProperties(['title' => 'Node title']);
     $this->drupalGet('node/' . current($nodes)->id() . '/edit');
-    $this->drupalPostForm(NULL, [], t('field_paragraphs_0_edit'));
-    $this->drupalPostForm(NULL, [], t('field_paragraphs_0_collapse'));
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_collapse');
     $this->assertSession()->statusCodeEquals(200);
 
     // Add a Block Paragraphs type.
@@ -136,14 +137,14 @@ public function testCollapsedSummary() {
     $this->placeBlock($after_block2->id());
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_block_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_block_paragraph_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_block][0][plugin_id]' => 'block_content:' . $after_block2->uuid(),
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     $this->assertSession()->responseContains('<span class="summary-content">Llama custom block');
     $edit = ['title[0][value]' => 'Test llama block'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Delete the block.
     $after_block2->delete();
     // Attempt to edit the node when the node is deleted.
@@ -156,23 +157,24 @@ public function testCollapsedSummary() {
     $this->addParagraphsType($paragraph_type);
     static::fieldUIAddNewField('admin/structure/paragraphs_type/' . $paragraph_type, 'link', 'Link', 'link', [], []);
     // Create a node with a link paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_link_paragraph_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_link_paragraph_add_more');
     $edit = [
       'title[0][value]' => 'Test link',
       'field_paragraphs[0][subform][field_link][0][uri]' => 'http://www.google.com',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check the summary when no link title is provided.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">http://www.google.com');
     // Set a link title.
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $edit = [
       'field_paragraphs[0][subform][field_link][0][title]' => 'Link title',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check the summary when the link title is set.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('<span class="summary-content">Link title');
 
     // Allow the user to select if the paragraphs is published or not.
@@ -180,30 +182,34 @@ public function testCollapsedSummary() {
       'fields[status][region]' => 'content',
       'fields[status][type]' => 'boolean_checkbox'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $title_paragraphs_type . '/form-display', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/' . $title_paragraphs_type . '/form-display');
+    $this->submitForm($edit, 'Save');
     $edit = [
       'fields[field_nested_content][type]' => 'paragraphs',
       'fields[status][region]' => 'content',
       'fields[status][type]' => 'boolean_checkbox'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/nested_paragraph/form-display', $edit, 'Save');
+    $this->drupalGet('admin/structure/paragraphs_type/nested_paragraph/form-display');
+    $this->submitForm($edit, 'Save');
 
     // Add a unpublished text paragraph and check its summary when unpublished.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_title_add_more');
     $edit = [
       'title[0][value]' => 'Access summary test',
       'field_paragraphs[0][subform][field_title][0][value]' => 'memorable_summary_title',
       'field_paragraphs[0][subform][status][value]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextNotContains('memorable_summary_title');
     $node = $this->getNodeByTitle('Access summary test');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->responseContains('<span class="summary-content">memorable_summary_title');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
 
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_content_title_add_more');
 
     // Add a nested paragraph and with the parent unpublished, check the
     // summary.
@@ -213,14 +219,14 @@ public function testCollapsedSummary() {
       'field_paragraphs[0][subform][field_nested_content][0][subform][status][value]' => FALSE,
       'field_paragraphs[0][subform][field_nested_content][0][subform][field_title][0][value]' => 'memorable_nested_summary_title',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextNotContains('memorable_nested_summary_title');
     $node = $this->getNodeByTitle('Access nested summary test');
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->responseContains('<span class="summary-content">memorable_nested_summary_title');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
     $this->assertSession()->responseContains('<span class="summary-content">memorable_nested_summary_title');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
 
@@ -232,8 +238,8 @@ public function testCollapsedSummary() {
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->responseContains('<span class="summary-content">memorable_nested_summary_title');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_content_0_collapse');
     $this->assertSession()->responseContains('<span class="summary-content">memorable_nested_summary_title');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-view')]")));
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
similarity index 71%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
index 766535c702..98da3e6449 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsEntityTranslationWithNonTranslatableParagraphs.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests the translation of heavily nested / specialized setup.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs extends ParagraphsExperimentalTestBase {
+class ParagraphsEntityTranslationWithNonTranslatableParagraphs extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'language',
     'content_translation',
   ];
@@ -22,7 +22,7 @@ class ParagraphsExperimentalEntityTranslationWithNonTranslatableParagraphs exten
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     $this->admin_user = $this->drupalCreateUser([], NULL, TRUE);
@@ -32,11 +32,13 @@ protected function setUp() {
     $edit = array(
       'predefined_langcode' => 'de',
     );
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->drupalGet('admin/config/regional/language/add');
+    $this->submitForm($edit, 'Add language');
     $edit = array(
       'predefined_langcode' => 'fr',
     );
-    $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->drupalGet('admin/config/regional/language/add');
+    $this->submitForm($edit, 'Add language');
 
     // Create article content type with a paragraphs field.
     $this->addParagraphedContentType('article', 'field_paragraphs');
@@ -45,7 +47,8 @@ protected function setUp() {
     $edit = array(
       'language_configuration[content_translation]' => TRUE,
     );
-    $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
+    $this->drupalGet('admin/structure/types/manage/article');
+    $this->submitForm($edit, 'Save content type');
     $this->drupalGet('admin/structure/types/manage/article');
 
     // Ensue the paragraphs field itself isn't translatable - this would be a
@@ -53,7 +56,8 @@ protected function setUp() {
     $edit = array(
       'translatable' => FALSE,
     );
-    $this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_paragraphs', $edit, t('Save settings'));
+    $this->drupalGet('admin/structure/types/manage/article/fields/node.article.field_paragraphs');
+    $this->submitForm($edit, 'Save settings');
 
     // Add Paragraphs type.
     $this->addParagraphsType('test_paragraph_type');
@@ -79,30 +83,30 @@ public function testParagraphsIEFTranslation() {
     $edit = [
       'title[0][value]' => 'Title English',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Title English');
 
     $edit = array(
       'title[0][value]' => 'Title French',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('article Title French has been updated.');
 
     // Add german translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'));
+    $this->clickLink('Translate');
+    $this->clickLink('Add');
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Title English');
 
     $edit = array(
       'title[0][value]' => 'Title German',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('article Title German has been updated.');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsFieldGroupTest.php
similarity index 70%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsFieldGroupTest.php
index a80cbd0ed1..3f2223a653 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalFieldGroupTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsFieldGroupTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests the field group on node.
@@ -8,14 +8,14 @@
  * @group paragraphs
  * @requires module field_group
  */
-class ParagraphsExperimentalFieldGroupTest extends ParagraphsExperimentalTestBase {
+class ParagraphsFieldGroupTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'field_group',
   ];
 
@@ -41,22 +41,25 @@ public function testFieldGroup() {
       'label' => 'paragraph_field_group_title',
       'group_name' => 'field'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display/add-group', $edit, t('Save and continue'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display/add-group');
+    $this->submitForm($edit, 'Save and continue');
     $edit = [
       'format_settings[label]' => 'field_group'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Create group'));
+    $this->submitForm($edit, 'Create group');
 
     // Put the text field into the field group.
     $edit = [
       'fields[group_field][region]' => 'content',
       'fields[field_text][parent]' => 'group_field'
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display', $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type . '/form-display');
+    $this->submitForm($edit, 'Save');
 
     // Create a node with a paragraph.
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostForm('node/add/' . $content_type, [], 'field_paragraphs_paragraph_type_test_add_more');
+    $this->drupalGet('node/add/' . $content_type);
+    $this->submitForm([], 'field_paragraphs_paragraph_type_test_add_more');
 
     // Test if the new field group is displayed.
     $this->assertSession()->pageTextContains('field_group');
@@ -67,7 +70,7 @@ public function testFieldGroup() {
       'title[0][value]' => 'paragraphed_title',
       'field_paragraphs[0][subform][field_text][0][value]' => 'paragraph_value',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsHeaderActionsTest.php
similarity index 80%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsHeaderActionsTest.php
index cf8063d597..174ecd618f 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalHeaderActionsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsHeaderActionsTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Symfony\Component\CssSelector\CssSelectorConverter;
@@ -10,14 +10,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalHeaderActionsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsHeaderActionsTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
   );
 
@@ -62,7 +62,7 @@ public function testHeaderActions() {
     $this->assertEquals(1, count($table_rows));
 
     // Add second paragraph and check for Collapse/Edit all button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
     $this->assertSession()->responseContains('field_paragraphs_collapse_all');
     $this->assertSession()->responseContains('field_paragraphs_edit_all');
 
@@ -70,21 +70,21 @@ public function testHeaderActions() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'First text',
       'field_paragraphs[1][subform][field_text][0][value]' => 'Second text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Collapse all');
+    $this->submitForm($edit, 'Collapse all');
 
     // Checks that after collapsing all we can edit again these paragraphs.
     $this->assertSession()->responseContains('field_paragraphs_0_edit');
     $this->assertSession()->responseContains('field_paragraphs_1_edit');
 
     // Test Edit all button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->submitForm([], 'field_paragraphs_edit_all');
     $this->assertSession()->responseContains('field_paragraphs_0_collapse');
     $this->assertSession()->responseContains('field_paragraphs_1_collapse');
 
     $edit = [
       'title[0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Test has been created.');
 
     $node = $this->getNodeByTitle('Test');
@@ -93,41 +93,41 @@ public function testHeaderActions() {
     $this->assertSession()->pageTextNotContains('No Paragraph added yet.');
 
     // Add and remove another paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
     $edit = [
       'field_paragraphs[2][subform][field_text][0][value]' => 'Third text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_2_remove');
+    $this->submitForm($edit, 'field_paragraphs_2_remove');
 
     // Check that pressing "Collapse all" does not restore the removed
     // paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->submitForm([], 'field_paragraphs_edit_all');
     $this->assertSession()->pageTextContains('First text');
     $this->assertSession()->pageTextContains('Second text');
     $this->assertSession()->pageTextNotContains('Third text');
 
     // Check that pressing "Edit all" does not restore the removed paragraph,
     // either.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all');
+    $this->submitForm([], 'field_paragraphs_collapse_all');
     $this->assertSession()->pageTextContains('First text');
     $this->assertSession()->pageTextContains('Second text');
     $this->assertSession()->pageTextNotContains('Third text');
     $this->assertSession()->buttonExists('field_paragraphs_collapse_all');
     $this->assertSession()->buttonExists('field_paragraphs_edit_all');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     // Check that the drag and drop button is present when there is a paragraph
     // and that it is not shown when the paragraph is deleted.
     $this->drupalGet('node/add/paragraphed_test');
     $this->assertSession()->responseContains('name="field_paragraphs_dragdrop_mode"');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'field_paragraphs_0_remove');
     $this->assertSession()->responseNotContains('name="field_paragraphs_dragdrop_mode"');
 
     // Disable show multiple actions.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => FALSE], t('Update'));
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => FALSE], 'Update');
+    $this->submitForm([], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check that the collapse/edit all actions are not present.
     $this->assertSession()->buttonNotExists('field_paragraphs_collapse_all');
@@ -136,9 +136,9 @@ public function testHeaderActions() {
 
     // Enable show "Collapse / Edit all" actions.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_settings_edit');
-    $this->drupalPostForm(NULL, ['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => TRUE], t('Update'));
-    $this->drupalPostForm(NULL, [], 'Save');
+    $this->submitForm([], 'field_paragraphs_settings_edit');
+    $this->submitForm(['fields[field_paragraphs][settings_edit_form][settings][features][collapse_edit_all]' => TRUE], 'Update');
+    $this->submitForm([], 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Check that the collapse/edit all actions are present.
     $this->assertSession()->buttonExists('field_paragraphs_collapse_all');
@@ -186,34 +186,34 @@ public function testHeaderActionsWithNesting() {
     );
 
     $this->drupalGet('admin/structure/paragraphs_type/nested_paragraph/form-display');
-    $this->drupalPostForm(NULL, ['fields[field_nested][type]' => 'paragraphs'], t('Save'));
+    $this->submitForm(['fields[field_nested][type]' => 'paragraphs'], 'Save');
     $this->setParagraphsWidgetSettings($nested_paragraph_type, 'nested', ['edit_mode' => 'closed'], 'paragraphs', 'paragraph');
 
     // Checks that Collapse/Edit all button is presented.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_add_more');
     $this->assertSession()->responseContains('field_paragraphs_collapse_all');
     $this->assertSession()->responseContains('field_paragraphs_edit_all');
 
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->submitForm([], 'field_paragraphs_text_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $this->assertSession()->responseNotContains('field_paragraphs_0_collapse_all');
     $this->assertSession()->responseNotContains('field_paragraphs_0_edit_all');
     $edit = [
       'field_paragraphs[0][subform][field_nested][0][subform][field_text][0][value]' => 'Nested text',
       'field_paragraphs[1][subform][field_text][0][value]' => 'Second text paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Collapse all');
+    $this->submitForm($edit, 'Collapse all');
     $this->assertSession()->responseContains('field-paragraphs-0-edit');
     $this->assertSession()->elementExists('css', '[name="field_paragraphs_1_edit"] + .paragraphs-dropdown');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_edit_all');
+    $this->submitForm([], 'field_paragraphs_edit_all');
     $this->assertSession()->responseContains('field-paragraphs-0-collapse');
 
     $edit = [
       'title[0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Test has been created.');
 
     $node = $this->getNodeByTitle('Test');
@@ -221,12 +221,12 @@ public function testHeaderActionsWithNesting() {
     $this->clickLink('Edit');
     $this->assertSession()->pageTextNotContains('No Paragraph added yet.');
 
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_subform_field_nested_text_add_more');
+    $this->submitForm([], 'field_paragraphs_0_subform_field_nested_text_add_more');
     $edit = [
       'field_paragraphs[0][subform][field_nested][1][subform][field_text][0][value]' => 'Second nested text',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $this->assertSession()->responseContains('field_paragraphs_0_subform_field_nested_collapse_all');
     $this->assertSession()->responseContains('field_paragraphs_0_subform_field_nested_edit_all');
   }
@@ -250,15 +250,15 @@ public function testHeaderActionsWithMultiFields() {
       'label' => 'Second paragraph',
       'field_name' => 'second',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save and continue');
-    $this->drupalPostForm(NULL, [], 'Save field settings');
-    $this->drupalPostForm(NULL, [], 'Save settings');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm([], 'Save settings');
 
     $this->drupalGet('/admin/structure/types/manage/paragraphed_test/form-display');
     $edit = [
       'fields[field_second][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save');
+    $this->submitForm($edit, 'Save');
 
     // Add a text field to the text_paragraph type.
     static::fieldUIAddNewField(
@@ -271,8 +271,8 @@ public function testHeaderActionsWithMultiFields() {
     );
 
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_second_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_second_text_paragraph_add_more');
 
     // Checks that we have Collapse\Edit all for each field.
     $this->assertSession()->responseContains('field_paragraphs_collapse_all');
@@ -283,23 +283,23 @@ public function testHeaderActionsWithMultiFields() {
     $edit = [
       'field_second[0][subform][field_text][0][value]' => 'Second field',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_second_collapse_all');
+    $this->submitForm($edit, 'field_second_collapse_all');
 
     // Checks that we collapsed only children from second field.
     $this->assertSession()->responseNotContains('field_paragraphs_0_edit');
     $this->assertSession()->responseContains('field_second_0_edit');
 
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_collapse_all');
+    $this->submitForm([], 'field_paragraphs_collapse_all');
     $this->assertSession()->responseContains('field_paragraphs_0_edit');
     $this->assertSession()->responseContains('field_second_0_edit');
 
-    $this->drupalPostForm(NULL, [], 'field_second_edit_all');
+    $this->submitForm([], 'field_second_edit_all');
     $this->assertSession()->responseContains('field_second_0_collapse');
 
     $edit = [
       'title[0][value]' => 'Test',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test Test has been created.');
 
     $node = $this->getNodeByTitle('Test');
@@ -333,7 +333,7 @@ function testHeaderActionsWhileTranslating() {
       'entity_types[node]' => TRUE,
       'settings[node][paragraphed_test][translatable]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save configuration');
+    $this->submitForm($edit, 'Save configuration');
 
     // Add a Paragraph type.
     $paragraph_type = 'text_paragraph';
@@ -347,7 +347,7 @@ function testHeaderActionsWhileTranslating() {
       'title[0][value]' => 'Title',
       'field_paragraphs[0][subform][field_text][0][value]' => 'First',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->clickLink('Translate');
     $this->clickLink('Add');
     // Assert that the drag and drop button is not present while translating.
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsInlineEntityFormTest.php
similarity index 83%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsInlineEntityFormTest.php
index 236253ea95..99a7b16a7c 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalInlineEntityFormTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsInlineEntityFormTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
@@ -9,7 +9,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalInlineEntityFormTest extends ParagraphsExperimentalTestBase {
+class ParagraphsInlineEntityFormTest extends ParagraphsTestBase {
 
   use ParagraphsTestBaseTrait;
 
@@ -18,7 +18,7 @@ class ParagraphsExperimentalInlineEntityFormTest extends ParagraphsExperimentalT
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'inline_entity_form',
   ];
 
@@ -49,7 +49,7 @@ public function testParagraphsIEFPreview() {
     $edit = [
       'fields[field_article][type]' => 'inline_entity_form_simple',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Set the paragraphs widget edit mode to "Closed" and the closed mode to
     // "Preview".
@@ -61,21 +61,21 @@ public function testParagraphsIEFPreview() {
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
       'title[0][value]' => 'Dummy1',
       'field_paragraphs[0][subform][field_article][0][inline_entity_form][title][0][value]' => 'Dummy2',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Go back into edit page.
     $node = $this->getNodeByTitle('Dummy1');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Try to open the previewed paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
   }
 
   /**
@@ -106,21 +106,21 @@ public function testParagraphsIEFChangeOrder() {
       'settings[target_type]' => 'paragraph',
       'cardinality' => '-1',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save field settings'));
+    $this->submitForm($edit, 'Save field settings');
 
     // Enable IEF simple widget.
     $this->drupalGet('admin/structure/paragraphs_type/simple/form-display');
     $edit = [
       'fields[field_article][type]' => 'inline_entity_form_simple',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Set the paragraphs widget closed mode to preview.
     $this->setParagraphsWidgetSettings('article', 'field_paragraphs', ['closed_mode' => 'preview']);
 
     // Create node with one paragraph.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values and save.
     $edit = [
@@ -128,20 +128,20 @@ public function testParagraphsIEFChangeOrder() {
       'field_paragraphs[0][subform][field_article][0][inline_entity_form][title][0][value]' => 'Basic page 1',
     ];
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Go back into edit page.
     $node = $this->getNodeByTitle('Article 1');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Create second paragraph.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_simple_add_more');
+    $this->submitForm([], 'field_paragraphs_simple_add_more');
 
     // Set the values of second paragraph.
     $edit = [
       'field_paragraphs[1][subform][field_article][0][inline_entity_form][title][0][value]' => 'Basic 2'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsPreviewTest.php
similarity index 85%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsPreviewTest.php
index c94aabdee4..bf47bf24bf 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalPreviewTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsPreviewTest.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests the configuration of paragraphs.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalPreviewTest extends ParagraphsExperimentalTestBase {
+class ParagraphsPreviewTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'image',
   );
 
@@ -44,14 +44,14 @@ public function testParagraphsPreview() {
     $test_text_2 = 'dummy_preview_text_2';
     // Create node with two paragraphs.
     $this->drupalGet('node/add/article');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     // Set the value of the paragraphs.
     $edit = [
       'title[0][value]' => 'Page_title',
       'field_paragraphs[0][subform][field_text][0][value]' => $test_text_1,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     // Check if the text is displayed.
     $this->assertSession()->responseContains($test_text_1);
 
@@ -67,15 +67,15 @@ public function testParagraphsPreview() {
     $paragraph_1 = $this->xpath('//*[@id="edit-field-paragraphs-0-subform-field-text-0-value"]')[0];
     $this->assertEquals($paragraph_1->getValue(), $test_text_1);
 
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     $this->clickLink('Edit');
-    $this->drupalPostForm(NULL, array(), 'field_paragraphs_text_add_more');
+    $this->submitForm(array(), 'field_paragraphs_text_add_more');
     $edit = [
       'field_paragraphs[1][subform][field_text][0][value]' => $test_text_2,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($test_text_2);
 
@@ -87,7 +87,7 @@ public function testParagraphsPreview() {
       'field_paragraphs[1][subform][field_text][0][value]' => $new_test_text_2,
     ];
     // Preview the article.
-    $this->drupalPostForm(NULL, $edit, t('Preview'));
+    $this->submitForm($edit, 'Preview');
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($new_test_text_2);
 
@@ -103,7 +103,7 @@ public function testParagraphsPreview() {
     $paragraph_2 = $this->xpath('//*[@id="edit-field-paragraphs-1-subform-field-text-0-value"]')[0];
     $this->assertEquals($paragraph_1->getValue(), $test_text_1);
     $this->assertEquals($paragraph_2->getValue(), $new_test_text_2);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     $this->assertSession()->responseContains($test_text_1);
     $this->assertSession()->responseContains($new_test_text_2);
diff --git a/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsReplicateEnableTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsReplicateEnableTest.php
new file mode 100644
index 0000000000..a5ee9956a8
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsReplicateEnableTest.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
+
+/**
+ * Enables replicate module.
+ *
+ * @group paragraphs
+ */
+
+class ParagraphsReplicateEnableTest extends ParagraphsDuplicateFeatureTest {
+
+  protected static $modules = [
+    'replicate',
+  ];
+
+}
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsSummaryFormatterTest.php
similarity index 77%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsSummaryFormatterTest.php
index 8402f6e310..5083e42c06 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalSummaryFormatterTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsSummaryFormatterTest.php
@@ -1,20 +1,20 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests the paragraphs summary formatter.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalSummaryFormatterTest extends ParagraphsExperimentalTestBase {
+class ParagraphsSummaryFormatterTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'image',
   ];
 
@@ -41,10 +41,11 @@ public function testParagraphsSummaryFormatter() {
     // Set display format to paragraphs summary.
     $this->drupalGet('admin/structure/types/manage/paragraphed_test/display');
     $edit = ['fields[field_paragraphs][type]' => 'paragraph_summary'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Add a paragraph.
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_title_add_more');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_title_add_more');
 
     // Create a node with a text.
     $edit = [
@@ -52,13 +53,13 @@ public function testParagraphsSummaryFormatter() {
       'field_paragraphs[0][subform][field_text][0][value]' => 'text_summary',
       'field_paragraphs[1][subform][field_title][0][value]' => 'Title example',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->clickLink(t('Edit'));
-    $this->drupalPostForm(NULL, [], t('Add user_paragraph'));
+    $this->submitForm($edit, 'Save');
+    $this->clickLink('Edit');
+    $this->submitForm([], 'Add user_paragraph');
     $edit = [
       'field_paragraphs[2][subform][field_user][0][target_id]' => $this->admin_user->label() . ' (' . $this->admin_user->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Assert the summary is correctly generated.
     $this->assertSession()->pageTextContains($this->admin_user->label());
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTestBase.php
similarity index 81%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTestBase.php
index 681658117d..dae186edaf 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTestBase.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTestBase.php
@@ -1,15 +1,15 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
-use Drupal\Tests\paragraphs\Functional\Classic\ParagraphsTestBase;
+use Drupal\Tests\paragraphs\Functional\WidgetLegacy\ParagraphsTestBase as LegacyParagraphsTestBase;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
 
 /**
  * Base class for tests.
  */
-abstract class ParagraphsExperimentalTestBase extends ParagraphsTestBase {
+abstract class ParagraphsTestBase extends LegacyParagraphsTestBase {
 
   use ParagraphsTestBaseTrait;
 
@@ -40,7 +40,7 @@ protected function setAddMode($content_type, $paragraphs_field, $mode) {
    */
   protected function removeDefaultParagraphType($content_type) {
     $this->drupalGet('node/add/' . $content_type);
-    $this->drupalPostForm(NULL, [], 'Remove');
+    $this->submitForm([], 'Remove');
     $this->assertSession()->pageTextNotContains('No paragraphs added yet.');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationTest.php
similarity index 83%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationTest.php
index cd34ddf560..66c6fc35bc 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
@@ -15,14 +15,14 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalTranslationTest extends ParagraphsExperimentalTestBase {
+class ParagraphsTranslationTest extends ParagraphsTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'link',
     'image',
@@ -36,7 +36,7 @@ class ParagraphsExperimentalTranslationTest extends ParagraphsExperimentalTestBa
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -77,7 +77,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
 
     if (version_compare(\Drupal::VERSION, '8.4', '>=')) {
       // @todo Workaround for file usage/unable to save the node with no usages.
@@ -110,38 +111,38 @@ public function testParagraphTranslation() {
       'fields[status][type]' => 'boolean_checkbox',
       'fields[status][region]' => 'content',
     );
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
       ]);
     $form_display->save();
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('paragraph.nested_paragraph.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
       ]);
     $form_display->save();
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $this->assertSession()->responseContains('edit-field-paragraphs-demo-0-subform-status-value');
     $edit = [
       'title[0][value]' => 'example_publish_unpublish',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Example published and unpublished',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextContains(t('Example published and unpublished'));
-    $this->clickLink(t('Edit'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextContains('Example published and unpublished');
+    $this->clickLink('Edit');
 
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'field_paragraphs_demo[0][subform][status][value]' => FALSE,
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'Dummy text'
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertSession()->pageTextNotContains(t('Example published and unpublished'));
+    $this->submitForm($edit, 'Save');
+    $this->assertSession()->pageTextNotContains('Example published and unpublished');
 
     // Check the parent fields are set properly. Get the node.
     $node = $this->drupalGetNodeByTitle('example_publish_unpublish');
@@ -164,26 +165,26 @@ public function testParagraphTranslation() {
 
     // Add paragraphed content.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text_image'));
+    $this->submitForm([], 'Add text_image');
     $edit = array(
       'title[0][value]' => 'Title in english',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Text in english',
     );
     // The button to remove a paragraph is present.
-    $this->assertSession()->responseContains(t('Remove'));
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->assertSession()->responseContains('Remove');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('Title in english');
     // The text is present when editing again.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in english');
     $this->assertSession()->pageTextContains('Text in english');
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure the Add / Remove paragraph buttons are hidden.
-    $this->assertSession()->responseNotContains(t('Remove'));
-    $this->assertSession()->responseNotContains(t('Add text_image'));
+    $this->assertSession()->responseNotContains('Remove');
+    $this->assertSession()->responseNotContains('Add text_image');
     // Make sure that the original paragraph text is displayed.
     $this->assertSession()->pageTextContains('Text in english');
 
@@ -193,7 +194,7 @@ public function testParagraphTranslation() {
       'revision' => TRUE,
       'revision_log[0][value]' => 'french 1',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in french has been updated.');
 
     // Check the english translation.
@@ -209,7 +210,7 @@ public function testParagraphTranslation() {
     $this->assertSession()->pageTextContains('Text in french');
     $this->assertSession()->pageTextNotContains('Title in english');
     // The translation is still present when editing again.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in french');
     $this->assertSession()->pageTextContains('Text in french');
     $edit = array(
@@ -218,35 +219,35 @@ public function testParagraphTranslation() {
       'revision' => TRUE,
       'revision_log[0][value]' => 'french 2',
     );
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title Change in french');
     $this->assertSession()->pageTextContains('New text in french');
 
     // Back to the source language.
     $this->drupalGet('node/' . $node->id());
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertSession()->pageTextContains('Title in english');
     $this->assertSession()->pageTextContains('Text in english');
     // Save the original content on second request.
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in english has been updated.');
 
     // Test if reverting to old paragraphs revisions works, make sure that
     // the reverted node can be saved again.
     $this->drupalGet('fr/node/' . $node->id() . '/revisions');
-    $this->clickLink(t('Revert'));
-    $this->drupalPostForm(NULL, ['revert_untranslated_fields' => TRUE], t('Revert'));
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Revert');
+    $this->submitForm(['revert_untranslated_fields' => TRUE], 'Revert');
+    $this->clickLink('Edit');
     $this->assertSession()->responseContains('Title in french');
     $this->assertSession()->pageTextContains('Text in french');
-    $this->drupalPostForm(NULL, [], t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->responseNotContains('The content has either been modified by another user, or you have already submitted modifications');
     $this->assertSession()->pageTextContains('Text in french');
 
     //Add paragraphed content with untranslatable language
     $this->drupalGet('node/add/paragraphed_content_demo');
     $edit = array('langcode[0][value]' => LanguageInterface::LANGCODE_NOT_SPECIFIED);
-    $this->drupalPostForm(NULL, $edit, t('Add text_image'));
+    $this->submitForm($edit, 'Add text_image');
     $this->assertSession()->statusCodeEquals(200);
 
     // Make 'Images' paragraph field translatable, enable alt and title fields.
@@ -257,41 +258,41 @@ public function testParagraphTranslation() {
       'settings[alt_field]' => 1,
       'settings[title_field]' => 1,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save settings'));
+    $this->submitForm($edit, 'Save settings');
 
     // Create a node with an image paragraph, its alt and title text.
     $files = $this->getTestFiles('image');
     $file_system = \Drupal::service('file_system');
     $file_path = $file_system->realpath($file_system->realpath($files[0]->uri));
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add images'));
-    $this->drupalPostForm(NULL, ['files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path], t('Upload'));
+    $this->submitForm([], 'Add images');
+    $this->submitForm(['files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $file_path], 'Upload');
     $edit = [
       'title[0][value]' => 'Title EN',
       'field_paragraphs_demo[0][subform][field_images_demo][0][alt]' => 'Image alt',
       'field_paragraphs_demo[0][subform][field_images_demo][0][title]' => 'Image title',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Translate the node with the image paragraph.
     $this->clickLink('Translate');
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Add', 1);
     $edit = [
       'title[0][value]' => 'Title FR',
       'field_paragraphs_demo[0][subform][field_images_demo][0][alt]' => 'Image alt FR',
       'field_paragraphs_demo[0][subform][field_images_demo][0][title]' => 'Image title FR',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertSession()->responseContains('Title FR');
 
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add text'));
+    $this->submitForm([], 'Add text');
     $edit = [
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'texto',
       'title[0][value]' => 'titulo',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('titulo');
     $this->assertParagraphsLangcode($node->id(), 'de');
 
@@ -324,7 +325,7 @@ public function testParagraphTranslation() {
       'field_paragraphs_demo' => [$paragraph_1, $translated_paragraph],
     ]);
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo ' . $node->label() . ' has been updated.');
     // Check that first paragraph langcode has been updated.
     \Drupal::entityTypeManager()->getStorage('paragraph')->resetCache([$paragraph_1->id(), $paragraph_2->id()]);
@@ -342,25 +343,26 @@ public function testParagraphTranslation() {
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'english_translation_1',
       'field_paragraphs_demo[1][subform][field_text_demo][0][value]' => 'english_translation_2',
     ];
-    $this->drupalPostForm('node/' . $node->id() . '/translations/add/de/en', $edit, t('Save (this translation)'));
+    $this->drupalGet('node/' . $node->id() . '/translations/add/de/en');
+    $this->submitForm($edit, 'Save (this translation)');
     // Attempt to create a french translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
     // Check that the german translation of the paragraphs is displayed.
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[0][subform][field_text_demo][0][value]', 'english_text_1');
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[1][subform][field_text_demo][0][value]', 'german_text_2');
-    $this->drupalPostForm(NULL, ['source_langcode[source]' => 'en'], t('Change'));
+    $this->submitForm(['source_langcode[source]' => 'en'], 'Change');
     // Check that the english translation of the paragraphs is displayed.
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[0][subform][field_text_demo][0][value]', 'english_translation_1');
     $this->assertSession()->fieldValueEquals('field_paragraphs_demo[1][subform][field_text_demo][0][value]', 'english_translation_2');
 
     // Create a node with empty Paragraphs.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], t('Add nested_paragraph'));
+    $this->submitForm([], 'Add nested_paragraph');
     $edit = ['title[0][value]' => 'empty_node'];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Attempt to translate it.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'));
+    $this->clickLink('Translate');
+    $this->clickLink('Add');
     // Check the add button is not displayed.
     $this->assertEquals(count($this->xpath('//*[@name="field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more"]')), 0);
 
@@ -370,9 +372,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_field',
       'field_name' => 'untranslatable_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm([], 'Save settings');
 
     // Add a non translatable reference field.
     $edit = [
@@ -380,9 +383,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_ref_field',
       'field_name' => 'untranslatable_ref_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, ['settings[handler_settings][target_bundles][paragraphed_content_demo]' => TRUE], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm(['settings[handler_settings][target_bundles][paragraphed_content_demo]' => TRUE], 'Save settings');
 
     // Add a non translatable link field.
     $edit = [
@@ -390,9 +394,10 @@ public function testParagraphTranslation() {
       'label' => 'untranslatable_link_field',
       'field_name' => 'untranslatable_link_field',
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/add-field', $edit, t('Save and continue'));
-    $this->drupalPostForm(NULL, [], t('Save field settings'));
-    $this->drupalPostForm(NULL, [], t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/add-field');
+    $this->submitForm($edit, 'Save and continue');
+    $this->submitForm([], 'Save field settings');
+    $this->submitForm([], 'Save settings');
 
     // Attempt to add a translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
@@ -405,8 +410,10 @@ public function testParagraphTranslation() {
     $edit = [
       'translatable' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_ref_field', $edit, t('Save settings'));
-    $this->drupalPostForm('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_link_field', $edit, t('Save settings'));
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_ref_field');
+    $this->submitForm($edit, 'Save settings');
+    $this->drupalGet('admin/structure/paragraphs_type/text/fields/paragraph.text.field_untranslatable_link_field');
+    $this->submitForm($edit, 'Save settings');
 
     // Attempt to add a translation.
     $this->drupalGet('node/' . $node->id() . '/translations/add/de/fr');
@@ -420,27 +427,27 @@ public function testParagraphTranslation() {
     $this->setParagraphsWidgetSettings('paragraphed_content_demo', 'field_paragraphs_demo', ['edit_mode' => 'closed']);
     // Create a node with a text and a nested paragraph.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
-    $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
+    $this->submitForm([], 'Add text');
+    $this->submitForm([], 'Add nested_paragraph');
+    $this->submitForm([], 'field_paragraphs_demo_1_subform_field_paragraphs_demo_text_add_more');
     $edit = [
       'title[0][value]' => 'EN llama',
       'langcode[0][value]' => 'en',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'EN text llama',
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'EN nested text llama',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_content_demo EN llama has been created.');
     // Create a german translation.
     $node = $this->drupalGetNodeByTitle('EN llama');
     $this->drupalGet('node/' . $node->id() . '/translations/add/en/de');
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_edit_all');
+    $this->submitForm([], 'field_paragraphs_demo_edit_all');
     $edit = [
       'title[0][value]' => 'DE llama',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'DE text llama',
       'field_paragraphs_demo[1][subform][field_paragraphs_demo][0][subform][field_text_demo][0][value]' => 'DE nested text llama',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     // Assert that the summary is displayed in the current language.
     $this->drupalGet('de/node/' . $node->id() . '/edit');
     $this->assertSession()->fieldValueEquals('title[0][value]', 'DE llama');
@@ -457,20 +464,20 @@ public function testParagraphTranslation() {
     ]);
     // Add a node with a reference paragraph.
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add node_reference'));
+    $this->submitForm([], 'Add node_reference');
     $edit = [
       'title[0][value]' => 'EN referencing llama',
       'langcode[0][value]' => 'en',
       'field_paragraphs_demo[0][subform][field_entity_reference][0][target_id]' => $node->label() . ' (' . $node->id() . ')',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $referencing_node = $this->drupalGetNodeByTitle('EN referencing llama');
     // Translate the node.
     $this->drupalGet('node/' . $referencing_node->id() . '/translations/add/en/de');
     $edit = [
       'title[0][value]' => 'DE referencing llama',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     // Edit the node again and check the paragraph summary.
     $this->drupalGet('de/node/' . $referencing_node->id() . '/edit');
     $this->assertSession()->responseContains('<span class="summary-content">DE llama</span></div></div>');
@@ -488,20 +495,20 @@ public function testParagraphTranslationMultilingual() {
     // Case 1: original node langcode in EN, translate in FR, change to DE.
 
     // Add 'Images' paragraph and check the paragraphs buttons are displayed.
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
       ]);
     $form_display->save();
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('paragraph.nested_paragraph.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
       ]);
     $form_display->save();
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, NULL, t('Add images'));
+    $this->submitForm([], 'Add images');
     $this->assertParagraphsButtons(1);
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
@@ -509,24 +516,24 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in english');
     $node = $this->drupalGetNodeByTitle('Title in english');
     // Check the paragraph langcode is 'en'.
     $this->assertParagraphsLangcode($node->id());
 
     // Add french translation.
-    $this->clickLink(t('Translate'));
-    $this->clickLink(t('Add'), 1);
+    $this->clickLink('Translate');
+    $this->clickLink('Add', 1);
     // Make sure the host entity and its paragraphs have valid source language
     // and check that the paragraphs buttons are hidden.
     $this->assertNoParagraphsButtons(1);
     $edit = [
       'title[0][value]' => 'Title in french',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
+    $this->submitForm($edit, 'Save (this translation)');
     $this->assertParagraphsLangcode($node->id(), 'en', 'fr');
     $this->assertSession()->pageTextContains('paragraphed_content_demo Title in french has been updated.');
     $this->assertSession()->pageTextContains('Title in french');
@@ -537,14 +544,14 @@ public function testParagraphTranslationMultilingual() {
     // Edit the french translation and upload a new image.
     $this->clickLink('Edit');
     $images = $this->getTestFiles('image')[1];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'en', 'fr');
     $this->assertNoParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title in french');
     $this->assertSession()->pageTextNotContains('Title in english');
 
@@ -563,23 +570,23 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add nested_paragraph'));
+    $this->submitForm($edit, 'Add nested_paragraph');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Add an 'Images' paragraph inside the nested one, check the paragraphs
     // langcode are still 'en' and the paragraphs buttons are still displayed.
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_1_subform_field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
     // Upload a new image, check the paragraphs langcode are still 'en' and the
     // paragraphs buttons are displayed.
     $images = $this->getTestFiles('image')[2];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node->id());
     $this->assertParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     $this->assertSession()->pageTextContains('Title in english (de)');
     $this->assertSession()->pageTextNotContains('Title in french');
     // Check the original node and the paragraphs langcode are now 'de'.
@@ -599,9 +606,10 @@ public function testParagraphTranslationMultilingual() {
     // node langcode to EN.
 
     // Change the site langcode to french.
-    $this->drupalPostForm('admin/config/regional/language', [
+    $this->drupalGet('admin/config/regional/language');
+    $this->submitForm([
       'site_default_language' => 'fr',
-    ], t('Save configuration'));
+    ], 'Save configuration');
 
     // Check the original node and its paragraphs langcode are still 'de'
     // and the paragraphs buttons are still displayed.
@@ -611,21 +619,21 @@ public function testParagraphTranslationMultilingual() {
 
     // Go to the french translation.
     $this->drupalGet('node/' . $node->id() . '/translations');
-    $this->clickLink(t('Edit'), 1);
+    $this->clickLink('Edit', 1);
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
     // Upload another image.
     $images = $this->getTestFiles('image')[3];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     // Check editing a translation does not affect the source langcode and
     // check that the paragraphs buttons are still hidden.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertNoParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     // Check the paragraphs langcode are still 'de' after saving the translation.
     $this->assertParagraphsLangcode($node->id(), 'de', 'fr');
     $this->assertSession()->pageTextContains('Title in french');
@@ -646,18 +654,18 @@ public function testParagraphTranslationMultilingual() {
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     $this->assertParagraphsLangcode($node->id(), 'de');
       $this->assertParagraphsButtons(3);
     // Upload a new image, check the paragraphs langcode are still 'de' and the
     // paragraphs buttons are displayed.
     $images = $this->getTestFiles('image')[4];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node->id(), 'de');
     $this->assertParagraphsButtons(3);
-    $this->drupalPostForm(NULL, NULL, t('Save (this translation)'));
+    $this->submitForm([], 'Save (this translation)');
     // Check the original node and the paragraphs langcode are now 'en'.
     $this->assertParagraphsLangcode($node->id());
   }
@@ -674,13 +682,13 @@ public function testParagraphTranslationMultilingual() {
   public function testParagraphsMultilingualWorkflow() {
     // Case 1: Check the paragraphs buttons after changing the NODE language
     // (original node langcode in GERMAN, default site langcode in english).
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('node.paragraphed_content_demo.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
       ]);
     $form_display->save();
-    // Use the experimental widget.
+    // Use the stable widget.
     $form_display = EntityFormDisplay::load('paragraph.nested_paragraph.default')
       ->setComponent('field_paragraphs_demo', [
         'type' => 'paragraphs',
@@ -695,25 +703,25 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in german',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Add nested_paragraph'));
+    $this->submitForm($edit, 'Add nested_paragraph');
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in german');
     $node1 = $this->getNodeByTitle('Title in german');
 
     // Check the paragraph langcode is 'de' and its buttons are displayed.
     // @todo check for the nested children paragraphs buttons and langcode
     // when it's supported.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'english' and upload another image.
@@ -723,16 +731,16 @@ public function testParagraphsMultilingualWorkflow() {
       'langcode[0][value]' => 'en',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_1][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     // Check the paragraph langcode is still 'de' and its buttons are shown.
     $this->assertParagraphsLangcode($node1->id(), 'de');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraph langcode is now 'en' after saving.
     $this->assertParagraphsLangcode($node1->id());
 
     // Check the paragraph langcode is 'en' and its buttons are still shown.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node1->id());
     $this->assertParagraphsButtons(1);
 
@@ -744,27 +752,27 @@ public function testParagraphsMultilingualWorkflow() {
     // Check that the node langcode is 'english' and add a 'Nested Paragraph'.
     $option_field = $this->assertSession()->optionExists('edit-langcode-0-value', 'en');
     $this->assertTrue($option_field->hasAttribute('selected'));
-    $this->drupalPostForm(NULL, NULL, t('Add nested_paragraph'));
+    $this->submitForm([], 'Add nested_paragraph');
     // Check that the paragraphs buttons are displayed and add an 'Images'
     // paragraph inside the nested paragraph.
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_0_subform_field_paragraphs_demo_images_add_more');
     // Upload an image and check the paragraphs buttons are still displayed.
     $images = $this->getTestFiles('image')[0];
     $edit = [
       'title[0][value]' => 'Title in english',
       'files[field_paragraphs_demo_0_subform_field_paragraphs_demo_0_subform_field_images_demo_0][]' => $images->uri,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Upload'));
+    $this->submitForm($edit, 'Upload');
     $this->assertParagraphsButtons(1);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('Title in english');
     $node2 = $this->drupalGetNodeByTitle('Title in english');
 
     // Check the paragraph langcode is 'en' and its buttons are displayed.
     // @todo check for the nested children paragraphs buttons and langcode
     // when it's supported.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(1);
     // Change the node langcode to 'german' and add another 'Images' paragraph.
@@ -772,29 +780,29 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[1];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_1_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are now 'de' after saving.
     $this->assertParagraphsLangcode($node2->id(), 'de');
 
     // Change node langcode back to 'english' and save.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $edit = [
       'title[0][value]' => 'Title in english',
       'langcode[0][value]' => 'en',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Check the paragraphs langcode are now 'en' after saving.
     $this->assertParagraphsLangcode($node2->id());
 
@@ -804,7 +812,8 @@ public function testParagraphsMultilingualWorkflow() {
     $edit = [
       'site_default_language' => 'de',
     ];
-    $this->drupalPostForm('admin/config/regional/language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/language');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check the original node and the paragraphs langcode are still 'en' and
     // check that the paragraphs buttons are still displayed.
@@ -812,24 +821,24 @@ public function testParagraphsMultilingualWorkflow() {
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(2);
     // Add another 'Images' paragraph with node langcode as 'english'.
-    $this->drupalPostForm(NULL, NULL, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm([], 'field_paragraphs_demo_images_add_more');
     // Check the paragraph langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[2];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_2_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are still 'en' after saving.
     $this->assertParagraphsLangcode($node2->id());
 
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
-    $this->clickLink(t('Edit'));
+    $this->clickLink('Edit');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(3);
     // Change node langcode to 'german' and add another 'Images' paragraph.
@@ -837,19 +846,19 @@ public function testParagraphsMultilingualWorkflow() {
       'title[0][value]' => 'Title in english (de)',
       'langcode[0][value]' => 'de',
     ];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_demo_images_add_more');
+    $this->submitForm($edit, 'field_paragraphs_demo_images_add_more');
     // Check the paragraphs langcode are still 'en' and their buttons are shown.
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
     // Upload an image, check the paragraphs langcode are still 'en' and their
     // buttons are displayed.
     $images = $this->getTestFiles('image')[3];
-    $this->drupalPostForm(NULL, [
+    $this->submitForm([
       'files[field_paragraphs_demo_3_subform_field_images_demo_0][]' => $images->uri,
-    ], t('Upload'));
+    ], 'Upload');
     $this->assertParagraphsLangcode($node2->id());
     $this->assertParagraphsButtons(4);
-    $this->drupalPostForm(NULL, NULL, t('Save'));
+    $this->submitForm([], 'Save');
     // Check the paragraphs langcode are now 'de' after saving.
     $this->assertParagraphsLangcode($node2->id(), 'de');
   }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationsTest.php
similarity index 95%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationsTest.php
index 13a6774296..75ef6f6be6 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTranslationsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTranslationsTest.php
@@ -1,8 +1,9 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsLastEntityQueryTrait;
 
 /**
@@ -10,16 +11,16 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalTranslationsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsTranslationsTest extends ParagraphsTestBase {
 
-  use ParagraphsLastEntityQueryTrait;
+  use ParagraphsLastEntityQueryTrait, ParagraphsCoreVersionUiTestTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -40,13 +41,9 @@ class ParagraphsExperimentalTranslationsTest extends ParagraphsExperimentalTestB
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
     $this->addParagraphedContentType('paragraphed_test', 'field_paragraphs', 'paragraphs');
 
@@ -104,7 +101,7 @@ protected function setUp() {
       'settings[paragraph][text_untranslatable_hide][fields][field_text_untranslatable_hide]' => FALSE,
       'settings[paragraph][container][fields][field_paragraphs]' => FALSE,
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTypesTest.php
similarity index 78%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTypesTest.php
index ceee3ba906..1446524335 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalTypesTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsTypesTest.php
@@ -1,13 +1,13 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 /**
  * Tests paragraphs types.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalTypesTest extends ParagraphsExperimentalTestBase {
+class ParagraphsTypesTest extends ParagraphsTestBase {
 
   /**
    * Tests the deletion of Paragraphs types.
@@ -22,26 +22,26 @@ public function testRemoveTypesWithContent() {
 
     // Attempt to delete the content type not used yet.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Delete'));
+    $this->clickLink('Delete');
     $this->assertSession()->pageTextContains('This action cannot be undone.');
-    $this->clickLink(t('Cancel'));
+    $this->clickLink('Cancel');
 
     // Add a test node with a Paragraph.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
+    $this->submitForm([], 'paragraphs_paragraph_type_test_add_more');
     $edit = ['title[0][value]' => 'test_node'];
     $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']);
     $this->assertEquals(1, count($table_rows));
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test test_node has been created.');
 
     // Attempt to delete the paragraph type already used.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Delete'));
+    $this->clickLink('Delete');
     $this->assertSession()->pageTextContains('paragraph_type_test Paragraphs type is used by 1 piece of content on your site. You can not remove this paragraph_type_test Paragraphs type until you have removed all from the content.');
 
     // Delete all entities of that Paragraph type.
-    $this->drupalPostForm(NULL, [], t('Delete existing Paragraph'));
+    $this->submitForm([], 'Delete existing Paragraph');
     $this->assertSession()->pageTextContains('Entity is successfully deleted.');
     $node = $this->drupalGetNodeByTitle('test_node');
     $this->drupalGet('node/' . $node->id() . '/edit');
@@ -49,22 +49,22 @@ public function testRemoveTypesWithContent() {
     $this->assertEquals(0, count($table_rows));
 
     // @todo Remove this when https://www.drupal.org/node/2846549 is resolved.
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
 
     // Add two different Paragraphs to the node.
-    $this->drupalPostForm(NULL, [], 'paragraphs_paragraph_type_test_add_more');
-    $this->drupalPostForm(NULL, [], 'paragraphs_text_add_more');
+    $this->submitForm([], 'paragraphs_paragraph_type_test_add_more');
+    $this->submitForm([], 'paragraphs_text_add_more');
     $table_rows = $this->xpath('//table[contains(@class, :class)]/tbody/tr', [':class' => 'field-multiple-table']);
     $this->assertEquals(2, count($table_rows));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     // Attempt to delete the Paragraph type.
     $this->drupalGet('admin/structure/paragraphs_type');
-    $this->clickLink(t('Delete'));
+    $this->clickLink('Delete');
     $this->assertSession()->pageTextContains('paragraph_type_test Paragraphs type is used by 1 piece of content on your site. You can not remove this paragraph_type_test Paragraphs type until you have removed all from the content.');
-    $this->drupalPostForm(NULL, [], t('Delete existing Paragraph'));
+    $this->submitForm([], 'Delete existing Paragraph');
     $this->assertSession()->pageTextContains('Entity is successfully deleted.');
-    $this->drupalPostForm(NULL, [], t('Delete'));
+    $this->submitForm([], 'Delete');
     // Check that the Paragraph of the deleted type is removed and the rest
     // remains.
     $node = $this->drupalGetNodeByTitle('test_node');
@@ -88,10 +88,10 @@ public function testCreateParagraphType() {
       'label' => 'Test',
       'id' => 'test_name_with_more_than_32_characters'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save and manage fields');
+    $this->submitForm($edit, 'Save and manage fields');
     $this->assertSession()->pageTextContains('Machine-readable name cannot be longer than 32 characters but is currently 38 characters long.');
     $edit['id'] = 'new_test_id';
-    $this->drupalPostForm(NULL, $edit, 'Save and manage fields');
+    $this->submitForm($edit, 'Save and manage fields');
     $this->assertSession()->pageTextContains('Saved the Test Paragraphs type.');
   }
 }
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsUiTest.php
similarity index 82%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsUiTest.php
index 066007d473..bfcac0a82f 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalUiTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsUiTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 
@@ -9,12 +9,12 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
+class ParagraphsUiTest extends ParagraphsTestBase {
 
   /**
    * {@inheritdoc}
    */
-  public static $modules = array(
+  protected static $modules = array(
     'content_translation',
     'image',
     'field',
@@ -27,7 +27,7 @@ class ParagraphsExperimentalUiTest extends ParagraphsExperimentalTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     ConfigurableLanguage::create(['id' => 'de', 'label' => '1German'])->save();
     ConfigurableLanguage::create(['id' => 'fr', 'label' => '2French'])->save();
@@ -62,7 +62,8 @@ protected function setUp() {
       'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
       'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
   }
 
   /**
@@ -90,33 +91,34 @@ public function testEmptyRequiredField() {
     $form_display_edit = [
       'fields[field_content][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm($bundle_path . '/form-display', $form_display_edit, t('Save'));
+    $this->drupalGet($bundle_path . '/form-display');
+    $this->submitForm($form_display_edit, 'Save');
 
     // Attempt to create a paragraphed node with an empty required field.
     $title = 'Empty';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->submitForm(['title[0][value]' => $title], 'Save');
     $this->assertSession()->pageTextContains($field_title . ' field is required');
 
     // Attempt to create a paragraphed node with only a paragraph in the
     // "remove" mode in the required field.
     $title = 'Remove all items';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostForm(NULL, [], 'field_content_0_remove');
+    $this->submitForm([], 'field_content_text_image_add_more');
+    $this->submitForm([], 'field_content_0_remove');
     $this->assertSession()->pageTextNotContains($field_title . ' field is required');
-    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->submitForm(['title[0][value]' => $title], 'Save');
     $this->assertSession()->pageTextContains($field_title . ' field is required');
 
     // Attempt to create a paragraphed node with a valid paragraph and a
     // removed paragraph.
     $title = 'Valid Removal';
     $this->drupalGet('node/add/paragraphed_content_demo');
-    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostForm(NULL, [], 'field_content_text_image_add_more');
-    $this->drupalPostForm(NULL, [], 'field_content_1_remove');
+    $this->submitForm([], 'field_content_text_image_add_more');
+    $this->submitForm([], 'field_content_text_image_add_more');
+    $this->submitForm([], 'field_content_1_remove');
     $this->assertSession()->pageTextNotContains($field_title . ' field is required');
-    $this->drupalPostForm(NULL, ['title[0][value]' => $title], t('Save'));
+    $this->submitForm(['title[0][value]' => $title], 'Save');
     $this->assertSession()->pageTextNotContains($field_title . ' field is required');
   }
 
diff --git a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsWidgetButtonsTest.php
similarity index 84%
rename from web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
rename to web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsWidgetButtonsTest.php
index 989c0dd87d..3c0fb53547 100644
--- a/web/modules/paragraphs/tests/src/Functional/Experimental/ParagraphsExperimentalWidgetButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/Functional/WidgetStable/ParagraphsWidgetButtonsTest.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\Tests\paragraphs\Functional\Experimental;
+namespace Drupal\Tests\paragraphs\Functional\WidgetStable;
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\paragraphs\FunctionalJavascript\ParagraphsTestBaseTrait;
@@ -9,11 +9,11 @@
 use Drupal\node\Entity\NodeType;
 
 /**
- * Tests paragraphs experimental widget buttons.
+ * Tests paragraphs stable widget buttons.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTestBase {
+class ParagraphsWidgetButtonsTest extends ParagraphsTestBase {
 
   use ParagraphsTestBaseTrait;
 
@@ -22,7 +22,7 @@ class ParagraphsExperimentalWidgetButtonsTest extends ParagraphsExperimentalTest
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs_test',
     'language',
     'content_translation',
@@ -45,8 +45,10 @@ public function testWidgetButtons() {
     $edit = [
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save'));
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
+    $this->submitForm($edit, 'Save');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -54,33 +56,33 @@ public function testWidgetButtons() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     // Test the 'Open' edit mode.
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains($text);
 
     // Test the 'Closed' edit mode.
     $this->setParagraphsWidgetMode('paragraphed_test', 'field_paragraphs', 'closed');
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_1_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_1_edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $text);
     $closed_mode_text = 'closed_mode_text';
     // Click "Collapse" button on both paragraphs.
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     $edit = ['field_paragraphs[1][subform][field_text][0][value]' => $closed_mode_text];
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_1_collapse');
+    $this->submitForm($edit, 'field_paragraphs_1_collapse');
     // Verify that we have warning message for each paragraph.
     $this->assertEquals(2, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]")));
     $this->assertSession()->responseContains('<span class="summary-content">' . $closed_mode_text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextContains($closed_mode_text);
 
@@ -88,24 +90,24 @@ public function testWidgetButtons() {
     $this->setParagraphsWidgetSettings('paragraphed_test', 'field_paragraphs', ['closed_mode' => 'preview']);
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Edit" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_edit');
+    $this->submitForm([], 'field_paragraphs_0_edit');
     $this->assertSession()->fieldValueEquals('field_paragraphs[0][subform][field_text][0][value]', $closed_mode_text);
     $preview_mode_text = 'preview_mode_text';
     $edit = ['field_paragraphs[0][subform][field_text][0][value]' => $preview_mode_text];
     // Click "Collapse" button.
-    $this->drupalPostForm(NULL, $edit, 'field_paragraphs_0_collapse');
+    $this->submitForm($edit, 'field_paragraphs_0_collapse');
     $this->assertSession()->pageTextContains('You have unsaved changes on this Paragraph item.');
     $this->assertEquals(1, count($this->xpath("//*[contains(@class, 'paragraphs-icon-changed')]")));
     $this->assertSession()->pageTextContains($preview_mode_text);
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextContains($preview_mode_text);
 
     // Test the remove function.
     $this->drupalGet('node/' . $node->id() . '/edit');
     // Click "Remove" button.
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_0_remove');
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'field_paragraphs_0_remove');
+    $this->submitForm([], 'Save');
     $this->assertSession()->pageTextContains('paragraphed_test ' . $node->label() . ' has been updated.');
     $this->assertSession()->pageTextNotContains($preview_mode_text);
   }
@@ -134,8 +136,10 @@ public function testButtonsVisibility() {
     $edit = [
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save'));
-    $this->drupalPostForm('node/add/paragraphed_test', [], 'field_paragraphs_text_paragraph_add_more');
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
+    $this->submitForm($edit, 'Save');
+    $this->drupalGet('node/add/paragraphed_test');
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
 
     // Create a node with a Paragraph.
     $text = 'recognizable_text';
@@ -143,8 +147,8 @@ public function testButtonsVisibility() {
       'title[0][value]' => 'paragraphs_mode_test',
       'field_paragraphs[0][subform][field_text][0][value]' => $text,
     ];
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_text_paragraph_add_more');
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm([], 'field_paragraphs_text_paragraph_add_more');
+    $this->submitForm($edit, 'Save');
     $node = $this->drupalGetNodeByTitle('paragraphs_mode_test');
 
     // Checking visible buttons on "Open" mode.
@@ -177,21 +181,21 @@ public function testButtonsVisibility() {
     $edit = [
       'fields[field_nested][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $node->id() . '/edit');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_nested_paragraph_add_more');
-    $this->drupalPostForm(NULL, [], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_nested_paragraph_add_more');
+    $this->submitForm([], 'field_paragraphs_2_subform_field_nested_nested_paragraph_add_more');
     // Collapse is present on each nesting level.
     $this->assertSession()->buttonExists('field_paragraphs_2_collapse');
     $this->assertSession()->buttonExists('field_paragraphs_2_subform_field_nested_0_collapse');
 
     // Tests hook_paragraphs_widget_actions_alter.
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->buttonNotExists('edit-field-paragraphs-0-top-links-test-button');
     \Drupal::state()->set('paragraphs_test_dropbutton', TRUE);
     $this->drupalGet('node/add/paragraphed_test');
-    $this->drupalPostForm(NULL, NULL, t('Add text'));
+    $this->submitForm([], 'Add text');
     $this->assertSession()->buttonNotExists('edit-field-paragraphs-0-top-links-test-button');
 
     ConfigurableLanguage::createFromLangcode('sr')->save();
@@ -202,7 +206,7 @@ public function testButtonsVisibility() {
       'entity_types[node]' => TRUE,
       'settings[node][paragraphed_test][translatable]' => TRUE,
     ];
-    $this->drupalPostForm(NULL, $edit, 'Save configuration');
+    $this->submitForm($edit, 'Save configuration');
 
     // Check that operation is hidden during translation.
     $this->drupalGet('sr/node/' . $node->id() . '/translations/add/en/sr');
@@ -283,7 +287,8 @@ public function testButtonsVisibilityException() {
     $edit = [
       'fields[field_paragraphs][type]' => 'paragraphs',
     ];
-    $this->drupalPostForm('admin/structure/types/manage/paragraphed_test/form-display', $edit, t('Save'));
+    $this->drupalGet('admin/structure/types/manage/paragraphed_test/form-display');
+    $this->submitForm($edit, 'Save');
 
     // Checking hidden button on "Open" mode.
     $this->drupalGet('node/add/paragraphed_test');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/LoginAdminTrait.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/LoginAdminTrait.php
index baf3032012..6ddd332c10 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/LoginAdminTrait.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/LoginAdminTrait.php
@@ -28,6 +28,7 @@ public function loginAsAdmin($additional_permissions = [], $reset_permissions =
       'administer node form display',
       'administer paragraph fields',
       'administer paragraph form display',
+      'bypass node access',
     ];
 
     if ($reset_permissions) {
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php
similarity index 94%
rename from web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php
rename to web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php
index 55244887a0..0327df745d 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalAddWidgetTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php
@@ -12,7 +12,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalAddWidgetTest extends WebDriverTestBase {
+class ParagraphsAddWidgetTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use FieldUiTestTrait;
@@ -24,7 +24,7 @@ class ParagraphsExperimentalAddWidgetTest extends WebDriverTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -42,14 +42,9 @@ class ParagraphsExperimentalAddWidgetTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp()
-  {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
 
   }
 
@@ -73,10 +68,10 @@ public function testAddWidgetButton() {
       'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
       'fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'modal'
     ];
-    $this->drupalPostForm(NULL, $edit, 'Update');
+    $this->submitForm($edit, 'Update');
     $this->assertSession()->assertWaitOnAjaxRequest();
 
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     // Add a Paragraph type.
     $paragraph_type = 'text_paragraph';
@@ -149,7 +144,7 @@ public function testAddWidgetButton() {
     $edit = [
       'title[0][value]' => 'Example title',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
 
     // Check the created paragraphed test.
     $this->assertSession()->pageTextContainsOnce('paragraphed_test Example title has been created.');
@@ -202,9 +197,9 @@ public function testModalAddWidgetDelta() {
       'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
       'fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'modal',
     ];
-    $this->drupalPostForm(NULL, $edit, 'Update');
+    $this->submitForm($edit, 'Update');
     $this->assertSession()->assertWaitOnAjaxRequest();
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     // Add a Paragraph types.
     $this->addParagraphsType('test_1');
@@ -267,7 +262,7 @@ public function testModalAddWidgetDelta() {
     //
     // This case covers full execution of
     // ParagraphsWidget::prepareDeltaPosition() when list is empty.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val(-100)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val(-100)");
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_nested")]')->click();
@@ -281,7 +276,7 @@ public function testModalAddWidgetDelta() {
     // paragraph respectively.
     //
     // Add 2 additional paragraphs in base field.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val('')");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val('')");
     for ($i = 1; $i <= 2; $i++) {
       $page->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')->click();
       $this->assertSession()->assertWaitOnAjaxRequest();
@@ -295,7 +290,7 @@ public function testModalAddWidgetDelta() {
     $this->assertEquals('test_2', $base_paragraphs[2]->getText(), 'Last paragraph should be type "test_2".');
 
     // Add new paragraph to 1st position - set delta to 0 for base paragraphs.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val(0)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val(0)");
     $page->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')->click();
@@ -307,7 +302,7 @@ public function testModalAddWidgetDelta() {
     $this->assertEquals('test_3', $base_paragraphs[0]->getText(), '1st paragraph should be type "test_3".');
 
     // Add new paragraph to 3rd position - set delta to 2 for base paragraphs.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val(2)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val(2)");
     $page->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->click();
@@ -319,7 +314,7 @@ public function testModalAddWidgetDelta() {
     $this->assertEquals('test_2', $base_paragraphs[2]->getText(), '3rd paragraph should be type "test_2".');
 
     // Add new paragraph to last position - using really big delta.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val(1000)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val(1000)");
     $page->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')->click();
@@ -331,7 +326,7 @@ public function testModalAddWidgetDelta() {
     $this->assertEquals('test_1', $base_paragraphs[5]->getText(), 'Last paragraph should be type "test_1".');
 
     // Clear delta base paragraphs.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').last().val('')");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').last().val('')");
     $page->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')->click();
@@ -376,28 +371,28 @@ public function testModalAddWidgetDelta() {
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Add new paragraph to first position.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(0)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').first().val(0)");
     $page->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Add new paragraph to 2nd position - using float value for index.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(1.1111)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').first().val(1.1111)");
     $page->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Add new paragraph to first position - using negative index.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(-100)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').first().val(-100)");
     $page->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
 
     // Add new paragraph to last position - using some text as position.
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val('some_text')");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').first().val('some_text')");
     $page->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')->click();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $page->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')->click();
@@ -430,9 +425,9 @@ public function testModalAddWidgetDelta() {
     $this->assertSession()->assertWaitOnAjaxRequest();
     // Attempt to add a new Paragraph above and cancel.
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
-    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-modal-delta').first().val(0)");
+    $this->getSession()->executeScript("jQuery('input.paragraph-type-add-delta').first().val(0)");
     $this->assertSession()->elementExists('css', '.ui-dialog-titlebar-close')->press();
-    $delta = $this->getSession()->evaluateScript("jQuery('paragraph-type-add-modal-delta').val()");
+    $delta = $this->getSession()->evaluateScript("jQuery('.paragraph-type-add-delta').val()");
     $this->assertEquals($delta, '');
     // Add a new Paragraph with the Add button at the bottom.
     $page->find('xpath', '//*[@name="button_add_modal"]')->click();
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsClientsideButtonsTest.php
similarity index 89%
rename from web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php
rename to web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsClientsideButtonsTest.php
index 1ca60d565f..ad994ea016 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalClientsideButtonsTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsClientsideButtonsTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\paragraphs\FunctionalJavascript;
 
+use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\Tests\field_ui\Traits\FieldUiTestTrait;
 use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
@@ -12,7 +13,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalClientsideButtonsTest extends WebDriverTestBase {
+class ParagraphsClientsideButtonsTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use FieldUiTestTrait;
@@ -23,7 +24,7 @@ class ParagraphsExperimentalClientsideButtonsTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -41,13 +42,9 @@ class ParagraphsExperimentalClientsideButtonsTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
-    // Place the breadcrumb, tested in fieldUIAddNewField().
-    $this->drupalPlaceBlock('system_breadcrumb_block');
-    $this->drupalPlaceBlock('local_tasks_block');
-    $this->drupalPlaceBlock('local_actions_block');
-    $this->drupalPlaceBlock('page_title_block');
+    $this->placeDefaultBlocks();
   }
 
   /**
@@ -117,6 +114,8 @@ public function testAddParagraphAboveButton() {
     $dialog->pressButton('text');
     $assert_session->assertWaitOnAjaxRequest();
     $session->wait(2000);
+    // Check that the add above button has the button--small class.
+    $page->find('xpath', '//input[@class="paragraphs-dropdown-action paragraphs-dropdown-action--add-above button button--small js-form-submit form-submit"]');
     // At this point we should have 3 injected "Add above" buttons.
     $all_add_above_buttons = $page->findAll('css', '#edit-field-paragraphs-wrapper input.paragraphs-dropdown-action--add-above');
     $this->assertEquals(3, count($all_add_above_buttons));
@@ -128,7 +127,7 @@ public function testAddParagraphAboveButton() {
       'field_paragraphs[1][subform][field_text][0][value]' => 'Second text',
       'field_paragraphs[2][subform][field_text][0][value]' => 'Third text',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $node_id = $this->getLastEntityOfType('node');
 
     // Make sure we honor the widget settings when injecting the button.
@@ -269,7 +268,31 @@ public function testAddParagraphAboveButton() {
     $dialog->pressButton('text');
     $assert_session->assertWaitOnAjaxRequest();
 
-    // 5 paragraphs, we expect 5 injected buttons.
+    // 5 paragraphs, we expect 4 injected buttons as the cardinality of the
+    // nested paragraph is one and we cannot Add Above.
+    $all_add_above_buttons = $page->findAll('css', '#edit-field-paragraphs-wrapper input.paragraphs-dropdown-action--add-above');
+    $this->assertEquals(4, count($all_add_above_buttons));
+
+    // Remove the new added Paragraph.
+    $rich_paragraph_row = $assert_session->elementExists('css', '#field-paragraphs-add-more-wrapper tr:nth-of-type(2) .field--name-field-nested-paragraphs tr.draggable');
+    $dropdown = $assert_session->elementExists('css', '.paragraphs-dropdown', $rich_paragraph_row);
+    $dropdown->click();
+    $remove_button = $assert_session->buttonExists('field_paragraphs_3_subform_field_nested_paragraphs_0_remove');
+    $remove_button->click();
+    $assert_session->assertWaitOnAjaxRequest();
+    // Set the config to allow more than one Paragraph.
+    $field_storage = FieldStorageConfig::loadByName('paragraph', 'field_nested_paragraphs');
+    $field_storage->setCardinality(-1);
+    $field_storage->save();
+    // Add the Paragraph back.
+    $add_paragraph_rich_row->click();
+    $assert_session->assertWaitOnAjaxRequest();
+    $dialog = $page->find('xpath', '//div[contains(@class, "ui-dialog")]');
+    $dialog->pressButton('text');
+    $assert_session->assertWaitOnAjaxRequest();
+
+    // 5 paragraphs, we expect 5 injected buttons as the cardinality of the
+    // nested paragraph is unlimited.
     $all_add_above_buttons = $page->findAll('css', '#edit-field-paragraphs-wrapper input.paragraphs-dropdown-action--add-above');
     $this->assertEquals(5, count($all_add_above_buttons));
 
@@ -297,7 +320,7 @@ public function testAddParagraphAboveButton() {
     // We have one more injected add_more button.
     $all_add_above_buttons = $page->findAll('css', '#edit-field-paragraphs-wrapper input.paragraphs-dropdown-action--add-above');
     $this->assertEquals(6, count($all_add_above_buttons));
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
 
     $this->drupalGet("/node/{$node_id}/edit");
     $edit_all_button = $assert_session->buttonExists('field_paragraphs_edit_all');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsStableEditPerspectivesUiTest.php
similarity index 95%
rename from web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php
rename to web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsStableEditPerspectivesUiTest.php
index f6217e53c0..e712e20980 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalEditPerspectivesUiTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsStableEditPerspectivesUiTest.php
@@ -5,23 +5,25 @@
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
 use Drupal\paragraphs\Entity\ParagraphsType;
+use Drupal\Tests\paragraphs\Traits\ParagraphsCoreVersionUiTestTrait;
 
 /**
  * Test paragraphs user interface.
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalEditPerspectivesUiTest extends WebDriverTestBase {
+class ParagraphsStableEditPerspectivesUiTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use ParagraphsTestBaseTrait;
+  use ParagraphsCoreVersionUiTestTrait;
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs_test',
     'paragraphs',
@@ -40,8 +42,9 @@ class ParagraphsExperimentalEditPerspectivesUiTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
+    $this->placeDefaultBlocks();
   }
 
   /**
@@ -72,7 +75,7 @@ public function testEditPerspectives() {
     $this->assertFalse($style_selector->isVisible());
 
     // Assert scroll position when switching tabs.
-    $this->getSession()->resizeWindow(800, 500);
+    $this->getSession()->resizeWindow(800, 450);
     $this->drupalGet('node/add/testcontent');
     $button = $this->getSession ()->getPage()->findButton('Add TestPlugin');
     $button->press();
@@ -202,12 +205,12 @@ public function testTabsVisibility() {
     $edit = [
       'settings[target_type]' => 'paragraph',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save field settings'));
-    $this->drupalPostForm(NULL, NULL, t('Save settings'));
+    $this->submitForm($edit, 'Save field settings');
+    $this->submitForm([], 'Save settings');
     $this->drupalGet('admin/structure/types/manage/testcontent/form-display');
     $page->selectFieldOption('fields[field_testparagraphfield][type]', 'paragraphs');
     $this->assertSession()->assertWaitOnAjaxRequest();
-    $this->drupalPostForm(NULL, [], t('Save'));
+    $this->submitForm([], 'Save');
     $this->drupalGet('node/add/testcontent');
     $style_selector = $page->find('css', '.paragraphs-tabs');
     $this->assertFalse($style_selector->isVisible());
@@ -228,7 +231,8 @@ public function testPerspectivesWithMultipleFields() {
     $edit = [
       'behavior_plugins[test_bold_text][enabled]' => TRUE,
     ];
-    $this->drupalPostForm('admin/structure/paragraphs_type/' . $paragraph_type, $edit, t('Save'));
+    $this->drupalGet('admin/structure/paragraphs_type/' . $paragraph_type);
+    $this->submitForm($edit, 'Save');
 
     $this->addParagraphedContentType('testcontent');
     $this->addParagraphsField('testcontent', 'field_paragraphs2', 'node');
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
index e872e300bc..f6f19db640 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsTestBaseTrait.php
@@ -33,9 +33,9 @@ trait ParagraphsTestBaseTrait {
    * @param string $paragraphs_field_name
    *   (optional) Field name to be used. Defaults to 'field_paragraphs'.
    * @param string $widget_type
-   *   (optional) Declares if we use experimental or classic widget.
-   *   Defaults to 'paragraphs' for experimental widget.
-   *   Use 'entity_reference_paragraphs' for classic widget.
+   *   (optional) Declares if we use stable or legacy widget.
+   *   Defaults to 'paragraphs' for stable widget.
+   *   Use 'entity_reference_paragraphs' for legacy widget.
    */
   protected function addParagraphedContentType($content_type_name, $paragraphs_field_name = 'field_paragraphs', $widget_type = 'paragraphs') {
     // Create the content type.
@@ -58,9 +58,9 @@ protected function addParagraphedContentType($content_type_name, $paragraphs_fie
    * @param string $entity_type
    *   Entity type where to add the field.
    * @param string $widget_type
-   *   (optional) Declares if we use experimental or classic widget.
-   *   Defaults to 'paragraphs' for experimental widget.
-   *   Use 'entity_reference_paragraphs' for classic widget.
+   *   (optional) Declares if we use stable or legacy widget.
+   *   Defaults to 'paragraphs' for stable widget.
+   *   Use 'entity_reference_paragraphs' for legacy widget.
    */
   protected function addParagraphsField($bundle, $paragraphs_field_name, $entity_type, $widget_type = 'paragraphs') {
     $field_storage = FieldStorageConfig::loadByName($entity_type, $paragraphs_field_name);
@@ -209,7 +209,7 @@ protected function setParagraphsWidgetSettings($bundle, $paragraphs_field, array
     $component = $default_form_display->getComponent($paragraphs_field);
 
     $updated_component = $component;
-    if ($field_widget === NULL || $field_widget === $component['type']) {
+    if ($field_widget === NULL || (isset($component['type']) && $field_widget === $component['type'])) {
       // The widget stays the same.
       $updated_component['settings'] = $settings + $component['settings'];
     }
diff --git a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsWidgetElementsTest.php
similarity index 91%
rename from web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php
rename to web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsWidgetElementsTest.php
index 2e9e7efac1..5875c39785 100644
--- a/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsExperimentalWidgetElementsTest.php
+++ b/web/modules/paragraphs/tests/src/FunctionalJavascript/ParagraphsWidgetElementsTest.php
@@ -10,7 +10,7 @@
  *
  * @group paragraphs
  */
-class ParagraphsExperimentalWidgetElementsTest extends WebDriverTestBase {
+class ParagraphsWidgetElementsTest extends WebDriverTestBase {
 
   use LoginAdminTrait;
   use ParagraphsTestBaseTrait;
@@ -20,7 +20,7 @@ class ParagraphsExperimentalWidgetElementsTest extends WebDriverTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'paragraphs',
     'field',
@@ -61,7 +61,8 @@ public function testDragHandler() {
       'settings[paragraph][text][translatable]' => TRUE,
       'settings[paragraph][text][settings][language][language_alterable]' => TRUE,
     ];
-    $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
+    $this->drupalGet('admin/config/regional/content-language');
+    $this->submitForm($edit, 'Save configuration');
     $settings = [
       'add_mode' => 'modal',
     ];
@@ -81,7 +82,7 @@ public function testDragHandler() {
       'title[0][value]' => 'Title',
       'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'First',
     ];
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     // Translate the node.
     $node = $this->getNodeByTitle('Title');
     $this->drupalGet('node/' . $node->id() . '/translations/add/en/sr');
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
index 9dc7e00163..eec1a1aec8 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsAccessTest.php
@@ -17,7 +17,7 @@ class ParagraphsAccessTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
   ];
 
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
index 7d2508c9c1..b9ecc2e6f5 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsBehaviorPluginsTest.php
@@ -18,7 +18,7 @@ class ParagraphsBehaviorPluginsTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'user',
     'system',
@@ -31,7 +31,7 @@ class ParagraphsBehaviorPluginsTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installEntitySchema('user');
     $this->installEntitySchema('paragraph');
@@ -87,6 +87,17 @@ public function testBehaviorSettings() {
     $plugin = $paragraph->getParagraphType()->getBehaviorPlugins()->getEnabled();
     $this->assertEquals($plugin['test_text_color']->settingsSummary($paragraph)[0], ['label' => 'Text color', 'value' => 'blue']);
 
+    // Settings another behavior settings should retain the original behaviors
+    // from another plugin.
+    \Drupal::entityTypeManager()->getStorage('paragraph')->resetCache();
+    $paragraph = Paragraph::load($paragraph->id());
+    $paragraph->setBehaviorSettings('test_another_id', ['foo' => 'bar']);
+    $paragraph->save();
+
+    $paragraph = Paragraph::load($paragraph->id());
+    $settings = $paragraph->getAllBehaviorSettings();
+    $this->assertArrayHasKey('test_text_color', $settings);
+    $this->assertArrayHasKey('test_another_id', $settings);
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
index 93be4840af..6b926c939c 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCollapsedSummaryTest.php
@@ -27,12 +27,11 @@ class ParagraphsCollapsedSummaryTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'user',
     'system',
     'field',
-    'entity_reference',
     'entity_reference_revisions',
     'paragraphs_test',
     'file',
@@ -41,7 +40,7 @@ class ParagraphsCollapsedSummaryTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installEntitySchema('user');
     $this->installEntitySchema('paragraph');
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
index 4be7c37a80..72bc9c5d9a 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsCompositeRelationshipTest.php
@@ -25,7 +25,7 @@ class ParagraphsCompositeRelationshipTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'paragraphs',
     'node',
     'user',
@@ -39,7 +39,7 @@ class ParagraphsCompositeRelationshipTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs and article content types.
     $values = ['type' => 'article', 'name' => 'Article'];
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
index c4b7805737..aaf784a666 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsEntityMethodsTest.php
@@ -23,7 +23,7 @@ class ParagraphsEntityMethodsTest extends KernelTestBase {
    *
    * @var string[]
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'node',
     'user',
@@ -36,7 +36,7 @@ class ParagraphsEntityMethodsTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installEntitySchema('user');
     $this->installEntitySchema('node');
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
index b8a9e21ae2..7c4bc8b672 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsIsChangedTest.php
@@ -18,7 +18,7 @@ class ParagraphsIsChangedTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'user',
     'system',
@@ -30,7 +30,7 @@ class ParagraphsIsChangedTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installEntitySchema('user');
     $this->installEntitySchema('paragraph');
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsLangcodeChangeTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsLangcodeChangeTest.php
new file mode 100644
index 0000000000..3b3e6046dc
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsLangcodeChangeTest.php
@@ -0,0 +1,384 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Kernel;
+
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Form\FormState;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+use Drupal\language\Entity\ContentLanguageSettings;
+use Drupal\paragraphs_test\Form\TestEmbeddedEntityForm;
+
+/**
+ * Tests the langcode change mechanics of paragraphs.
+ *
+ * @group paragraphs
+ */
+class ParagraphsLangcodeChangeTest extends EntityKernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  protected static $modules = [
+    'user',
+    'system',
+    'field',
+    'text',
+    'filter',
+    'entity_test',
+    'paragraphs',
+    'paragraphs_test',
+    'entity_reference_revisions',
+    'node',
+    'language',
+    'file',
+  ];
+
+  /**
+   * The machine name of the node type.
+   *
+   * @var string
+   */
+  protected $nodeType = 'page';
+
+  /**
+   * The machine name of the node's paragraphs field.
+   *
+   * @var string
+   */
+  protected $nodeParagraphsFieldName = 'field_paragraphs';
+
+  /**
+   * The machine name of the paragraph type.
+   *
+   * @var string
+   */
+  protected $paragraphType = 'paragraph_type';
+
+  /**
+   * The current node.
+   *
+   * @var \Drupal\node\NodeInterface
+   */
+  protected $node;
+
+  /**
+   * The current paragraph.
+   *
+   * @var \Drupal\paragraphs\ParagraphInterface
+   */
+  protected $paragraph;
+
+  /**
+   * The array of the current form.
+   *
+   * @var array
+   */
+  protected $form;
+
+  /**
+   * The current form state.
+   *
+   * @var \Drupal\Core\Form\FormStateInterface
+   */
+  protected $formState;
+
+  /**
+   * The current form object.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityFormInterface
+   */
+  protected $formObject;
+
+  /**
+   * The current entity form display.
+   *
+   * @var \Drupal\Core\Entity\Entity\EntityFormDisplay
+   */
+  protected $formDisplay;
+
+  /**
+   * The current form builder.
+   *
+   * @var \Drupal\Core\Form\FormBuilderInterface
+   */
+  protected $formBuilder;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('file');
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('paragraph');
+
+    $this->installSchema('node', ['node_access']);
+
+    $this->installConfig(static::$modules);
+
+    $this->formBuilder = $this->container->get('form_builder');
+
+    // Activate Spanish language, so there are two languages activated.
+    $this->entityTypeManager->getStorage('configurable_language')->create([
+      'id' => 'es',
+    ])->save();
+
+    // Create a paragraph type.
+    $this->entityTypeManager->getStorage('paragraphs_type')->create([
+      'label' => 'Paragraph type',
+      'id' => $this->paragraphType,
+      'status' => TRUE,
+    ])->save();
+
+    // Create a node type.
+    $this->entityTypeManager->getStorage('node_type')->create([
+      'name' => 'Example page',
+      'type' => $this->nodeType,
+      'create_body' => FALSE,
+    ])->save();
+
+    // Enable translations on the node type and paragraph type.
+    ContentLanguageSettings::loadByEntityTypeBundle('node', $this->nodeType)
+      ->setLanguageAlterable(TRUE)
+      ->setDefaultLangcode('en')
+      ->save();
+    ContentLanguageSettings::loadByEntityTypeBundle('paragraph', $this->paragraphType)
+      ->setLanguageAlterable(TRUE)
+      ->setDefaultLangcode('en')
+      ->save();
+
+    // Create a field with paragraphs for the node type.
+    FieldStorageConfig::create([
+      'entity_type' => 'node',
+      'type' => 'entity_reference_revisions',
+      'field_name' => $this->nodeParagraphsFieldName,
+      'settings' => [
+        'target_type' => 'paragraph',
+      ],
+      'cardinality' => -1,
+      'translatable' => TRUE,
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => 'node',
+      'bundle' => $this->nodeType,
+      'field_name' => $this->nodeParagraphsFieldName,
+      'label' => $this->randomString(),
+      'settings' => [
+        'handler' => 'default:paragraph',
+        'handler_settings' => [
+          'negate' => 1,
+          'target_bundles' => NULL,
+          'target_bundles_drag_drop' => [
+            $this->paragraphType => [
+              'weight' => 0,
+              'enabled' => FALSE,
+            ],
+          ],
+        ],
+      ],
+    ])->save();
+
+    // Create the form display of the node type,
+    // with the language switcher enabled.
+    // The default autocomplete widget does not work properly
+    // within a kernel test. Thus, use a simple select list widget instead.
+    EntityFormDisplay::create([
+      'targetEntityType' => 'node',
+      'bundle' => $this->nodeType,
+      'mode' => 'default',
+      'status' => TRUE,
+    ])->setComponent('langcode', [
+      'type' => 'language_select',
+      'region' => 'content',
+      'weight' => 10,
+    ])->setComponent('uid', [
+      'type' => 'options_select',
+      'region' => 'content',
+      'weight' => 100,
+    ])->save();
+
+    $this->formDisplay = EntityFormDisplay::load('node.' . $this->nodeType . '.default');
+
+    $this->createUser(['uid' => 1, 'name' => 'user1'])->save();
+
+    $this->paragraph = $this->entityTypeManager->getStorage('paragraph')->create([
+      'type' => $this->paragraphType,
+    ]);
+
+    $this->node = $this->entityTypeManager->getStorage('node')->create([
+      'type' => $this->nodeType,
+      'title' => $this->randomString(),
+      'status' => TRUE,
+      'uid' => 1,
+      'langcode' => 'es',
+      $this->nodeParagraphsFieldName => [$this->paragraph],
+    ]);
+  }
+
+  /**
+   * Tests the langcode change within a node form using the legacy widget.
+   */
+  public function testChangeWithLegacyWidget() {
+    $this->doTestLangcodeChange(
+      [
+        'type' => 'entity_reference_paragraphs',
+        'weight' => 5,
+      ],
+      FALSE
+    );
+  }
+
+  /**
+   * Tests the langcode change within a node form using the stable widget.
+   */
+  public function testChangeWithStableWidget() {
+    $this->doTestLangcodeChange(
+      [
+        'type' => 'paragraphs',
+        'weight' => 15,
+      ],
+      FALSE
+    );
+  }
+
+  /**
+   * Tests langcode change within an embedded node form and the legacy widget.
+   */
+  public function testChangeWithEmbeddedLegacyWidget() {
+    $this->doTestLangcodeChange(
+      [
+        'type' => 'entity_reference_paragraphs',
+        'weight' => 5,
+      ],
+      TRUE
+    );
+  }
+
+  /**
+   * Tests langcode change within an embedded node form and the stable widget.
+   */
+  public function testChangeWithEmbeddedStableWidget() {
+    $this->doTestLangcodeChange(
+      [
+        'type' => 'paragraphs',
+        'weight' => 15,
+      ],
+      TRUE
+    );
+  }
+
+  /**
+   * Performs the test run with the given options.
+   *
+   * @param array $widget_options
+   *   The paragraph widget options.
+   * @param bool $embedded
+   *   (Optional) Whether the embedded form should be used or not.
+   */
+  protected function doTestLangcodeChange(array $widget_options, $embedded = FALSE) {
+    $this->formDisplay
+      ->setComponent($this->nodeParagraphsFieldName, $widget_options)
+      ->save();
+    $this->doTestChangeWithinNodeForm($embedded);
+  }
+
+  /**
+   * Performs the test run regards the node form.
+   *
+   * @param bool $embedded
+   *   (Optional) Whether the embedded form should be used or not.
+   */
+  protected function doTestChangeWithinNodeForm($embedded = FALSE) {
+    $this->assertEquals('es', $this->node->language()->getId(), "The node was created with langcode es.");
+    $this->assertEquals('en', $this->paragraph->language()->getId(), "The paragraph was created with its default langcode en.");
+
+    // Use this form to add a node.
+    $this->buildNodeForm($embedded);
+
+    $this->submitNodeForm();
+
+    $langcode = $this->node->language()->getId();
+    $this->assertEquals('es', $langcode, "The node's langcode remains unchanged to value es (after submission).");
+    $this->assertEquals($langcode, $this->paragraph->language()->getId(), "The paragraph's langcode was inherited from its parent (after submission).");
+
+    // Switch to the form again.
+    $this->buildNodeForm($embedded);
+
+    // Change the node's language from es to en.
+    if ($embedded) {
+      $this->formState->setValue(['embedded_entity_form', 'langcode'], [['value' => 'en']]);
+    }
+    else {
+      $this->formState->setValue('langcode', [['value' => 'en']]);
+    }
+    $this->submitNodeForm();
+
+    $langcode = $this->node->language()->getId();
+    $this->assertEquals('en', $langcode, "The node's langcode was updated to value en (after submission).");
+    $this->assertEquals($langcode, $this->paragraph->language()->getId(), "The paragraph's updated langcode was inherited from its parent (after submission).");
+
+    // Rebuild the form once more and make sure
+    // that the langcode change does not get lost.
+    $this->buildNodeForm($embedded);
+
+    // Change the node's language from en to es.
+    if ($embedded) {
+      $this->formState->setValue(['embedded_entity_form', 'langcode'], [['value' => 'es']]);
+    }
+    else {
+      $this->formState->setValue('langcode', [['value' => 'es']]);
+    }
+
+    $this->submitNodeForm();
+
+    $langcode = $this->node->language()->getId();
+    $this->assertEquals('es', $langcode, "The node's langcode was set to es (after rebuild and submission).");
+    $this->assertEquals($langcode, $this->paragraph->language()->getId(), "The paragraph's langcode was inherited from its parent (after rebuild and submission).");
+  }
+
+  /**
+   * Builds the node form.
+   *
+   * @param bool $embedded
+   *   (Optional) Whether the embedded form should be used or not.
+   */
+  protected function buildNodeForm($embedded = FALSE) {
+    if ($embedded) {
+      $this->formObject = new TestEmbeddedEntityForm($this->node);
+    }
+    else {
+      $this->formObject = $this->entityTypeManager->getFormObject('node', 'default');
+      $this->formObject->setEntity($this->node);
+    }
+    $this->formState = (new FormState())
+      ->disableRedirect()
+      ->setFormObject($this->formObject);
+    $this->form = $this->formBuilder->buildForm($this->formObject, $this->formState);
+    $this->reassignEntities();
+  }
+
+  /**
+   * Submits the node form, emulating the save operation as triggering element.
+   */
+  protected function submitNodeForm() {
+    // Submit the form with the default save operation.
+    $this->formState->setValue('op', $this->formState->getValue('submit'));
+    $this->formBuilder->submitForm($this->formObject, $this->formState);
+    $this->reassignEntities();
+  }
+
+  /**
+   * Helper method to reassign the current entity objects.
+   */
+  protected function reassignEntities() {
+    $this->node = $this->formObject->getEntity();
+    $paragraphs = $this->node->get($this->nodeParagraphsFieldName)->referencedEntities();
+    $this->paragraph = reset($paragraphs);
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
index 2d2b68a03b..c28c5c47df 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsReplicateTest.php
@@ -23,7 +23,7 @@ class ParagraphsReplicateTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'replicate',
     'node',
@@ -37,7 +37,7 @@ class ParagraphsReplicateTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs and article content types.
     $values = ['type' => 'article', 'name' => 'Article'];
diff --git a/web/modules/paragraphs/tests/src/Kernel/ParagraphsTypeHasEnabledBehaviorPluginTest.php b/web/modules/paragraphs/tests/src/Kernel/ParagraphsTypeHasEnabledBehaviorPluginTest.php
index 05de58617f..e016c4a7f6 100644
--- a/web/modules/paragraphs/tests/src/Kernel/ParagraphsTypeHasEnabledBehaviorPluginTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/ParagraphsTypeHasEnabledBehaviorPluginTest.php
@@ -18,7 +18,7 @@ class ParagraphsTypeHasEnabledBehaviorPluginTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'paragraphs',
     'user',
     'paragraphs_test',
@@ -35,7 +35,7 @@ class ParagraphsTypeHasEnabledBehaviorPluginTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void{
     parent::setUp();
     $this->installEntitySchema('user');
     $this->installEntitySchema('paragraph');
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemRevisionSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemRevisionSourceTest.php
index 0295414992..5136f27505 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemRevisionSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemRevisionSourceTest.php
@@ -17,7 +17,7 @@ class FieldCollectionItemRevisionSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemSourceTest.php
index 0f30cce131..3a545420e5 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionItemSourceTest.php
@@ -17,7 +17,7 @@ class FieldCollectionItemSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionTypeSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionTypeSourceTest.php
index 1beaa8059a..dec70ed8d0 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionTypeSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/FieldCollectionTypeSourceTest.php
@@ -17,7 +17,7 @@ class FieldCollectionTypeSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphContentMigrationTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphContentMigrationTest.php
new file mode 100644
index 0000000000..dc71738682
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphContentMigrationTest.php
@@ -0,0 +1,112 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Kernel\migrate;
+
+use Drupal\Core\TypedData\TranslatableInterface;
+use Drupal\node\Entity\Node;
+use Drupal\Tests\paragraphs\Traits\ParagraphsNodeMigrationAssertionsTrait;
+
+/**
+ * Test 'classic' Paragraph content migration.
+ *
+ * @group paragraphs
+ * @require entity_reference_revisions
+ */
+class ParagraphContentMigrationTest extends ParagraphsMigrationTestBase {
+
+  use ParagraphsNodeMigrationAssertionsTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'comment',
+    'datetime',
+    'datetime_range',
+    'field',
+    'file',
+    'image',
+    'link',
+    'menu_ui',
+    'node',
+    'options',
+    'system',
+    'taxonomy',
+    'telephone',
+    'text',
+    'user',
+    'content_translation',
+    'language'
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('file');
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('paragraph');
+    $this->installEntitySchema('comment');
+    $this->installSchema('node', ['node_access']);
+    $this->installSchema('comment', [
+      'comment_entity_statistics',
+    ]);
+
+    $this->executeMigrationWithDependencies('d7_field_collection_revisions');
+    $this->executeMigrationWithDependencies('d7_paragraphs_revisions');
+    $this->executeMigrationWithDependencies('d7_node:paragraphs_test');
+
+    $this->prepareMigrations([
+      'd7_node:article' => [],
+      'd7_node:blog' => [],
+      'd7_node:book' => [],
+      'd7_node:forum' => [],
+      'd7_node:test_content_type' => [],
+    ]);
+  }
+
+  /**
+   * Tests the migration of a content with paragraphs and field collections.
+   *
+   * @dataProvider providerParagraphContentMigration
+   */
+  public function testParagraphContentMigration($migration_to_run) {
+    if ($migration_to_run) {
+      // Drupal 8.8.x only has 'classic' node migrations.
+      // @see https://www.drupal.org/node/3105503
+      if (strpos($migration_to_run, 'd7_node_complete') === 0 && version_compare(\Drupal::VERSION, '8.9', '<')) {
+        $this->pass("Drupal 8.8.x has only the 'classic' node migration.");
+        return;
+      }
+
+      $this->executeMigration($migration_to_run);
+    }
+
+    $this->assertNode8Paragraphs();
+
+    $this->assertNode9Paragraphs();
+
+    $node_9 = Node::load(9);
+    if ($node_9 instanceof TranslatableInterface && !empty($node_9->getTranslationLanguages(FALSE))) {
+      $this->assertIcelandicNode9Paragraphs();
+    }
+  }
+
+  /**
+   * Provides data and expected results for testing paragraph migrations.
+   *
+   * @return string[][]
+   *   The node migration to run.
+   */
+  public function providerParagraphContentMigration() {
+    return [
+      ['node_migration' => NULL],
+      ['node_migration' => 'd7_node_revision:paragraphs_test'],
+      ['node_migration' => 'd7_node_translation:paragraphs_test'],
+      ['node_migration' => 'd7_node_complete:paragraphs_test'],
+    ];
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsFieldMigrationTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsFieldMigrationTest.php
index e4d93d7a24..434410f2bc 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsFieldMigrationTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsFieldMigrationTest.php
@@ -18,20 +18,17 @@ class ParagraphsFieldMigrationTest extends ParagraphsMigrationTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'comment',
     'datetime',
     'datetime_range',
-    'entity_reference_revisions',
     'field',
     'file',
     'image',
     'link',
     'menu_ui',
-    'migrate_drupal',
     'node',
     'options',
-    'paragraphs',
     'system',
     'taxonomy',
     'telephone',
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemRevisionSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemRevisionSourceTest.php
index 70c3fa5e3f..fca6b99643 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemRevisionSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemRevisionSourceTest.php
@@ -17,7 +17,7 @@ class ParagraphsItemRevisionSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
@@ -31,6 +31,8 @@ public function providerSource() {
         'field_name' => 'field_paragraphs_field',
         'bundle' => 'paragraphs_field',
         'archived' => '0',
+        'parent_id' => '42',
+        'parent_type' => 'taxonomy_term',
         'field_text' => [
           0 => [
             'value' => 'PID2R2 text',
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemSourceTest.php
index 1ab9d2e5e8..f55a234a4c 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsItemSourceTest.php
@@ -17,7 +17,7 @@ class ParagraphsItemSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
@@ -31,6 +31,8 @@ public function providerSource() {
         'field_name' => 'field_paragraphs_field',
         'bundle' => 'paragraphs_field',
         'archived' => '0',
+        'parent_id' => '5',
+        'parent_type' => 'node',
         'field_text' => [
           0 => [
             'value' => 'PID1R1 text',
@@ -43,6 +45,8 @@ public function providerSource() {
         'field_name' => 'field_paragraphs_field',
         'bundle' => 'paragraphs_field',
         'archived' => '0',
+        'parent_id' => '42',
+        'parent_type' => 'taxonomy_term',
         'field_text' => [
           0 => [
             'value' => 'PID2R3 text',
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsMigrationTestBase.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsMigrationTestBase.php
index 4766443d80..10e6a33932 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsMigrationTestBase.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsMigrationTestBase.php
@@ -16,7 +16,17 @@ abstract class ParagraphsMigrationTestBase extends MigrateDrupalTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  protected static $modules = [
+    'entity_reference_revisions',
+    'migrate',
+    'migrate_drupal',
+    'paragraphs',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp(): void {
     parent::setUp();
     $this->loadFixture(__DIR__ . '/../../../fixtures/drupal7.php');
 
@@ -119,8 +129,7 @@ protected function executeMigrationDependencies(MigrationInterface $migration) {
    * {@inheritdoc}
    */
   protected function prepareMigration(MigrationInterface $migration) {
-
-    // We want to run the revision migraiton without running all the node
+    // We want to run the revision migration without running all the node
     // migrations.
     if ($migration->id() == 'd7_node_revision:paragraphs_test') {
       $migration->set('migration_dependencies', [
@@ -128,7 +137,6 @@ protected function prepareMigration(MigrationInterface $migration) {
         'optional' => [],
       ]);
       $migration->set('requirements', ['d7_node:paragraphs_test' => 'd7_node:paragraphs_test']);
-
     }
   }
 
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeMigrationTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeMigrationTest.php
index ecb2d280a0..1586d4d25e 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeMigrationTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeMigrationTest.php
@@ -9,14 +9,6 @@
  */
 class ParagraphsTypeMigrationTest extends ParagraphsMigrationTestBase {
 
-  /**
-   * {@inheritdoc}
-   */
-  public static $modules = [
-    'migrate',
-    'paragraphs',
-  ];
-
   /**
    * Test if the paragraph/fc types were brought over as a paragraph.
    */
diff --git a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeSourceTest.php b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeSourceTest.php
index 329113c6e2..565b5837f6 100644
--- a/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeSourceTest.php
+++ b/web/modules/paragraphs/tests/src/Kernel/migrate/ParagraphsTypeSourceTest.php
@@ -17,7 +17,7 @@ class ParagraphsTypeSourceTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate_drupal', 'paragraphs'];
+  protected static $modules = ['migrate_drupal', 'paragraphs'];
 
   /**
    * {@inheritdoc}
diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php
index f08040b271..319d1718a8 100644
--- a/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php
+++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsCoreVersionUiTestTrait.php
@@ -35,24 +35,38 @@ protected function paragraphsPostNodeForm($path, $edit, $submit, array $options
     if ($drupal_version > 8.3) {
       switch ($submit) {
         case  t('Save and unpublish'):
-          $submit = t('Save');
+          $submit = 'Save';
           $edit['status[value]'] = FALSE;
           break;
 
-        case t('Save and publish'):
-          $submit = t('Save');
+        case 'Save and publish':
+          $submit = 'Save';
           $edit['status[value]'] = TRUE;
           break;
 
-        case t('Save and keep published (this translation)'):
-          $submit = t('Save (this translation)');
+        case 'Save and keep published (this translation)':
+          $submit = 'Save (this translation)';
           break;
 
         default:
-          $submit = t('Save');
+          $submit = 'Save';
       }
     }
     parent::drupalPostForm($path, $edit, $submit, $options, $headers, $form_html_id, $extra_post);
   }
 
+  /**
+   * Places commonly used blocks in a consistent order.
+   */
+  protected function placeDefaultBlocks() {
+    // Place the system main block explicitly and first to have a consistent
+    // block order before and after Drupal 9.4
+    $this->drupalPlaceBlock('system_main_block', ['weight' => -1, 'region' => 'content']);
+    // Place the breadcrumb, tested in fieldUIAddNewField().
+    $this->drupalPlaceBlock('system_breadcrumb_block', ['region' => 'content']);
+    $this->drupalPlaceBlock('local_tasks_block', ['region' => 'content']);
+    $this->drupalPlaceBlock('local_actions_block', ['region' => 'content']);
+    $this->drupalPlaceBlock('page_title_block', ['region' => 'content']);
+  }
+
 }
diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsLastEntityQueryTrait.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsLastEntityQueryTrait.php
index 91d7424413..0e4b239a47 100644
--- a/web/modules/paragraphs/tests/src/Traits/ParagraphsLastEntityQueryTrait.php
+++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsLastEntityQueryTrait.php
@@ -25,6 +25,7 @@ trait ParagraphsLastEntityQueryTrait {
    */
   protected function getLastEntityOfType($entity_type_id, $load = FALSE) {
     $query_result = \Drupal::entityQuery($entity_type_id)
+      ->accessCheck(TRUE)
       ->sort('created', 'DESC')
       ->range(0, 1)
       ->execute();
diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsNodeMigrationAssertionsTrait.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsNodeMigrationAssertionsTrait.php
new file mode 100644
index 0000000000..ed28675031
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsNodeMigrationAssertionsTrait.php
@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Traits;
+
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\TypedData\TranslatableInterface;
+use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
+use Drupal\node\Entity\Node;
+use Drupal\node\NodeInterface;
+use Drupal\paragraphs\ParagraphInterface;
+
+trait ParagraphsNodeMigrationAssertionsTrait {
+
+  /**
+   * Assertions on node 8.
+   */
+  protected function assertNode8Paragraphs() {
+    $node_8 = Node::load(8);
+    assert($node_8 instanceof NodeInterface);
+    // Check 'field collection test' field.
+    $node_8_field_collection_field_entities = $this->getReferencedEntities($node_8, 'field_field_collection_test', 2);
+    $this->assertEquals('Field Collection Text Data One UND', $node_8_field_collection_field_entities[0]->field_text->value);
+    $this->assertEquals('1', $node_8_field_collection_field_entities[0]->field_integer_list->value);
+    $this->assertEquals('Field Collection Text Data Two UND', $node_8_field_collection_field_entities[1]->field_text->value);
+    $this->assertNull($node_8_field_collection_field_entities[1]->field_integer_list->value);
+    // Check 'any paragraph' field.
+    $node_8_field_any_paragraph_entities = $this->getReferencedEntities($node_8, 'field_any_paragraph', 2);
+    $this->assertEquals('Paragraph Field One Bundle One UND', $node_8_field_any_paragraph_entities[0]->field_text->value);
+    $this->assertEquals('Some Text', $node_8_field_any_paragraph_entities[0]->field_text_list->value);
+    $this->assertEquals('Paragraph Field One Bundle Two UND', $node_8_field_any_paragraph_entities[1]->field_text->value);
+    $this->assertEquals('joe@joe.com', $node_8_field_any_paragraph_entities[1]->field_email->value);
+    // Check 'paragraph one only' field.
+    $node_8_field_paragraph_one_only_entities = $this->getReferencedEntities($node_8, 'field_paragraph_one_only', 1);
+    $this->assertEquals('Paragraph Field Two Bundle One Revision Two UND', $node_8_field_paragraph_one_only_entities[0]->field_text->value);
+    $this->assertEquals('Some more text', $node_8_field_paragraph_one_only_entities[0]->field_text_list->value);
+    // Check 'nested fc outer' field.
+    $node_8_field_nested_fc_outer_entities = $this->getReferencedEntities($node_8, 'field_nested_fc_outer', 1);
+    assert($node_8_field_nested_fc_outer_entities[0] instanceof ParagraphInterface);
+    $node_8_inner_nested_fc_0_entities = $this->getReferencedEntities($node_8_field_nested_fc_outer_entities[0], 'field_nested_fc_inner', 1);
+    $this->assertEquals('Nested FC test text', $node_8_inner_nested_fc_0_entities[0]->field_text->value);
+  }
+
+  /**
+   * Assertions of node 9.
+   */
+  protected function assertNode9Paragraphs() {
+    $node_9 = Node::load(9);
+    assert($node_9 instanceof NodeInterface);
+
+    if ($this->container->get('module_handler')->moduleExists('content_translation') && $node_9 instanceof TranslatableInterface) {
+      // Test the default translation.
+      $node_9 = $node_9->getUntranslated();
+      $this->assertSame('en', $node_9->language()->getId());
+    }
+
+    // Check 'field collection test' field.
+    $node_9_field_collection_field_entities = $this->getReferencedEntities($node_9, 'field_field_collection_test', 1);
+    $this->assertEquals('Field Collection Text Data Two EN', $node_9_field_collection_field_entities[0]->field_text->value);
+    $this->assertEquals('2', $node_9_field_collection_field_entities[0]->field_integer_list->value);
+    // Check 'any paragraph' field.
+    $node_9_field_any_paragraph_entities = $this->getReferencedEntities($node_9, 'field_any_paragraph', 2);
+    $this->assertEquals('Paragraph Field One Bundle One EN', $node_9_field_any_paragraph_entities[0]->field_text->value);
+    $this->assertEquals('Some Text', $node_9_field_any_paragraph_entities[0]->field_text_list->value);
+    $this->assertEquals('Paragraph Field One Bundle Two EN', $node_9_field_any_paragraph_entities[1]->field_text->value);
+    $this->assertEquals('jose@jose.com', $node_9_field_any_paragraph_entities[1]->field_email->value);
+    // Check 'paragraph one only' field.
+    $node_9_field_paragraph_one_only_entities = $this->getReferencedEntities($node_9, 'field_paragraph_one_only', 1);
+    $this->assertEquals('Paragraph Field Two Bundle One EN', $node_9_field_paragraph_one_only_entities[0]->field_text->value);
+    $this->assertEquals('Some Text', $node_9_field_paragraph_one_only_entities[0]->field_text_list->value);
+    // The 'nested fc outer' field should be empty.
+    $this->getReferencedEntities($node_9, 'field_nested_fc_outer', 0);
+  }
+
+  /**
+   * Assertions of the Icelandic translation of node 9.
+   */
+  protected function assertIcelandicNode9Paragraphs() {
+    // Confirm that the Icelandic translation of node 9 (which was node 10 on
+    // the source site) has the expected data.
+    $node_9 = Node::load(9);
+    assert($node_9 instanceof NodeInterface);
+    assert($node_9 instanceof TranslatableInterface);
+    $node_9_translation_languages = $node_9->getTranslationLanguages(FALSE);
+    $this->assertEquals(['is'], array_keys($node_9_translation_languages));
+    $node_9 = $node_9->getTranslation('is');
+    $this->assertSame('is', $node_9->language()->getId());
+
+    // Check 'field collection test' field.
+    $node_9_field_collection_field_entities = $this->getReferencedEntities($node_9, 'field_field_collection_test', 3);
+    $this->assertEquals('Field Collection Text Data One IS', $node_9_field_collection_field_entities[0]->field_text->value);
+    $this->assertEquals('1', $node_9_field_collection_field_entities[0]->field_integer_list->value);
+    $this->assertEquals('Field Collection Text Data Two IS', $node_9_field_collection_field_entities[1]->field_text->value);
+    $this->assertEquals('2', $node_9_field_collection_field_entities[1]->field_integer_list->value);
+    $this->assertEquals('Field Collection Text Data Three IS', $node_9_field_collection_field_entities[2]->field_text->value);
+    $this->assertEquals('3', $node_9_field_collection_field_entities[2]->field_integer_list->value);
+    // Check 'any paragraph' field.
+    $node_9_field_any_paragraph_entities = $this->getReferencedEntities($node_9, 'field_any_paragraph', 3);
+    $this->assertEquals('Paragraph Field One Bundle One IS', $node_9_field_any_paragraph_entities[0]->field_text->value);
+    $this->assertEquals('Some Text', $node_9_field_any_paragraph_entities[0]->field_text_list->value);
+    $this->assertEquals('Paragraph Field One Bundle Two IS', $node_9_field_any_paragraph_entities[1]->field_text->value);
+    $this->assertEquals('jose@jose.com', $node_9_field_any_paragraph_entities[1]->field_email->value);
+    $this->assertEquals('Paragraph Field One Bundle Two Delta 3 IS', $node_9_field_any_paragraph_entities[2]->field_text->value);
+    $this->assertEquals('john@john.com', $node_9_field_any_paragraph_entities[2]->field_email->value);
+    // Check 'paragraph one only' field.
+    $node_9_field_paragraph_one_only_entities = $this->getReferencedEntities($node_9, 'field_paragraph_one_only', 1);
+    $this->assertEquals('Paragraph Field Two Bundle One IS', $node_9_field_paragraph_one_only_entities[0]->field_text->value);
+    $this->assertEquals('Some more text', $node_9_field_paragraph_one_only_entities[0]->field_text_list->value);
+    // The 'nested fc outer' field should be empty.
+    $this->getReferencedEntities($node_9, 'field_nested_fc_outer', 0);
+  }
+
+  /**
+   * Get the referred entities.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
+   *   The parent entity.
+   * @param string $field_name
+   *   The name of the entity revision reference field.
+   * @param int $expected_count
+   *   The expected number of the referenced entities.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface[]
+   *   An array of entity objects keyed by field item deltas.
+   */
+  protected function getReferencedEntities(ContentEntityInterface $entity, $field_name, int $expected_count) {
+    $entity_field = $entity->hasField($field_name) ?
+      $entity->get($field_name) :
+      NULL;
+    assert($entity_field instanceof EntityReferenceRevisionsFieldItemList);
+    $entity_field_entities = $entity_field->referencedEntities();
+    $this->assertCount($expected_count, $entity_field_entities);
+
+    return $entity_field_entities;
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Traits/ParagraphsSourceData.php b/web/modules/paragraphs/tests/src/Traits/ParagraphsSourceData.php
index 970e0da19d..aba892a72e 100644
--- a/web/modules/paragraphs/tests/src/Traits/ParagraphsSourceData.php
+++ b/web/modules/paragraphs/tests/src/Traits/ParagraphsSourceData.php
@@ -16,7 +16,7 @@ trait ParagraphsSourceData {
   protected function getSourceData() {
     $data = [];
 
-    $data[]['source_data'] = [
+    $data[0]['source_data'] = [
       'paragraphs_bundle' => [
         [
           'bundle' => 'paragraphs_field',
@@ -103,7 +103,31 @@ protected function getSourceData() {
           'revision_id' => '3',
         ],
       ],
+      'field_data_field_paragraphs_field' => [
+        [
+          'entity_type' => 'node',
+          'entity_id' => '5',
+          // @todo Don't we have to match also entity revision IDs?
+          // 'revision_id' => 'something',
+          'field_paragraphs_field_value' => '1',
+          'field_paragraphs_field_revision_id' => '1',
+        ],
+        [
+          'entity_type' => 'taxonomy_term',
+          'entity_id' => '42',
+          'field_paragraphs_field_value' => '2',
+          'field_paragraphs_field_revision_id' => '3',
+        ],
+      ],
     ];
+    $data[0]['source_data']['field_revision_field_paragraphs_field'] = array_merge($data[0]['source_data']['field_data_field_paragraphs_field'], [
+      [
+        'entity_type' => 'taxonomy_term',
+        'entity_id' => '42',
+        'field_paragraphs_field_value' => '2',
+        'field_paragraphs_field_revision_id' => '2',
+      ],
+    ]);
     return $data;
   }
 
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionFieldSettingsTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionFieldSettingsTest.php
index 20248a114c..e47d6fbd80 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionFieldSettingsTest.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionFieldSettingsTest.php
@@ -16,7 +16,7 @@ class FieldCollectionFieldSettingsTest extends MigrateProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     $this->plugin = new FieldCollectionFieldSettings([], 'field_collection_field_settings', []);
     parent::setUp();
 
@@ -31,7 +31,7 @@ public function testParagraphsFieldSettings() {
       ->with('type')
       ->willReturn('field_collection');
     $value = $this->plugin->transform([], $this->migrateExecutable, $this->row, 'settings');
-    $this->assertArrayEquals(['target_type' => 'paragraph'], $value);
+    $this->assertEquals(['target_type' => 'paragraph'], $value);
   }
 
   /**
@@ -55,7 +55,7 @@ public function testTaxonomyParagraphFieldSettings() {
       ->with('type')
       ->willReturn('taxonomy_term');
     $value = $this->plugin->transform(['target_type' => 'some_preset_vaue'], $this->migrateExecutable, $this->row, 'settings');
-    $this->assertArrayEquals(['target_type' => 'some_preset_vaue'], $value);
+    $this->assertEquals(['target_type' => 'some_preset_vaue'], $value);
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionsFieldInstanceSettingsTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionsFieldInstanceSettingsTest.php
index 1a845317e2..00fafb6609 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionsFieldInstanceSettingsTest.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/FieldCollectionsFieldInstanceSettingsTest.php
@@ -16,7 +16,7 @@ class FieldCollectionsFieldInstanceSettingsTest extends ProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     $this->plugin = new FieldCollectionFieldInstanceSettings([], 'field_collection_field_instance_settings', [], $this->entityTypeBundleInfo);
@@ -43,7 +43,7 @@ public function testFieldCollectionInstanceFieldSettings(array $source, array $e
       ]);
     $value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'settings');
 
-    $this->assertArrayEquals($expected, $value);
+    $this->assertEquals($expected, $value);
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/MigrationPluginsAltererTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/MigrationPluginsAltererTest.php
new file mode 100644
index 0000000000..4ac93577a6
--- /dev/null
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/MigrationPluginsAltererTest.php
@@ -0,0 +1,197 @@
+<?php
+
+namespace Drupal\Tests\paragraphs\Unit\migrate;
+
+use Drupal\paragraphs\MigrationPluginsAlterer;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the MigrationPluginsAlterer service.
+ *
+ * @todo Cover every method.
+ *
+ * @coversDefaultClass \Drupal\paragraphs\MigrationPluginsAlterer
+ *
+ * @group paragraphs
+ */
+class MigrationPluginsAltererTest extends UnitTestCase {
+
+  /**
+   * The migration plugin alterer.
+   *
+   * @var \Drupal\paragraphs\MigrationPluginsAlterer
+   */
+  protected $paragraphsMigrationPluginsAlterer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $logger_channel = $this->createMock('Drupal\Core\Logger\LoggerChannelInterface');
+    $logger_factory = $this->getMockBuilder('Drupal\Core\Logger\LoggerChannelFactory')
+      ->getMock();
+    $logger_factory->expects($this->atLeastOnce())
+      ->method('get')
+      ->with('paragraphs')
+      ->will($this->returnValue($logger_channel));
+
+    $this->paragraphsMigrationPluginsAlterer = new MigrationPluginsAlterer($logger_factory);
+  }
+
+  /**
+   * Tests that migration processes are transformed to an array of processors.
+   *
+   * @dataProvider providerParagraphsMigrationPrepareProcess
+   * @covers ::paragraphsMigrationPrepareProcess
+   */
+  public function testParagraphsMigrationPrepareProcess(array $input, array $expected) {
+    ['process' => $process, 'property' => $property] = $input;
+    $success = $this->paragraphsMigrationPluginsAlterer->paragraphsMigrationPrepareProcess($process, $property);
+    $this->assertSame($expected['return'], $success);
+    $this->assertEquals($expected['process'], $process);
+  }
+
+  /**
+   * Provides data and expected results for testing the prepare process method.
+   *
+   * @return array[]
+   *   Data and expected results.
+   */
+  public function providerParagraphsMigrationPrepareProcess() {
+    return [
+      // Missing property (no change).
+      [
+        'input' => [
+          'process' => [
+            'catname' => 'Picurka',
+            'wont/touch' => 'this',
+          ],
+          'property' => 'missing',
+        ],
+        'expected' => [
+          'return' => FALSE,
+          'process' => [
+            'catname' => 'Picurka',
+            'wont/touch' => 'this',
+          ],
+        ],
+      ],
+      // Existing string property.
+      [
+        'input' => [
+          'process' => [
+            'catname' => 'Picurka',
+            'wont/touch' => 'this',
+          ],
+          'property' => 'catname',
+        ],
+        'expected' => [
+          'return' => TRUE,
+          'process' => [
+            'catname' => [
+              [
+                'plugin' => 'get',
+                'source' => 'Picurka',
+              ],
+            ],
+            'wont/touch' => 'this',
+          ],
+        ],
+      ],
+      // Single process plugin.
+      [
+        'input' => [
+          'process' => [
+            'cat' => [
+              'plugin' => 'migration_lookup',
+              'migration' => 'cats',
+              'source' => 'cat_id',
+            ],
+          ],
+          'property' => 'cat',
+        ],
+        'expected' => [
+          'return' => TRUE,
+          'process' => [
+            'cat' => [
+              [
+                'plugin' => 'migration_lookup',
+                'migration' => 'cats',
+                'source' => 'cat_id',
+              ],
+            ],
+          ],
+        ],
+      ],
+      // Array of process plugins (no change).
+      [
+        'input' => [
+          'process' => [
+            'catname' => [
+              [
+                'plugin' => 'migration_lookup',
+                'migration' => 'cats',
+                'source' => 'cat_id',
+              ],
+              [
+                'plugin' => 'extract',
+                'index' => ['name'],
+              ],
+              [
+                'plugin' => 'callback',
+                'callable' => 'ucfirst',
+              ],
+            ],
+          ],
+          'property' => 'catname',
+        ],
+        'expected' => [
+          'return' => TRUE,
+          'process' => [
+            'catname' => [
+              [
+                'plugin' => 'migration_lookup',
+                'migration' => 'cats',
+                'source' => 'cat_id',
+              ],
+              [
+                'plugin' => 'extract',
+                'index' => ['name'],
+              ],
+              [
+                'plugin' => 'callback',
+                'callable' => 'ucfirst',
+              ],
+            ],
+          ],
+        ],
+      ],
+      // Invalid type.
+      [
+        'input' => [
+          'process' => [
+            'invalid' => (object) [
+              [
+                'not a' => 'kitten',
+              ],
+            ],
+          ],
+          'property' => 'invalid',
+        ],
+        'expected' => [
+          'return' => FALSE,
+          'process' => [
+            'invalid' => (object) [
+              [
+                'not a' => 'kitten',
+              ],
+            ],
+          ],
+        ],
+      ],
+    ];
+  }
+
+}
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldInstanceSettingsTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldInstanceSettingsTest.php
index 848a73f1ac..4bbb55c6d7 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldInstanceSettingsTest.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldInstanceSettingsTest.php
@@ -15,7 +15,7 @@ class ParagraphsFieldInstanceSettingsTest extends ProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->row->expects($this->any())
       ->method('getSourceProperty')
@@ -39,7 +39,7 @@ public function testParagraphsInstanceFieldSettings(array $source, array $expect
 
     $value = $this->plugin->transform($source, $this->migrateExecutable, $this->row, 'settings');
 
-    $this->assertArrayEquals($expected, $value);
+    $this->assertEquals($expected, $value);
   }
 
   /**
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldSettingsTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldSettingsTest.php
index 2c8e84fa7e..6c73cb1461 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldSettingsTest.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsFieldSettingsTest.php
@@ -16,7 +16,7 @@ class ParagraphsFieldSettingsTest extends MigrateProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     $this->plugin = new ParagraphsFieldSettings([], 'paragraphs_field_settings', []);
     parent::setUp();
 
@@ -31,7 +31,7 @@ public function testParagraphsFieldSettings() {
       ->with('type')
       ->willReturn('paragraphs');
     $value = $this->plugin->transform([], $this->migrateExecutable, $this->row, 'settings');
-    $this->assertArrayEquals(['target_type' => 'paragraph'], $value);
+    $this->assertEquals(['target_type' => 'paragraph'], $value);
   }
 
   /**
@@ -55,7 +55,7 @@ public function testTaxonomyParagraphFieldSettings() {
       ->with('type')
       ->willReturn('taxonomy_term');
     $value = $this->plugin->transform(['target_type' => 'some_preset_vaue'], $this->migrateExecutable, $this->row, 'settings');
-    $this->assertArrayEquals(['target_type' => 'some_preset_vaue'], $value);
+    $this->assertEquals(['target_type' => 'some_preset_vaue'], $value);
   }
 
 }
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsProcessOnValueTest.php b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsProcessOnValueTest.php
index c016690460..e3ec84256c 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsProcessOnValueTest.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/ParagraphsProcessOnValueTest.php
@@ -26,7 +26,7 @@ class ParagraphsProcessOnValueTest extends ProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  public function setup() {
+  public function setUp(): void {
     parent::setup();
     $configuration = [
       'source_value' => 'source',
diff --git a/web/modules/paragraphs/tests/src/Unit/migrate/ProcessTestCase.php b/web/modules/paragraphs/tests/src/Unit/migrate/ProcessTestCase.php
index c2fe37d091..0dfca72955 100644
--- a/web/modules/paragraphs/tests/src/Unit/migrate/ProcessTestCase.php
+++ b/web/modules/paragraphs/tests/src/Unit/migrate/ProcessTestCase.php
@@ -20,7 +20,7 @@ abstract class ProcessTestCase extends MigrateProcessTestCase {
   /**
    * {@inheritdoc}
    */
-  protected function setup() {
+  protected function setUp(): void {
     parent::setUp();
 
     $this->entityTypeBundleInfo = $this->getMockBuilder(EntityTypeBundleInfo::class)
-- 
GitLab