diff --git a/.composer.json b/.composer.json index 85936d7be80..fc12c2ff3a7 100644 --- a/.composer.json +++ b/.composer.json @@ -5,7 +5,8 @@ "type": "neos-package-collection", "require": { "neos/flow-development-collection": "9.0.x-dev", - "neos/neos-setup": "^2.0" + "neos/neos-setup": "^2.0", + "league/flysystem-memory": "^3" }, "replace": { }, @@ -14,12 +15,14 @@ "scripts": { "lint:phpcs-psr12": "../../bin/phpcs --colors --standard=PSR12 ./Neos.ContentGraph.DoctrineDbalAdapter/src ./Neos.ContentGraph.PostgreSQLAdapter/src ./Neos.ContentRepository.BehavioralTests/Classes ./Neos.ContentRepository.TestSuite/Classes ./Neos.ContentRepository.Core/Classes ./Neos.Neos/Classes", "lint:phpcs": [ - "@lint:phpcs-psr12 --exclude=Generic.Files.LineLength" + "@lint:phpcs-psr12 --exclude=Generic.Files.LineLength,PSR1.Files.SideEffects" ], "lint:phpstan": "../../bin/phpstan analyse", + "lint:distributionintegrity": "[ -d 'Neos.ContentRepository' ] && { echo 'Package Neos.ContentRepository should not exist.' 1>&2; exit 1; } || exit 0;", "lint": [ "@lint:phpcs", - "@lint:phpstan" + "@lint:phpstan", + "@lint:distributionintegrity" ], "test:unit": [ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/UnitTests.xml Neos.ContentRepository.Core/Tests/Unit", @@ -29,18 +32,17 @@ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" ], "test:behavioral": [ - "mkdir -p ../../Build/Behat/; cp -R Neos.ContentRepository.BehavioralTests/DistributionBehatTemplate/* ../../Build/Behat/; cd ../../Build/Behat/; composer install; cd ../../Packages/Neos", "../../bin/behat -f progress -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist", "../../bin/behat -f progress -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist", "../../flow doctrine:migrate --quiet; ../../flow cr:setup", - "../../bin/behat -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser" + "../../bin/behat -f progress -c Neos.Neos/Tests/Behavior/behat.yml" ], "test:behavioral:stop-on-failure": [ - "mkdir -p ../../Build/Behat/; cp -R Neos.ContentRepository.BehavioralTests/DistributionBehatTemplate/* ../../Build/Behat/; cd ../../Build/Behat/; composer install; cd ../../Packages/Neos", "../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist", "../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist", "../../flow doctrine:migrate --quiet; ../../flow cr:setup", - "../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser" + "../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml", + "../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/behat.yml.dist" ], "test": [ "@test:unit", diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8ac43f624d7..8cea3924b45 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,7 +132,7 @@ jobs: git -C ../${{ env.NEOS_FOLDER }} checkout -b build composer config repositories.neos '{ "type": "path", "url": "../${{ env.NEOS_FOLDER }}", "options": { "symlink": false } }' composer require --no-update neos/neos-development-collection:"dev-build as ${{ env.NEOS_BRANCH_ALIAS }}" - # workaround for not-yet-released neos/eventstore packages + # TODO workaround for not-yet-released neos/eventstore packages composer require --no-update neos/eventstore:"dev-main" composer require --no-update neos/eventstore-doctrineadapter:"dev-main" @@ -230,7 +230,7 @@ jobs: FLOW_CONTEXT=Testing ./flow doctrine:migrate --quiet bin/phpunit --colors --stop-on-failure -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml --testsuite "Neos tests" --verbose - - name: Run ES CR Tests + - name: Run Behavioral Tests (ES CR && Neos.Neos) id: escrtests if: matrix.parallel-parts == 'escr-behavioral' # DEBUG MODE: comment-in the next line, because we want to reach the Upload Mysql/Postgres DB dump step. @@ -325,18 +325,6 @@ jobs: if: matrix.parallel-parts == 'functionaltests-postgres' run: bin/phpunit --colors --stop-on-failure -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml --testsuite "Neos tests" --verbose - - name: Run behat tests (PGSQL) - if: matrix.parallel-parts == 'functionaltests-postgres' - run: | - FLOW_CONTEXT=Testing/Behat ./flow configuration:show - FLOW_CONTEXT=Testing/Behat ./flow doctrine:migrationstatus - - FLOW_CONTEXT=Testing/Behat ./flow behat:setup - FLOW_CONTEXT=Testing/Behat ./flow doctrine:create - FLOW_CONTEXT=Testing/Behat ./flow doctrine:migrationversion --add --version all - # TODO: RE-ENABLE AFTER FIXING - #bin/behat --stop-on-failure -f progress -c Packages/Neos/Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser - buildall: if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip travis]')" runs-on: ubuntu-20.04 diff --git a/.github/workflows/postgresql-versions.yml b/.github/workflows/postgresql-versions.yml index 9e0a6a27eea..cf04c05cc0f 100644 --- a/.github/workflows/postgresql-versions.yml +++ b/.github/workflows/postgresql-versions.yml @@ -154,5 +154,5 @@ jobs: FLOW_CONTEXT=Testing/Behat ./flow behat:setup FLOW_CONTEXT=Testing/Behat ./flow doctrine:create FLOW_CONTEXT=Testing/Behat ./flow doctrine:migrationversion --add --version all - bin/behat --stop-on-failure -f progress -c Packages/Neos/Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser + bin/behat --stop-on-failure -f progress -c Packages/Neos/Neos.Neos/Tests/Behavior/behat.yml bin/behat --stop-on-failure -f progress -c Packages/Neos/Neos.ContentRepository/Tests/Behavior/behat.yml.dist diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000000..a3765f1bbd9 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,26 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-20.04 + tools: + python: "3.9" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: Neos.Neos/Documentation/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +formats: + - pdf + - epub + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: Neos.Neos/Documentation/requirements.txt diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php index d8543a1e00a..2f918be284f 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php @@ -12,15 +12,12 @@ */ require_once(__DIR__ . '/../../../../../../Application/Neos.Behat/Tests/Behat/FlowContextTrait.php'); -require_once(__DIR__ . '/../../../../../../Framework/Neos.Flow/Tests/Behavior/Features/Bootstrap/IsolatedBehatStepsTrait.php'); -require_once(__DIR__ . '/../../../../../Neos.ContentRepository.Security/Tests/Behavior/Features/Bootstrap/NodeAuthorizationTrait.php'); require_once(__DIR__ . '/ProjectionIntegrityViolationDetectionTrait.php'); use Behat\Behat\Context\Context as BehatContext; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Neos\Behat\Tests\Behat\FlowContextTrait; use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\ProjectionIntegrityViolationDetectionTrait; -use Neos\ContentRepository\BehavioralTests\Tests\Functional\BehatTestHelper; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; @@ -30,7 +27,6 @@ use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\Flow\Tests\Behavior\Features\Bootstrap\IsolatedBehatStepsTrait; /** * Features context @@ -38,13 +34,10 @@ class FeatureContext implements BehatContext { use FlowContextTrait; - use IsolatedBehatStepsTrait; use ProjectionIntegrityViolationDetectionTrait; use CRTestSuiteTrait; use CRBehavioralTestsSubjectProvider; - protected string $behatTestHelperObjectName = BehatTestHelper::class; - protected ContentRepositoryRegistry $contentRepositoryRegistry; public function __construct() diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/ProjectionIntegrityViolationDetectionTrait.php b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/ProjectionIntegrityViolationDetectionTrait.php index a34cb7b2dad..82a090cecb4 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/ProjectionIntegrityViolationDetectionTrait.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/ProjectionIntegrityViolationDetectionTrait.php @@ -20,6 +20,7 @@ use Neos\ContentGraph\DoctrineDbalAdapter\DoctrineDbalContentGraphProjectionFactory; use Neos\ContentGraph\DoctrineDbalAdapter\DoctrineDbalProjectionIntegrityViolationDetectionRunnerFactory; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; +use Neos\ContentRepository\Core\SharedModel\Id\UuidFactory; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\Helpers\TestingNodeAggregateId; @@ -27,7 +28,6 @@ use Neos\ContentRepositoryRegistry\Infrastructure\DbalClient; use Neos\Error\Messages\Error; use Neos\Error\Messages\Result; -use Neos\Flow\Utility\Algorithms; use PHPUnit\Framework\Assert; /** @@ -236,14 +236,14 @@ private function transformDatasetToHierarchyRelationRecord(array $dataset): arra 'dimensionspacepoint' => $dimensionSpacePoint->toJson(), 'dimensionspacepointhash' => $dimensionSpacePoint->hash, 'parentnodeanchor' => $parentNodeAggregateId->isNonExistent() - ? Algorithms::generateUUID() + ? UuidFactory::create() : $this->findRelationAnchorPointByIds( ContentStreamId::fromString($dataset['contentStreamId']), $dimensionSpacePoint, NodeAggregateId::fromString($dataset['parentNodeAggregateId']) ), 'childnodeanchor' => $childAggregateId->isNonExistent() - ? Algorithms::generateUUID() + ? UuidFactory::create() : $this->findRelationAnchorPointByIds( ContentStreamId::fromString($dataset['contentStreamId']), $dimensionSpacePoint, diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature index 4205a9d7b9a..962becc18bd 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding hierarchy relations and nod | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature index e379e6dd59f..eedd68e8ffd 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding parent relations | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature index 2c78056066a..577f79c2461 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding reference relations | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: referenceProperty: diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature index f73f315d2b0..7412e9ee0cb 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding restriction relations | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature index ab8b30e34ad..9253b7ac73a 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding restriction relations | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature index 11c77abe849..e8c8510392f 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding sibling sorting | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php index be851203b64..807679337c5 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php @@ -233,7 +233,7 @@ public function markStale(): void private function whenRootNodeAggregateWithNodeWasCreated(RootNodeAggregateWithNodeWasCreated $event, EventEnvelope $eventEnvelope): void { $nodeRelationAnchorPoint = NodeRelationAnchorPoint::create(); - $originDimensionSpacePoint = OriginDimensionSpacePoint::fromArray([]); + $originDimensionSpacePoint = OriginDimensionSpacePoint::createWithoutDimensions(); $node = new NodeRecord( $nodeRelationAnchorPoint, $event->nodeAggregateId, @@ -272,7 +272,7 @@ private function whenRootNodeAggregateDimensionsWereUpdated(RootNodeAggregateDim ->getAnchorPointForNodeAndOriginDimensionSpacePointAndContentStream( $event->nodeAggregateId, /** the origin DSP of the root node is always the empty dimension ({@see whenRootNodeAggregateWithNodeWasCreated}) */ - OriginDimensionSpacePoint::fromArray([]), + OriginDimensionSpacePoint::createWithoutDimensions(), $event->contentStreamId ); if ($rootNodeAnchorPoint === null) { diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjectionFactory.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjectionFactory.php index 51373f5d428..a264b39f8d7 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjectionFactory.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjectionFactory.php @@ -41,7 +41,6 @@ public function build( ); return new ContentGraphProjection( - // @phpstan-ignore-next-line new DoctrineDbalContentGraphProjection( $this->dbalClient, new NodeFactory( diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php index d493cf8d0b0..55b446e8bde 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php @@ -14,7 +14,7 @@ namespace Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection; -use Neos\Flow\Utility\Algorithms; +use Neos\ContentRepository\Core\SharedModel\Id\UuidFactory; /** * The node relation anchor value object @@ -30,7 +30,7 @@ private function __construct( public static function create(): self { - return new self(Algorithms::generateUUID()); + return new self(UuidFactory::create()); } public static function forRootEdge(): self diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php index 5be39df7d16..126200f98a3 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentGraph.php @@ -84,40 +84,6 @@ final public function getSubgraph( return $this->subgraphs[$index]; } - /** - * @throws DBALException - * @throws NodeTypeNotFoundException - */ - public function findNodeByIdAndOriginDimensionSpacePoint( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - OriginDimensionSpacePoint $originDimensionSpacePoint - ): ?Node { - $connection = $this->client->getConnection(); - - // HINT: we check the ContentStreamId on the EDGE; - // as this is where we actually find out whether the node exists in the content stream - $nodeRow = $connection->executeQuery( - 'SELECT n.*, h.contentstreamid, h.name FROM ' . $this->tableNamePrefix . '_node n - INNER JOIN ' . $this->tableNamePrefix . '_hierarchyrelation h - ON h.childnodeanchor = n.relationanchorpoint - WHERE n.nodeaggregateid = :nodeAggregateId - AND n.origindimensionspacepointhash = :originDimensionSpacePointHash - AND h.contentstreamid = :contentStreamId', - [ - 'nodeAggregateId' => $nodeAggregateId->value, - 'originDimensionSpacePointHash' => $originDimensionSpacePoint->hash, - 'contentStreamId' => $contentStreamId->value - ] - )->fetchAssociative(); - - return $nodeRow ? $this->nodeFactory->mapNodeRowToNode( - $nodeRow, - $originDimensionSpacePoint->toDimensionSpacePoint(), - VisibilityConstraints::withoutRestrictions() - ) : null; - } - /** * @throws RootNodeAggregateDoesNotExist */ diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php index 40225e2c489..798b59ef07c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/ContentSubgraph.php @@ -34,6 +34,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindBackReferencesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindReferencesFilter; @@ -63,7 +64,6 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\References; use Neos\ContentRepository\Core\Projection\ContentGraph\SearchTerm; use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree; -use Neos\ContentRepository\Core\Projection\ContentGraph\Subtrees; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateClassification; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; @@ -303,19 +303,22 @@ public function findSubtree(NodeAggregateId $entryNodeAggregateId, FindSubtreeFi ->setParameter('entryNodeAggregateId', $entryNodeAggregateId->value); $result = $this->fetchCteResults($queryBuilderInitial, $queryBuilderRecursive, $queryBuilderCte, 'tree'); - $subtreesByNodeId = []; - $rootSubtrees = $subtreesByNodeId['ROOT'] = Subtrees::createEmpty(); - foreach ($result as $nodeData) { - $node = $this->nodeFactory->mapNodeRowToNode( - $nodeData, - $this->dimensionSpacePoint, - $this->visibilityConstraints - ); - $subtree = new Subtree((int)$nodeData['level'], $node); - $subtreesByNodeId[$nodeData['parentNodeAggregateId']]->add($subtree); - $subtreesByNodeId[$nodeData['nodeaggregateid']] = $subtree; + /** @var array $subtreesByParentNodeId */ + $subtreesByParentNodeId = []; + foreach (array_reverse($result) as $nodeData) { + $nodeAggregateId = $nodeData['nodeaggregateid']; + $parentNodeAggregateId = $nodeData['parentNodeAggregateId']; + $node = $this->nodeFactory->mapNodeRowToNode($nodeData, $this->dimensionSpacePoint, $this->visibilityConstraints); + $subtree = new Subtree((int)$nodeData['level'], $node, array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? array_reverse($subtreesByParentNodeId[$nodeAggregateId]) : []); + if ($subtree->level === 0) { + return $subtree; + } + if (!array_key_exists($parentNodeAggregateId, $subtreesByParentNodeId)) { + $subtreesByParentNodeId[$parentNodeAggregateId] = []; + } + $subtreesByParentNodeId[$parentNodeAggregateId][] = $subtree; } - return $rootSubtrees->first(); + return null; } public function findAncestorNodes(NodeAggregateId $entryNodeAggregateId, FindAncestorNodesFilter $filter): Nodes @@ -355,6 +358,50 @@ public function countAncestorNodes(NodeAggregateId $entryNodeAggregateId, CountA ); } + public function findClosestNode(NodeAggregateId $entryNodeAggregateId, FindClosestNodeFilter $filter): ?Node + { + $queryBuilderInitial = $this->createQueryBuilder() + ->select('n.*, ph.name, ph.contentstreamid, ph.parentnodeanchor') + ->from($this->tableNamePrefix . '_node', 'n') + // we need to join with the hierarchy relation, because we need the node name. + ->innerJoin('n', $this->tableNamePrefix . '_hierarchyrelation', 'ph', 'n.relationanchorpoint = ph.childnodeanchor') + ->andWhere('ph.contentstreamid = :contentStreamId') + ->andWhere('ph.dimensionspacepointhash = :dimensionSpacePointHash') + ->andWhere('n.nodeaggregateid = :entryNodeAggregateId'); + $this->addRestrictionRelationConstraints($queryBuilderInitial, 'n', 'ph'); + + $queryBuilderRecursive = $this->createQueryBuilder() + ->select('p.*, h.name, h.contentstreamid, h.parentnodeanchor') + ->from('ancestry', 'c') + ->innerJoin('c', $this->tableNamePrefix . '_node', 'p', 'p.relationanchorpoint = c.parentnodeanchor') + ->innerJoin('p', $this->tableNamePrefix . '_hierarchyrelation', 'h', 'h.childnodeanchor = p.relationanchorpoint') + ->where('h.contentstreamid = :contentStreamId') + ->andWhere('h.dimensionspacepointhash = :dimensionSpacePointHash'); + $this->addRestrictionRelationConstraints($queryBuilderRecursive, 'p'); + + $queryBuilderCte = $this->createQueryBuilder() + ->select('*') + ->from('ancestry', 'p') + ->setMaxResults(1) + ->setParameter('contentStreamId', $this->contentStreamId->value) + ->setParameter('dimensionSpacePointHash', $this->dimensionSpacePoint->hash) + ->setParameter('entryNodeAggregateId', $entryNodeAggregateId->value); + if ($filter->nodeTypeConstraints !== null) { + $this->addNodeTypeConstraints($queryBuilderCte, $filter->nodeTypeConstraints, 'p'); + } + $nodeRows = $this->fetchCteResults( + $queryBuilderInitial, + $queryBuilderRecursive, + $queryBuilderCte, + 'ancestry' + ); + return $this->nodeFactory->mapNodeRowsToNodes( + $nodeRows, + $this->dimensionSpacePoint, + $this->visibilityConstraints + )->first(); + } + public function findDescendantNodes(NodeAggregateId $entryNodeAggregateId, FindDescendantNodesFilter $filter): Nodes { ['queryBuilderInitial' => $queryBuilderInitial, 'queryBuilderRecursive' => $queryBuilderRecursive, 'queryBuilderCte' => $queryBuilderCte] = $this->buildDescendantNodesQueries($entryNodeAggregateId, $filter); @@ -666,7 +713,7 @@ private function buildSiblingsQuery(bool $preceding, NodeAggregateId $siblingNod /** * @return array{queryBuilderInitial: QueryBuilder, queryBuilderRecursive: QueryBuilder, queryBuilderCte: QueryBuilder} */ - private function buildAncestorNodesQueries(NodeAggregateId $entryNodeAggregateId, FindAncestorNodesFilter|CountAncestorNodesFilter $filter): array + private function buildAncestorNodesQueries(NodeAggregateId $entryNodeAggregateId, FindAncestorNodesFilter|CountAncestorNodesFilter|FindClosestNodeFilter $filter): array { $queryBuilderInitial = $this->createQueryBuilder() ->select('n.*, ph.name, ph.contentstreamid, ph.parentnodeanchor') diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php index 7794a3879d5..c93abc75f93 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Repository/NodeFactory.php @@ -57,14 +57,17 @@ public function __construct( /** * @param array $nodeRow Node Row from projection (_node table) - * @throws NodeTypeNotFoundException */ public function mapNodeRowToNode( array $nodeRow, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): Node { - return new Node( + $nodeType = $this->nodeTypeManager->hasNodeType($nodeRow['nodetypename']) + ? $this->nodeTypeManager->getNodeType($nodeRow['nodetypename']) + : null; + + return Node::create( ContentSubgraphIdentity::create( $this->contentRepositoryId, ContentStreamId::fromString($nodeRow['contentstreamid']), @@ -75,7 +78,7 @@ public function mapNodeRowToNode( OriginDimensionSpacePoint::fromJsonString($nodeRow['origindimensionspacepoint']), NodeAggregateClassification::from($nodeRow['classification']), NodeTypeName::fromString($nodeRow['nodetypename']), - $this->nodeTypeManager->getNodeType($nodeRow['nodetypename']), + $nodeType, $this->createPropertyCollectionFromJsonString($nodeRow['properties']), isset($nodeRow['name']) ? NodeName::fromString($nodeRow['name']) : null, Timestamps::create( diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Feature/NodeCreation.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Feature/NodeCreation.php index 56bd658091f..767eb7c064b 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Feature/NodeCreation.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Feature/NodeCreation.php @@ -44,7 +44,7 @@ trait NodeCreation private function whenRootNodeAggregateWithNodeWasCreated(RootNodeAggregateWithNodeWasCreated $event): void { $nodeRelationAnchorPoint = NodeRelationAnchorPoint::create(); - $originDimensionSpacePoint = OriginDimensionSpacePoint::fromArray([]); + $originDimensionSpacePoint = OriginDimensionSpacePoint::createWithoutDimensions(); $node = new NodeRecord( $nodeRelationAnchorPoint, diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeAggregateIds.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeAggregateIds.php index 85c891d485b..7558a09a96b 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeAggregateIds.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeAggregateIds.php @@ -64,9 +64,7 @@ public static function fromArray(array $array): self public static function fromCollection( NodeAggregateIdCollection $collection ): self { - return new self( - $collection->getIterator()->getArrayCopy() - ); + return new self(iterator_to_array($collection)); } public function add( @@ -99,8 +97,11 @@ public function isEmpty(): bool return count($this->ids) === 0; } + /** + * @return \Traversable + */ public function getIterator(): \Traversable { - return new \ArrayIterator($this->ids); + yield from $this->ids; } } diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php index 34778c00137..151a799ece2 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoint.php @@ -14,7 +14,7 @@ namespace Neos\ContentGraph\PostgreSQLAdapter\Domain\Projection; -use Neos\Flow\Utility\Algorithms; +use Neos\ContentRepository\Core\SharedModel\Id\UuidFactory; /** * The node relation anchor value object @@ -30,7 +30,7 @@ private function __construct( public static function create(): self { - return new self(Algorithms::generateUUID()); + return new self(UuidFactory::create()); } public static function forRootHierarchyRelation(): self diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoints.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoints.php index 33599f4f162..5e4cca781cc 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoints.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/NodeRelationAnchorPoints.php @@ -17,24 +17,23 @@ /** * The node relation anchor points value object collection * - * @implements \IteratorAggregate + * @implements \IteratorAggregate * @internal */ -final class NodeRelationAnchorPoints implements \IteratorAggregate, \Countable +final readonly class NodeRelationAnchorPoints implements \IteratorAggregate, \Countable { /** - * @var array + * @var array */ - public readonly array $nodeRelationAnchorPoints; + public array $nodeRelationAnchorPoints; public function __construct(NodeRelationAnchorPoint ...$nodeRelationAnchorPoints) { - /** @var array $nodeRelationAnchorPoints */ $this->nodeRelationAnchorPoints = $nodeRelationAnchorPoints; } /** - * @param array $array + * @param array $array */ public static function fromArray(array $array): self { @@ -46,8 +45,6 @@ public static function fromArray(array $array): self $values[] = $item; } } - /** @var array + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->nodeRelationAnchorPoints); + yield from $this->nodeRelationAnchorPoints; } public function count(): int diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/ProjectionHypergraph.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/ProjectionHypergraph.php index 124f10c7933..1d876921576 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/ProjectionHypergraph.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/ProjectionHypergraph.php @@ -71,7 +71,6 @@ public function findNodeRecordByCoverage( $query = ProjectionHypergraphQuery::create($contentStreamId, $this->tableNamePrefix); $query = $query->withDimensionSpacePoint($dimensionSpacePoint) ->withNodeAggregateId($nodeAggregateId); - /** @phpstan-ignore-next-line @todo check actual return type */ $result = $query->execute($this->getDatabaseConnection())->fetchAssociative(); return $result ? NodeRecord::fromDatabaseRow($result) : null; @@ -89,7 +88,6 @@ public function findNodeRecordByOrigin( $query = $query->withOriginDimensionSpacePoint($originDimensionSpacePoint); $query = $query->withNodeAggregateId($nodeAggregateId); - /** @phpstan-ignore-next-line @todo check actual return type */ $result = $query->execute($this->getDatabaseConnection())->fetchAssociative(); return $result ? NodeRecord::fromDatabaseRow($result) : null; @@ -191,7 +189,6 @@ public function findNodeRecordsForNodeAggregate( $query = ProjectionHypergraphQuery::create($contentStreamId, $this->tableNamePrefix); $query = $query->withNodeAggregateId($nodeAggregateId); - /** @phpstan-ignore-next-line @todo check actual return type */ $result = $query->execute($this->getDatabaseConnection())->fetchAllAssociative(); return array_map(function ($row) { diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQuery.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQuery.php index 53c1efacd45..ad41c6b19d3 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQuery.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQuery.php @@ -15,7 +15,7 @@ namespace Neos\ContentGraph\PostgreSQLAdapter\Domain\Projection\Query; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Driver\Result; use Doctrine\DBAL\Types\Types; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; @@ -113,10 +113,7 @@ public function withNodeAggregateId(NodeAggregateId $nodeAggregateId): self return new self($query, $parameters, $this->types); } - /** - * @return ResultStatement - */ - public function execute(Connection $databaseConnection): ResultStatement + public function execute(Connection $databaseConnection): Result { return $databaseConnection->executeQuery($this->query, $this->parameters, $this->types); } diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQueryInterface.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQueryInterface.php index ff2ee1066e4..602bf71191d 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQueryInterface.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Projection/Query/ProjectionHypergraphQueryInterface.php @@ -15,7 +15,7 @@ namespace Neos\ContentGraph\PostgreSQLAdapter\Domain\Projection\Query; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\Driver\Result; /** * The interface to be implemented by projection hypergraph queries @@ -24,8 +24,5 @@ */ interface ProjectionHypergraphQueryInterface { - /** - * @return ResultStatement - */ - public function execute(Connection $databaseConnection): ResultStatement; + public function execute(Connection $databaseConnection): Result; } diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php index f52f33fd94a..58244d9823b 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentHypergraph.php @@ -87,24 +87,6 @@ public function getSubgraph( return $this->subhypergraphs[$index]; } - public function findNodeByIdAndOriginDimensionSpacePoint( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - OriginDimensionSpacePoint $originDimensionSpacePoint - ): ?Node { - $query = HypergraphQuery::create($contentStreamId, $this->tableNamePrefix); - $query = $query->withOriginDimensionSpacePoint($originDimensionSpacePoint); - $query = $query->withNodeAggregateId($nodeAggregateId); - - $nodeRow = $query->execute($this->getDatabaseConnection())->fetchAssociative(); - - return $nodeRow ? $this->nodeFactory->mapNodeRowToNode( - $nodeRow, - VisibilityConstraints::withoutRestrictions(), - $originDimensionSpacePoint->toDimensionSpacePoint() - ) : null; - } - public function findRootNodeAggregateByType( ContentStreamId $contentStreamId, NodeTypeName $nodeTypeName diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentSubhypergraph.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentSubhypergraph.php index b6b8223e78f..6f1bf311ec7 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentSubhypergraph.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/ContentSubhypergraph.php @@ -31,6 +31,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindBackReferencesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindReferencesFilter; @@ -457,6 +458,13 @@ public function countAncestorNodes( return 0; } + public function findClosestNode( + NodeAggregateId $entryNodeAggregateId, + FindClosestNodeFilter $filter + ): ?Node { + return null; + } + public function findDescendantNodes( NodeAggregateId $entryNodeAggregateId, FindDescendantNodesFilter $filter diff --git a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php index 42b5ae409f5..894b86cc3b2 100644 --- a/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php +++ b/Neos.ContentGraph.PostgreSQLAdapter/src/Domain/Repository/NodeFactory.php @@ -21,8 +21,8 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Reference; use Neos\ContentRepository\Core\Projection\ContentGraph\References; use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree; -use Neos\ContentRepository\Core\Projection\ContentGraph\Subtrees; use Neos\ContentRepository\Core\Projection\ContentGraph\Timestamps; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; @@ -71,8 +71,11 @@ public function mapNodeRowToNode( ?DimensionSpacePoint $dimensionSpacePoint = null, ?ContentStreamId $contentStreamId = null ): Node { - $nodeType = $this->nodeTypeManager->getNodeType($nodeRow['nodetypename']); - $result = new Node( + $nodeType = $this->nodeTypeManager->hasNodeType($nodeRow['nodetypename']) + ? $this->nodeTypeManager->getNodeType($nodeRow['nodetypename']) + : null; + + return Node::create( ContentSubgraphIdentity::create( $this->contentRepositoryId, $contentStreamId ?: ContentStreamId::fromString($nodeRow['contentstreamid']), @@ -97,8 +100,6 @@ public function mapNodeRowToNode( isset($nodeRow['originallastmodified']) ? self::parseDateTimeString($nodeRow['originallastmodified']) : null, ), ); - - return $result; } /** @@ -159,21 +160,22 @@ public function mapNodeRowsToSubtree( array $nodeRows, VisibilityConstraints $visibilityConstraints ): ?Subtree { - $subtreesByParentNodeAggregateId = []; - foreach ($nodeRows as $nodeRow) { - $node = $this->mapNodeRowToNode( - $nodeRow, - $visibilityConstraints - ); - - $subtreesByParentNodeAggregateId[$nodeRow['parentnodeaggregateid']][] = new Subtree( - (int)$nodeRow['level'], - $node, - $subtreesByParentNodeAggregateId[$nodeRow['nodeaggregateid']] ?? [] - ); + /** @var array $subtreesByParentNodeId */ + $subtreesByParentNodeId = []; + foreach (array_reverse($nodeRows) as $nodeRow) { + $nodeAggregateId = $nodeRow['nodeaggregateid']; + $parentNodeAggregateId = $nodeRow['parentnodeaggregateid']; + $node = $this->mapNodeRowToNode($nodeRow, $visibilityConstraints); + $subtree = new Subtree((int)$nodeRow['level'], $node, array_key_exists($nodeAggregateId, $subtreesByParentNodeId) ? array_reverse($subtreesByParentNodeId[$nodeAggregateId]) : []); + if ($subtree->level === 0) { + return $subtree; + } + if (!array_key_exists($parentNodeAggregateId, $subtreesByParentNodeId)) { + $subtreesByParentNodeId[$parentNodeAggregateId] = []; + } + $subtreesByParentNodeId[$parentNodeAggregateId][] = $subtree; } - - return Subtrees::fromArray($subtreesByParentNodeAggregateId['ROOT'])->first(); + return null; } /** diff --git a/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementCommandController.php b/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementCommandController.php index 5423f286e0f..20b95cb0281 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementCommandController.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/Command/PerformanceMeasurementCommandController.php @@ -37,7 +37,11 @@ public function __construct( } /** - * @throws \Throwable + * Prepare the performance test by removing existing data and creating nodes for the test. + * + * @param int $nodesPerLevel The number of nodes to create per level. + * @param int $levels The number of levels in the node tree. + * @internal */ public function preparePerformanceTestCommand(int $nodesPerLevel, int $levels): void { @@ -51,7 +55,9 @@ public function preparePerformanceTestCommand(int $nodesPerLevel, int $levels): } /** - * @throws \Throwable + * Test the performance of forking a content stream and measure the time taken. + * + * @internal */ public function testPerformanceCommand(): void { diff --git a/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/Command/RaceConditionTrackerCommandController.php b/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/Command/RaceConditionTrackerCommandController.php index bd96c289904..6c50a6f55af 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/Command/RaceConditionTrackerCommandController.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/ProjectionRaceConditionTester/Command/RaceConditionTrackerCommandController.php @@ -35,12 +35,23 @@ final class RaceConditionTrackerCommandController extends CommandController */ protected $configuration; + /** + * Reset the race condition tracker by clearing the stored traces in Redis. + * @internal + */ public function resetCommand(): void { RedisInterleavingLogger::connect($this->configuration['redis']['host'], $this->configuration['redis']['port']); RedisInterleavingLogger::reset(); } + + /** + * Analyze the stored trace and detect race conditions and double-processed events. + * + * @param string|null $storeTrace The path to store the full trace in NDJSON format (optional). + * @internal + */ public function analyzeTraceCommand(string $storeTrace = null): void { RedisInterleavingLogger::connect($this->configuration['redis']['host'], $this->configuration['redis']['port']); diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php index 08e8b622a4f..bfcb0806fc9 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php @@ -74,16 +74,6 @@ public function usingTheFollowingContentDimensions(TableNode $contentDimensions) public function usingTheFollowingNodeTypes(PyStringNode $serializedNodeTypesConfiguration): void { GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); - GherkinPyStringNodeBasedNodeTypeManagerFactory::$fallbackNodeTypeName = null; - } - - /** - * @Given /^using the following node types with fallback to "([^"]*)":$/ - */ - public function usingTheFollowingNodeTypesWithFallback(string $fallbackNodeTypeName, PyStringNode $serializedNodeTypesConfiguration): void - { - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); - GherkinPyStringNodeBasedNodeTypeManagerFactory::$fallbackNodeTypeName = $fallbackNodeTypeName; } /** @@ -136,30 +126,6 @@ public function iChangeTheNodeTypesInContentRepositoryTo( } } - /** - * @Given /^I change the node types in content repository "([^"]*)" with fallback "([^"]*)" to:$/ - */ - public function iChangeTheNodeTypesInContentRepositoryWithFallbackTo( - string $contentRepositoryId, - string $fallbackNodeTypeName, - PyStringNode $serializedNodeTypesConfiguration - ): void { - if (!array_key_exists($contentRepositoryId, $this->contentRepositories)) { - throw new \DomainException('undeclared content repository ' . $contentRepositoryId); - } else { - $contentRepository = $this->contentRepositories[$contentRepositoryId]; - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode( - $serializedNodeTypesConfiguration, - $fallbackNodeTypeName - ); - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = $contentRepository->getContentDimensionSource(); - $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); - if ($this->currentContentRepository->id->value === $contentRepositoryId) { - $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; - } - } - } - protected function setUpContentRepository(ContentRepositoryId $contentRepositoryId): ContentRepository { /** diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php index 4bc5bd2cdb3..026136c0ca3 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php @@ -31,8 +31,6 @@ final class GherkinPyStringNodeBasedNodeTypeManagerFactory implements NodeTypeMa { public static ?NodeTypeManager $nodeTypesToUse = null; - public static ?string $fallbackNodeTypeName = null; - /** * @param array $options */ @@ -44,22 +42,21 @@ public function build(ContentRepositoryId $contentRepositoryId, array $options): return self::$nodeTypesToUse; } - public static function initializeWithPyStringNode(PyStringNode $nodeTypesToUse, ?string $fallbackNodeTypeName = null): void + public static function initializeWithPyStringNode(PyStringNode $nodeTypesToUse): void { self::$nodeTypesToUse = new NodeTypeManager( - fn (): array => Yaml::parse($nodeTypesToUse->getRaw()), + fn (): array => Yaml::parse($nodeTypesToUse->getRaw()) ?? [], new class implements NodeLabelGeneratorFactoryInterface { public function create(NodeType $nodeType): NodeLabelGeneratorInterface { return new class implements NodeLabelGeneratorInterface { public function getLabel(Node $node): string { - return $node->nodeType->getLabel(); + return $node->nodeTypeName->value; } }; } - }, - $fallbackNodeTypeName + } ); } diff --git a/Neos.ContentRepository.BehavioralTests/DistributionBehatTemplate/composer.json b/Neos.ContentRepository.BehavioralTests/DistributionBehatTemplate/composer.json deleted file mode 100644 index a29f59524d9..00000000000 --- a/Neos.ContentRepository.BehavioralTests/DistributionBehatTemplate/composer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "require": { - "behat/behat": "^3.11.0", - "behat/mink-extension": "^2.3.1", - "behat/mink-goutte-driver": "*", - "psr/container": "^1.0" - }, - "config": { - "bin-dir": "../../bin/" - } -} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php index d55e4307a95..31d9bc21b50 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php @@ -12,18 +12,15 @@ */ require_once(__DIR__ . '/../../../../../Application/Neos.Behat/Tests/Behat/FlowContextTrait.php'); -require_once(__DIR__ . '/../../../../Neos.ContentRepository.Security/Tests/Behavior/Features/Bootstrap/NodeAuthorizationTrait.php'); require_once(__DIR__ . '/../../../../Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/ProjectionIntegrityViolationDetectionTrait.php'); -require_once(__DIR__ . '/../../../../../Framework/Neos.Flow/Tests/Behavior/Features/Bootstrap/IsolatedBehatStepsTrait.php'); -require_once(__DIR__ . '/../../../../../Framework/Neos.Flow/Tests/Behavior/Features/Bootstrap/SecurityOperationsTrait.php'); use Behat\Behat\Context\Context as BehatContext; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use GuzzleHttp\Psr7\Uri; use Neos\Behat\Tests\Behat\FlowContextTrait; +use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\ProjectionIntegrityViolationDetectionTrait; use Neos\ContentRepository\BehavioralTests\ProjectionRaceConditionTester\Dto\TraceEntryType; use Neos\ContentRepository\BehavioralTests\ProjectionRaceConditionTester\RedisInterleavingLogger; -use Neos\ContentRepository\BehavioralTests\Tests\Functional\BehatTestHelper; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; @@ -33,19 +30,15 @@ use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Infrastructure\DbalClientInterface; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\MigrationsTrait; -use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\ProjectionIntegrityViolationDetectionTrait; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\StructureAdjustmentsTrait; use Neos\ContentRepository\Core\Tests\Behavior\Fixtures\DayOfWeek; use Neos\ContentRepository\Core\Tests\Behavior\Fixtures\PostalAddress; use Neos\ContentRepository\Core\Tests\Behavior\Fixtures\PriceSpecification; -use Neos\ContentRepository\Security\Service\AuthorizationService; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\MigrationsTrait; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\StructureAdjustmentsTrait; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Configuration\ConfigurationManager; use Neos\Flow\ObjectManagement\ObjectManagerInterface; -use Neos\Flow\Tests\Behavior\Features\Bootstrap\IsolatedBehatStepsTrait; -use Neos\Flow\Tests\Behavior\Features\Bootstrap\SecurityOperationsTrait; /** * Features context @@ -53,17 +46,12 @@ class FeatureContext implements BehatContext { use FlowContextTrait; - use NodeAuthorizationTrait; - use SecurityOperationsTrait; - use IsolatedBehatStepsTrait; use CRTestSuiteTrait; use CRBehavioralTestsSubjectProvider; use ProjectionIntegrityViolationDetectionTrait; use StructureAdjustmentsTrait; use MigrationsTrait; - protected string $behatTestHelperObjectName = BehatTestHelper::class; - protected ContentRepositoryRegistry $contentRepositoryRegistry; private bool $raceConditionTrackerEnabled = false; @@ -75,8 +63,6 @@ public function __construct() } $this->objectManager = self::$bootstrap->getObjectManager(); - $this->setupSecurity(); - $this->nodeAuthorizationService = $this->getObjectManager()->get(AuthorizationService::class); $this->dbalClient = $this->getObjectManager()->get(DbalClientInterface::class); $this->setupCRTestSuiteTrait(); $this->setUpInterleavingLogger(); diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature index 4ffe9474b35..1aa76a131e7 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature @@ -10,7 +10,6 @@ Feature: Create a root node aggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractRoot': abstract: true 'Neos.ContentRepository.Testing:NonRoot': [] diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature index 17f689aed95..324f7c6d0f0 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature @@ -10,7 +10,6 @@ Feature: Create a root node aggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository:AnotherRoot': superTypes: 'Neos.ContentRepository:Root': true diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNode_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNode_WithDimensions.feature index eff5980741e..4770ce6aead 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNode_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNode_WithDimensions.feature @@ -12,7 +12,6 @@ Feature: Create a root node aggregate | language | mul, de, en, gsw | gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository:AnotherRoot': superTypes: 'Neos.ContentRepository:Root': true diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature index ecc43b0eafb..18d2a8d135b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature @@ -11,7 +11,6 @@ Feature: Create node aggregate with node Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Node': properties: postalAddress: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature index d1da3295221..67583dec79f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature @@ -13,7 +13,6 @@ Feature: Create node aggregate with node | language | mul, de, gsw | gsw->de->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Node': properties: postalAddress: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature index bfdbd2d2be1..bd56ce51ff7 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature @@ -11,7 +11,6 @@ Feature: Create node aggregate with node Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithoutTetheredChildNodes': properties: defaultText: @@ -191,7 +190,6 @@ Feature: Create node aggregate with node Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithoutTetheredChildNodes': [] """ And using identifier "default", I define a content repository @@ -257,7 +255,6 @@ Feature: Create node aggregate with node Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:SubSubNode': properties: text: @@ -454,7 +451,6 @@ Feature: Create node aggregate with node Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:SubNode': [] 'Neos.ContentRepository.Testing:NodeWithTetheredChildNodes': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature index 3c4a8f8392c..272af25581c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature @@ -10,7 +10,6 @@ Feature: Create node aggregate with node | language | mul, de, en, gsw | gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithoutTetheredChildNodes': properties: defaultText: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature index bbd981af493..99ece1dbca9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature @@ -7,7 +7,6 @@ Feature: Create a node aggregate with complex default values Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Node': properties: array: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature index 9ca7c98e47d..701ef17114d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature @@ -10,7 +10,6 @@ Feature: Create node variant | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: tethered: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature index be8c01a2096..a092c8da646 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature @@ -10,7 +10,6 @@ Feature: Create node specialization | language | en, de, gsw | gsw->de->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: tethered-node: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature index 191bf845d8d..cf81e99de4e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature @@ -10,7 +10,6 @@ Feature: Create node generalization | language | en, de, gsw | gsw->de->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: tethered-node: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature index a248c0548ef..d34578b9f84 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature @@ -10,7 +10,6 @@ Feature: Create node peer variant | language | en, de, fr, gsw | gsw->de->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Tethered': [] 'Neos.ContentRepository.Testing:TetheredDocument': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature index 4cf7822b852..cae1505f4c6 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature @@ -9,7 +9,6 @@ Feature: Set node properties: Constraint checks | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: text: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature index 2c2f6618d2f..0edc545ef4e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature @@ -9,7 +9,6 @@ Feature: Set properties | language | mul, de, gsw | gsw->de->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: string: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature index 98d89c06336..a4af16d7c13 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature @@ -9,7 +9,6 @@ Feature: Set node properties with different scopes | language | mul, de, gsw | gsw->de->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: unscopedProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature index c3fb1d6b76e..2e04fc4c051 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature @@ -9,7 +9,6 @@ Feature: Constraint checks on SetNodeReferences | language | de, gsw, en | gsw->de, en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: referenceProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature index 360db28497e..fdd2769f2f5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature @@ -7,7 +7,6 @@ Feature: Node References without Dimensions Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: referenceProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature index 549f21d17bc..ce9a9f8f4f6 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature @@ -11,7 +11,6 @@ Feature: Node References with Dimensions | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: referenceProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature index 292b81352d0..b5be6986e06 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature @@ -9,7 +9,6 @@ Feature: Set node properties with different scopes | language | mul, de, gsw | gsw->de->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: unscopedReference: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature index c72d5b09b4a..ae2e995690a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature @@ -11,7 +11,6 @@ Feature: Node References with Dimensions | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: referenceProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature index 53b1435cd50..c1362e74535 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature @@ -11,7 +11,6 @@ Feature: Constraint checks on node aggregate disabling | language | de, gsw, en | gsw->de, en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature index 479f978752d..9f8d73c1cf0 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature @@ -9,7 +9,6 @@ Feature: Disable a node aggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature index 9b72cef2dec..9ab8ece1340 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature @@ -11,7 +11,6 @@ Feature: Disable a node aggregate | language | mul, de, en, gsw, ltz | ltz->de->mul, gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature index 5cc1be11084..124c1de977b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature @@ -11,7 +11,6 @@ Feature: Enable a node aggregate | language | de, gsw, en | gsw->de, en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature index ab94a4bb19c..1a53bc1d35b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature @@ -9,7 +9,6 @@ Feature: Enable a node aggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature index 0296fbf8ab7..eef0ffed0ed 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature @@ -11,7 +11,6 @@ Feature: Enable a node aggregate | language | mul, de, en, gsw, ltz | ltz->de->mul, gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature index 0cf8be8feee..5a897f510bc 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature @@ -10,7 +10,6 @@ Feature: Creation of nodes underneath disabled nodes Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Document': {} """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature index e7a70b37745..2db08431ae7 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature @@ -12,7 +12,6 @@ Feature: Creation of nodes underneath disabled nodes | language | mul, de, en, gsw, ltz | ltz->de->mul, gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Document': {} """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature index 5f05924c123..e419bb7d363 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature @@ -10,7 +10,6 @@ Feature: Variation of hidden nodes | language | mul, de, en, gsw, ltz | ltz->de->mul, gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Document': {} """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature index 13bfd190485..970c803e274 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature @@ -11,7 +11,6 @@ Feature: Remove NodeAggregate | language | de, gsw, en | gsw->de, en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Tethered': [] 'Neos.ContentRepository.Testing:Document': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature index 1151a6ee227..093aa669a7a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature @@ -9,7 +9,6 @@ Feature: Remove NodeAggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature index 56920f2437d..1186753cc69 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature @@ -11,7 +11,6 @@ Feature: Remove NodeAggregate | language | en, de, gsw, fr | gsw->de->en, fr->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature index 03f71caf95d..e16bb97b991 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature @@ -10,7 +10,6 @@ Feature: On forking a content stream, node references should be copied as well. | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:NodeWithReferences': properties: referenceProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature index 910e7134a67..3b433612102 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature @@ -50,11 +50,8 @@ Feature: Adjust node types with a node migration # Actual Test ######################## # we remove the Document node type (which still exists in the CR) - When I change the node types in content repository "default" with fallback "Neos.ContentRepository:Fallback" to: + When I change the node types in content repository "default" to: """yaml - # !!fallback node is needed!! - TODO DISCUSS - 'Neos.ContentRepository:Fallback': [] - 'Neos.ContentRepository:Root': constraints: nodeTypes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature index d5d84d3b0d9..511099385b9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature @@ -48,11 +48,8 @@ Feature: Adjust node types with a node migration # Actual Test ######################## # we remove the Document node type (which still exists in the CR) - And I change the node types in content repository "default" with fallback "Neos.ContentRepository:Fallback" to: + And I change the node types in content repository "default" to: """yaml - # !!fallback node is needed!! - TODO DISCUSS - 'Neos.ContentRepository:Fallback': [] - 'Neos.ContentRepository:Root': constraints: nodeTypes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature index 469b77b2457..5699d8fb4f4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature @@ -5,7 +5,6 @@ Feature: Copy nodes (without dimensions) Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate.feature index 4ecfa79368b..053d191525e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate.feature @@ -19,7 +19,6 @@ Feature: Move node to a new parent / within the current parent before a sibling | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] 'Neos.ContentRepository.Testing:Content': constraints: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature index bfcfcc68cbb..aa8c3df065b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature @@ -18,7 +18,6 @@ Feature: Move a node aggregate considering disable state but without content dim Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateWithoutDimensions.feature index 16329b15e24..c1dfb1bb4bc 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregateWithoutDimensions.feature @@ -13,7 +13,6 @@ Feature: Move a node without content dimensions Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature index aa225e1b7d3..2719cbd9eb6 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature @@ -14,7 +14,6 @@ Feature: Move a node with content dimensions | language | mul, de, en, gsw | gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature index 11fd69509eb..c90dc25ff35 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature @@ -14,7 +14,6 @@ Feature: Move a node with content dimensions | language | mul, de, en, gsw | gsw->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature index 20e8755dcc2..e112c758be8 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature @@ -5,7 +5,6 @@ Feature: Node Property Conversion Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Content': properties: dateProperty: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature new file mode 100644 index 00000000000..d6bfa11b1a2 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature @@ -0,0 +1,62 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Individual node publication + + Publishing an individual node works + + Background: + Given using no content dimensions + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Content': {} + 'Neos.ContentRepository.Testing:Document': + childNodes: + child1: + type: 'Neos.ContentRepository.Testing:Content' + child2: + type: 'Neos.ContentRepository.Testing:Content' + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + + # Create user workspace + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-identifier" | + And the graph projection is fully up to date + + ################ + # PUBLISHING + ################ + Scenario: It is possible to publish a single node; and only this one is live. + # create nodes in user WS + Given I am in content stream "user-cs-identifier" and dimension space point {} + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | {} | + And I remember NodeAggregateId of node "sir-david-nodenborough"s child "child2" as "child2Id" + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | $child2Id | nody | {} | + When the command PublishIndividualNodesFromWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | + | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | + And the graph projection is fully up to date + + And I am in content stream "cs-identifier" + + Then I expect a node identified by cs-identifier;sir-david-nodenborough;{} to exist in the content graph + diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature index 64af1f7d280..bf99d43aceb 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature @@ -14,7 +14,6 @@ Feature: Publishing moved nodes without dimensions Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature index 0c5eb08e55b..16d55fe52d5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature @@ -9,7 +9,6 @@ Feature: Disable a node aggregate Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: references: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature index 0a851bec8e1..92b49ded40a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature @@ -9,7 +9,6 @@ Feature: Remove NodeAggregate | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature index 3ca6f820424..c4bf71b0d0a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature @@ -7,7 +7,6 @@ Feature: Change node name Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Content': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature index ba15f6eff90..0f459aa04b1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature @@ -9,7 +9,6 @@ Feature: Change node aggregate type - basic error cases | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AutoCreated': [] 'Neos.ContentRepository.Testing:ParentNodeType': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature index cb3a964ca10..a7045ab3946 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature @@ -9,7 +9,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AutoCreated': [] 'Neos.ContentRepository.Testing:ParentNodeType': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature index b88a5066589..b50ac899fff 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature @@ -10,7 +10,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AutoCreated': [] 'Neos.ContentRepository.Testing:ParentNodeType': childNodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature index f89a3679e6d..d3ad4c3eda5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature @@ -8,7 +8,6 @@ Feature: Find and count nodes using the findAncestorNodes and countAncestorNodes | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true 'Neos.ContentRepository.Testing:SomeMixin': diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature index 5dc5c3f40aa..9424f93a7dd 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature @@ -9,7 +9,6 @@ Feature: Find and count nodes using the findChildNodes and countChildNodes queri | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature new file mode 100644 index 00000000000..58743520d52 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature @@ -0,0 +1,97 @@ +@contentrepository @adapters=DoctrineDBAL + # TODO implement for Postgres +Feature: Find nodes using the findClosestNode query + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | language | mul, de, en, ch | ch->de->mul, en->mul | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:AbstractPage': + abstract: true + 'Neos.ContentRepository.Testing:SomeMixin': + abstract: true + 'Neos.ContentRepository.Testing:Homepage': + superTypes: + 'Neos.ContentRepository.Testing:AbstractPage': true + childNodes: + terms: + type: 'Neos.ContentRepository.Testing:Terms' + contact: + type: 'Neos.ContentRepository.Testing:Contact' + + 'Neos.ContentRepository.Testing:Terms': + superTypes: + 'Neos.ContentRepository.Testing:AbstractPage': true + properties: + text: + defaultValue: 'Terms default' + 'Neos.ContentRepository.Testing:Contact': + superTypes: + 'Neos.ContentRepository.Testing:AbstractPage': true + 'Neos.ContentRepository.Testing:SomeMixin': true + properties: + text: + defaultValue: 'Contact default' + 'Neos.ContentRepository.Testing:Page': + superTypes: + 'Neos.ContentRepository.Testing:AbstractPage': true + 'Neos.ContentRepository.Testing:SpecialPage': + superTypes: + 'Neos.ContentRepository.Testing:AbstractPage': true + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And I am user identified by "initiating-user-identifier" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the graph projection is fully up to date + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeName | nodeTypeName | parentNodeAggregateId | initialPropertyValues | tetheredDescendantNodeAggregateIds | + | home | home | Neos.ContentRepository.Testing:Homepage | lady-eleonode-rootford | {} | {"terms": "terms", "contact": "contact"} | + | a | a | Neos.ContentRepository.Testing:Page | home | {} | {} | + | a1 | a1 | Neos.ContentRepository.Testing:Page | a | {} | {} | + | a2 | a2 | Neos.ContentRepository.Testing:Page | a | {} | {} | + | a2a | a2a | Neos.ContentRepository.Testing:SpecialPage | a2 | {} | {} | + | a2a1 | a2a1 | Neos.ContentRepository.Testing:Page | a2a | {} | {} | + | a2a2 | a2a2 | Neos.ContentRepository.Testing:Page | a2a | {} | {} | + | a2a2a | a2a2a | Neos.ContentRepository.Testing:Page | a2a2 | {} | {} | + | a2a2b | a2a2b | Neos.ContentRepository.Testing:Page | a2a2 | {} | {} | + | a2b | a2b | Neos.ContentRepository.Testing:Page | a2 | {} | {} | + | a2b1 | a2b1 | Neos.ContentRepository.Testing:Page | a2b | {} | {} | + | b | b | Neos.ContentRepository.Testing:Page | home | {} | {} | + And the command DisableNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "a2a2a" | + | nodeVariantSelectionStrategy | "allVariants" | + And the graph projection is fully up to date + And the command DisableNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "a2b" | + | nodeVariantSelectionStrategy | "allVariants" | + And the graph projection is fully up to date + + Scenario: + # findClosestNode queries without results +# When I execute the findClosestNode query for entry node aggregate id "non-existing" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:Page"}' I expect no node to be returned +# # a2a2a is disabled +# When I execute the findClosestNode query for entry node aggregate id "a2a2a" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:Page"}' I expect no node to be returned +# # a2b is disabled +# When I execute the findClosestNode query for entry node aggregate id "a2b1" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:Page"}' I expect no node to be returned + + # findClosestNode queries with results + When I execute the findClosestNode query for entry node aggregate id "a2a2b" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:Page"}' I expect the node "a2a2b" to be returned + When I execute the findClosestNode query for entry node aggregate id "a2a2b" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:SpecialPage"}' I expect the node "a2a" to be returned + When I execute the findClosestNode query for entry node aggregate id "a2a2b" and filter '{"nodeTypeConstraints": "!Neos.ContentRepository.Testing:Page,!Neos.ContentRepository.Testing:SpecialPage"}' I expect the node "home" to be returned + When I execute the findClosestNode query for entry node aggregate id "a2a" and filter '{"nodeTypeConstraints": "Neos.ContentRepository.Testing:SpecialPage"}' I expect the node "a2a" to be returned diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature index eebd49b0ca0..9bf7a88015f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the countNodes query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature index 3d8130c8202..f6777b70dbe 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature @@ -9,7 +9,6 @@ Feature: Find and count nodes using the findDescendantNodes and countDescendantN | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindChildNodeConnectedThroughEdgeName.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindChildNodeConnectedThroughEdgeName.feature index d77870df23f..67898ef2130 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindChildNodeConnectedThroughEdgeName.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindChildNodeConnectedThroughEdgeName.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the findChildNodeConnectedThroughEdgeName query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature index 71c56365f9d..86070abf48c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the findNodeById query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature index 1e82af65961..22ca151cffa 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the findNodeByPath query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository:AnotherRoot': superTypes: 'Neos.ContentRepository:Root': true diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature index 621980fabec..bcae519c37d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the findParentNodes query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature index a874fe22192..8ae3fb196f8 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature @@ -7,7 +7,6 @@ Feature: Find root nodes by type | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository:AnotherRoot': superTypes: 'Neos.ContentRepository:Root': true diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature index beecb05f499..89239ef7bb4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature @@ -7,7 +7,6 @@ Feature: Find nodes using the findSubtree query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature index ed10a279f0c..a3a6bd5f958 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature @@ -7,7 +7,6 @@ Feature: Find and count references and their target nodes using the findReferenc | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature index 424fbe8193a..8fd2e37cf40 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature @@ -8,7 +8,6 @@ Feature: Find nodes using the retrieveNodePath query | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature index be228f12a15..1f37538870b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature @@ -7,7 +7,6 @@ Feature: Find sibling nodes using the findPrecedingSiblingNodes and findSucceedi | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature index 1ddee7b3778..ddb1b31533e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature @@ -9,7 +9,6 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la | language | mul, de, en, ch | ch->de->mul, en->mul | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:AbstractPage': abstract: true properties: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature index 22228a65799..9dd34c4676b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature @@ -10,7 +10,6 @@ Feature: Run projection integrity violation detection regarding root connection | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature index dce5c02817b..77d4575b33f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature @@ -9,7 +9,6 @@ Feature: Run projection integrity violation detection to find nodes that do not | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/IntactContentGraph.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/IntactContentGraph.feature index b45fb7aa640..01276ad9f20 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/IntactContentGraph.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/IntactContentGraph.feature @@ -9,7 +9,6 @@ Feature: Create an intact content graph and run integrity violation detection | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature index c297da32e16..49fcc92aa44 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature @@ -9,7 +9,6 @@ Feature: Create two nodes with the same node aggregate identifier in the same su | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature index bba3bd28d53..8328134f806 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature @@ -9,7 +9,6 @@ Feature: Run projection integrity violation detection regarding node aggregate c | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature index f8c7bcab23f..3695cb2c013 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature @@ -9,7 +9,6 @@ Feature: Run projection integrity violation detection regarding node aggregate t | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] 'Neos.ContentRepository.Testing:DocumentA': [] 'Neos.ContentRepository.Testing:DocumentB': [] diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature index d52a6cc5103..fac33f3cf85 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature @@ -9,7 +9,6 @@ Feature: Run integrity violation detection regarding reference relations | language | de, gsw, fr | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature index fcbed35762a..db68d13c03e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature @@ -9,7 +9,6 @@ Feature: Run projection integrity violation detection regarding naming of tether | language | de, gsw | gsw->de | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature index ca5a15e8b96..f2e7eb542a4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature @@ -9,7 +9,6 @@ Feature: Update Root Node aggregate dimensions | language | mul, de | | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] """ And using identifier "default", I define a content repository And I am in content repository "default" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature index 390272d425d..23dcda99640 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature @@ -14,7 +14,6 @@ Feature: Dimension mismatch | language | en, de | de->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ And using identifier "default", I define a content repository diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature new file mode 100644 index 00000000000..9dc7063bf5d --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature @@ -0,0 +1,49 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Remove disallowed Child Nodes and grandchild nodes + + As a user of the CR I want to be able to keep tethered child nodes although their type is not allowed below their parent + + Scenario: Direct constraints + Given using no content dimensions + And using the following node types: + """yaml + 'Neos.ContentRepository:Root': + constraints: + nodeTypes: + '*': false + 'Neos.ContentRepository.Testing:Document': true + 'Neos.ContentRepository.Testing:Document': + constraints: + nodeTypes: + '*': false + childNodes: + tethered: + type: 'Neos.ContentRepository.Testing:AnotherDocument' + + 'Neos.ContentRepository.Testing:AnotherDocument': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in content stream "cs-identifier" and dimension space point {} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the graph projection is fully up to date + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | + | nody-mc-nodeface | lady-eleonode-rootford | Neos.ContentRepository.Testing:Document | + + ######################## + # Actual Test + ######################## + Then I expect no needed structure adjustments for type "Neos.ContentRepository:Root" + Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" + Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:AnotherDocument" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature index e9f064ee277..19aed834eae 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature @@ -10,7 +10,6 @@ Feature: Properties Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: myProp: @@ -52,7 +51,6 @@ Feature: Properties Scenario: The property is removed Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] """ Then I expect the following structure adjustments for type "Neos.ContentRepository.Testing:Document": @@ -68,7 +66,6 @@ Feature: Properties Scenario: a new property default value is set Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: myProp: @@ -94,7 +91,6 @@ Feature: Properties Scenario: a new property default value is not set if the value already contains the empty string Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: myProp: @@ -116,7 +112,6 @@ Feature: Properties Scenario: a broken property (which cannot be deserialized) is detected and removed Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': properties: myProp: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature index 5a123ed5805..8f74410ec2b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature @@ -10,7 +10,6 @@ Feature: Tethered Nodes integrity violations | language | en, de, gsw | gsw->de->en | And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': @@ -81,7 +80,6 @@ Feature: Tethered Nodes integrity violations Scenario: Adjusting the schema adding a new tethered node leads to a MissingTetheredNode integrity violation Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': @@ -106,7 +104,6 @@ Feature: Tethered Nodes integrity violations Scenario: Adding missing tethered nodes resolves the corresponding integrity violations Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': @@ -135,7 +132,6 @@ Feature: Tethered Nodes integrity violations Scenario: Adding the same Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': @@ -160,7 +156,6 @@ Feature: Tethered Nodes integrity violations Scenario: Adjusting the schema removing a tethered node leads to a DisallowedTetheredNode integrity violation (which can be fixed) Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] 'Neos.ContentRepository.Testing:Tethered': properties: @@ -184,7 +179,6 @@ Feature: Tethered Nodes integrity violations Scenario: Adjusting the schema changing the type of a tethered node leads to a InvalidTetheredNodeType integrity violation Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature index 08858525a0d..5e6a7a3615f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature @@ -7,7 +7,6 @@ Feature: Tethered Nodes Reordering Structure changes Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': @@ -57,7 +56,6 @@ Feature: Tethered Nodes Reordering Structure changes Scenario: re-ordering the tethered child nodes brings up wrongly sorted tethered nodes Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': childNodes: 'tethered-node': diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature index 8122ebecf33..4d0578ccf21 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature @@ -5,11 +5,9 @@ Feature: Unknown node types Background: Given using no content dimensions - And using the following node types with fallback to "Neos.ContentRepository:Fallback": + And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Document': [] - 'Neos.ContentRepository:Fallback': [] """ And using identifier "default", I define a content repository And I am in content repository "default" @@ -40,10 +38,8 @@ Feature: Unknown node types Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" Scenario: When removing "Neos.ContentRepository.Testing:Document", we find a missing node type. - Given I change the node types in content repository "default" with fallback "Neos.ContentRepository:Fallback" to: + Given I change the node types in content repository "default" to: """yaml - 'Neos.ContentRepository:Root': [] - 'Neos.ContentRepository:Fallback': [] """ Then I expect the following structure adjustments for type "Neos.ContentRepository.Testing:Document": | Type | nodeAggregateId | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature index 88de55f14f0..5cfe3aee9d7 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature @@ -18,7 +18,6 @@ Feature: Rebasing auto-created nodes works Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Content': childNodes: foo: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature index 47fb588416e..7e855d224bd 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature @@ -11,7 +11,6 @@ Feature: Workspace based content publishing Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Content': properties: text: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature index 6a4fe19b54e..fb90bd09ae5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature @@ -5,7 +5,6 @@ Feature: Single Node operations on multiple workspaces/content streams; e.g. cop Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} 'Neos.ContentRepository.Testing:Content': properties: text: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature index b5c1b39ec8a..d4dc4aa0924 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature @@ -6,7 +6,6 @@ Feature: If content streams are not in use anymore by the workspace, they can be Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': {} """ And using identifier "default", I define a content repository And I am in content repository "default" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature index 66ec0d2550f..c323f850774 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature @@ -7,7 +7,6 @@ Feature: Single Node operations on live workspace Given using no content dimensions And using the following node types: """yaml - 'Neos.ContentRepository:Root': [] 'Neos.ContentRepository.Testing:Content': properties: text: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Functional/BehatTestHelper.php b/Neos.ContentRepository.BehavioralTests/Tests/Functional/BehatTestHelper.php deleted file mode 100644 index 9b9ceb6f80c..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Functional/BehatTestHelper.php +++ /dev/null @@ -1,111 +0,0 @@ -get(Bootstrap::class); - $this->isolated = false; - } - - /** - * @return mixed - */ - protected function getObjectManager(): ObjectManagerInterface - { - return $this->objectManager; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Dimension/ConfigurationBasedContentDimensionSource.php b/Neos.ContentRepository.Core/Classes/Dimension/ConfigurationBasedContentDimensionSource.php index c353386def1..18010088156 100644 --- a/Neos.ContentRepository.Core/Classes/Dimension/ConfigurationBasedContentDimensionSource.php +++ b/Neos.ContentRepository.Core/Classes/Dimension/ConfigurationBasedContentDimensionSource.php @@ -81,7 +81,7 @@ protected function initializeDimensions(): void $this->contentDimensions[$rawDimensionId] = new ContentDimension( $dimensionId, new ContentDimensionValues($values), - new ContentDimensionValueVariationEdges($variationEdges), + new ContentDimensionValueVariationEdges(...$variationEdges), $additionalConfiguration ); } diff --git a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionConstraintSet.php b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionConstraintSet.php index 70c2786f751..e95bee72a02 100644 --- a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionConstraintSet.php +++ b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionConstraintSet.php @@ -56,11 +56,11 @@ public static function createEmpty(): self } /** - * @return \ArrayIterator|ContentDimensionConstraints[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->constraints); + yield from $this->constraints; } public function getConstraints(ContentDimensionId $dimensionId): ?ContentDimensionConstraints @@ -72,8 +72,7 @@ public function allowsCombinationWith( ContentDimensionId $contentDimensionId, ContentDimensionValue $contentDimensionValue ): bool { - return isset($this->constraints[$contentDimensionId->value]) - ? $this->constraints[$contentDimensionId->value]->allowsCombinationWith($contentDimensionValue) - : true; + return !isset($this->constraints[$contentDimensionId->value]) + || $this->constraints[$contentDimensionId->value]->allowsCombinationWith($contentDimensionValue); } } diff --git a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValueVariationEdges.php b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValueVariationEdges.php index 66852096c8d..00d96baa9e4 100644 --- a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValueVariationEdges.php +++ b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValueVariationEdges.php @@ -1,7 +1,7 @@ + * @implements \IteratorAggregate * @internal */ final class ContentDimensionValueVariationEdges implements \IteratorAggregate { /** - * @var array + * @var array */ private array $edges; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - - /** - * @param array $array - */ - public function __construct(array $array) + public function __construct(ContentDimensionValueVariationEdge ...$edges) { - foreach ($array as $edge) { - if (!$edge instanceof ContentDimensionValueVariationEdge) { - throw new \InvalidArgumentException( - 'ContentDimensionValueVariationEdges may only contain ContentDimensionValueVariationEdge objects', - 1639661280 - ); - } - } - - $this->edges = $array; - $this->iterator = new \ArrayIterator($this->edges); + $this->edges = $edges; } public static function createEmpty(): self { - return new self([]); + return new self(); } /** - * @return \ArrayIterator|ContentDimensionValueVariationEdge[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->edges; } public function isEmpty(): bool diff --git a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValues.php b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValues.php index 5c132448e6d..082e46411d6 100644 --- a/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValues.php +++ b/Neos.ContentRepository.Core/Classes/Dimension/ContentDimensionValues.php @@ -22,15 +22,15 @@ * @implements \IteratorAggregate * @api because used as return value of Dimension Eel helper */ -final class ContentDimensionValues implements \IteratorAggregate +final readonly class ContentDimensionValues implements \IteratorAggregate { /** * The actual values, indexed by string representation * @var array */ - public readonly array $values; + public array $values; - public readonly ContentDimensionValueSpecializationDepth $maximumDepth; + public ContentDimensionValueSpecializationDepth $maximumDepth; /** * @param array $values @@ -60,11 +60,11 @@ public function __construct(array $values) } /** - * @return \ArrayIterator|ContentDimensionValue[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->values); + yield from $this->values; } public function getValue(string $value): ?ContentDimensionValue diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/AbstractDimensionSpacePoint.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/AbstractDimensionSpacePoint.php index 8d03f3624d0..9f457b03576 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/AbstractDimensionSpacePoint.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/AbstractDimensionSpacePoint.php @@ -124,6 +124,7 @@ final public function equals(self $other): bool /** * @return array> + * @deprecated should be only used for conversion from Neos <= 8.x to 9.x upwards. never use this in "modern" code. */ final public function toLegacyDimensionArray(): array { diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePoint.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePoint.php index aecb51fe6f1..9a31aef29ad 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePoint.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePoint.php @@ -61,10 +61,21 @@ public static function fromJsonString(string $jsonString): self return self::instance(json_decode($jsonString, true)); } + /** + * Creates a dimension space point for a zero-dimensional content repository. + * + * This applies to content repositories without any dimensions configured. + */ + public static function createWithoutDimensions(): self + { + return self::fromArray([]); + } + /** * Creates a dimension space point from a legacy dimension array in format * ['language' => ['es'], 'country' => ['ar']] * + * @deprecated should be only used for conversion from Neos <= 8.x to 9.x upwards. never use this in "modern" code. * @param array> $legacyDimensionValues */ final public static function fromLegacyDimensionArray(array $legacyDimensionValues): self diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php index 3b8b3165831..56179626e7d 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/DimensionSpacePointSet.php @@ -1,7 +1,7 @@ es, country => ar], [language => es, country => es]} * @implements \IteratorAggregate * @implements \ArrayAccess * @api */ -final class DimensionSpacePointSet implements +final readonly class DimensionSpacePointSet implements \JsonSerializable, \IteratorAggregate, \ArrayAccess, @@ -31,12 +36,7 @@ final class DimensionSpacePointSet implements /** * @var array */ - public readonly array $points; - - /** - * @var \ArrayIterator - */ - public readonly \ArrayIterator $iterator; + public array $points; /** * @param array> $pointCandidates @@ -56,7 +56,6 @@ public function __construct(array $pointCandidates) $points[$pointCandidate->hash] = $pointCandidate; } $this->points = $points; - $this->iterator = new \ArrayIterator($this->points); } /** @@ -95,14 +94,14 @@ public function offsetGet(mixed $offset): ?DimensionSpacePoint return $this->points[$offset] ?? null; } - public function offsetSet(mixed $offset, mixed $value): void + public function offsetSet(mixed $offset, mixed $value): never { - // not going to happen + throw new \BadMethodCallException('Cannot modify immutable DimensionSpacePointSet', 1697802335); } - public function offsetUnset(mixed $offset): void + public function offsetUnset(mixed $offset): never { - // not going to happen + throw new \BadMethodCallException('Cannot modify immutable DimensionSpacePointSet', 1697802337); } public function getUnion(DimensionSpacePointSet $other): DimensionSpacePointSet @@ -150,11 +149,11 @@ public function equals(DimensionSpacePointSet $other): bool } /** - * @return \ArrayIterator|DimensionSpacePoint[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->points; } /** diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/InterDimensionalVariationGraph.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/InterDimensionalVariationGraph.php index 7cc294a242a..52725f6ec9e 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/InterDimensionalVariationGraph.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/InterDimensionalVariationGraph.php @@ -17,62 +17,62 @@ use Neos\ContentRepository\Core\Dimension; /** - * The inter dimensional variation graph domain model + * The interdimensional variation graph domain model * Represents the specialization and generalization mechanism between dimension space points * @api */ -class InterDimensionalVariationGraph +final class InterDimensionalVariationGraph { /** * Weighed dimension space points, indexed by identity (DSP) hash * - * @var array|null + * @var array */ - protected ?array $weightedDimensionSpacePoints = null; + private array $weightedDimensionSpacePoints; /** * Generalization dimension space point sets, indexed by specialization hash * - * @var array|null + * @var array */ - protected ?array $indexedGeneralizations = null; + private array $indexedGeneralizations; /** * Specialization dimension space point sets, indexed by generalization hash * - * @var array|null + * @var array */ - protected ?array $indexedSpecializations = null; + private array $indexedSpecializations; /** * Weighed generalizations, indexed by specialization hash and relative weight * - * @var array>|null + * @var array> */ - protected ?array $weightedGeneralizations = null; + private array $weightedGeneralizations; /** * Weighed specializations, indexed by generalization hash, relative weight and specialization hash - * @var array>>|null + * @var array>> */ - protected ?array $weightedSpecializations = null; + private array $weightedSpecializations; /** * Primary generalization dimension space points, indexed by specialization hash * * @var array */ - protected ?array $primaryGeneralizations = null; + private array $primaryGeneralizations; - protected ?int $weightNormalizationBase = null; + private int $weightNormalizationBase; public function __construct( - private Dimension\ContentDimensionSourceInterface $contentDimensionSource, - private ContentDimensionZookeeper $contentDimensionZookeeper + private readonly Dimension\ContentDimensionSourceInterface $contentDimensionSource, + private readonly ContentDimensionZookeeper $contentDimensionZookeeper ) { } - protected function initializeWeightedDimensionSpacePoints(): void + private function initializeWeightedDimensionSpacePoints(): void { $this->weightedDimensionSpacePoints = []; foreach ($this->contentDimensionZookeeper->getAllowedCombinations() as $dimensionValues) { @@ -93,13 +93,10 @@ public function getDimensionSpacePoints(): DimensionSpacePointSet */ public function getWeightedDimensionSpacePoints(): array { - if (is_null($this->weightedDimensionSpacePoints)) { + if (!isset($this->weightedDimensionSpacePoints)) { $this->initializeWeightedDimensionSpacePoints(); } - /** @var array $weighedDimensionSpacePoints */ - $weighedDimensionSpacePoints = $this->weightedDimensionSpacePoints; - - return $weighedDimensionSpacePoints; + return $this->weightedDimensionSpacePoints; } public function getWeightedDimensionSpacePointByDimensionSpacePoint( @@ -110,7 +107,7 @@ public function getWeightedDimensionSpacePointByDimensionSpacePoint( public function getWeightedDimensionSpacePointByHash(string $hash): ?WeightedDimensionSpacePoint { - if (is_null($this->weightedDimensionSpacePoints)) { + if (!isset($this->weightedDimensionSpacePoints)) { $this->initializeWeightedDimensionSpacePoints(); } @@ -134,9 +131,9 @@ public function getRootGeneralizations(): array return $rootGeneralizations; } - protected function determineWeightNormalizationBase(): int + private function determineWeightNormalizationBase(): int { - if (is_null($this->weightNormalizationBase)) { + if (!isset($this->weightNormalizationBase)) { $base = 0; foreach ($this->contentDimensionSource->getContentDimensionsOrderedByPriority() as $contentDimension) { $base = max($base, $contentDimension->getMaximumDepth()->value + 1); @@ -148,13 +145,15 @@ protected function determineWeightNormalizationBase(): int return $this->weightNormalizationBase; } - protected function initializeVariations(): void + private function initializeVariations(): void { $normalizedVariationWeights = []; $lowestVariationWeights = []; $this->weightedGeneralizations = []; + /** @var array> $indexedGeneralizations */ $indexedGeneralizations = []; + /** @var array> $indexedSpecializations */ $indexedSpecializations = []; foreach ($this->getWeightedDimensionSpacePoints() as $generalizationHash => $generalization) { @@ -165,8 +164,8 @@ protected function initializeVariations(): void foreach ($generalization->dimensionValues as $rawDimensionId => $contentDimensionValue) { $dimensionId = new Dimension\ContentDimensionId($rawDimensionId); - /** @var Dimension\ContentDimension $dimension */ $dimension = $this->contentDimensionSource->getDimension($dimensionId); + assert($dimension !== null); foreach ($dimension->getSpecializations($contentDimensionValue) as $specializedValue) { $specializedDimensionSpacePoint = $generalization->dimensionSpacePoint ->vary($dimensionId, $specializedValue->value); @@ -206,16 +205,13 @@ protected function initializeVariations(): void } } - /** @var array> $indexedGeneralizations */ foreach ($indexedGeneralizations as $specializationHash => $generalizations) { $this->indexedGeneralizations[$specializationHash] = new DimensionSpacePointSet($generalizations); } - /** @var array> $indexedSpecializations */ foreach ($indexedSpecializations as $generalizationHash => $specializations) { $this->indexedSpecializations[$generalizationHash] = new DimensionSpacePointSet($specializations); } - /** @phpstan-ignore-next-line */ foreach ($this->weightedGeneralizations as $specializationHash => &$generalizationsByWeight) { ksort($generalizationsByWeight); } @@ -225,8 +221,10 @@ protected function initializeVariations(): void * @param array $normalizedVariationWeights * @param array>& $indexedGeneralizations * @param array>& $indexedSpecializations + * @param-out array> $indexedGeneralizations + * @param-out array> $indexedSpecializations */ - protected function initializeVariationsForDimensionSpacePointPair( + private function initializeVariationsForDimensionSpacePointPair( WeightedDimensionSpacePoint $specialization, WeightedDimensionSpacePoint $generalization, array $normalizedVariationWeights, @@ -237,9 +235,9 @@ protected function initializeVariationsForDimensionSpacePointPair( if (isset($indexedGeneralizations[$generalization->getIdentityHash()])) { $generalizations = $indexedGeneralizations[$generalization->getIdentityHash()]; foreach ($generalizations as $parentGeneralizationHash => $parentGeneralization) { - /** @var WeightedDimensionSpacePoint $weighedParent */ - $weighedParent = $this->getWeightedDimensionSpacePointByHash($parentGeneralizationHash); - $generalizationsToProcess[$parentGeneralizationHash] = $weighedParent; + $weightedParent = $this->getWeightedDimensionSpacePointByHash($parentGeneralizationHash); + assert($weightedParent !== null); + $generalizationsToProcess[$parentGeneralizationHash] = $weightedParent; } } @@ -265,7 +263,7 @@ protected function initializeVariationsForDimensionSpacePointPair( */ public function getIndexedSpecializations(DimensionSpacePoint $generalization): DimensionSpacePointSet { - if (is_null($this->indexedSpecializations)) { + if (!isset($this->indexedSpecializations)) { $this->initializeVariations(); } @@ -277,7 +275,7 @@ public function getIndexedSpecializations(DimensionSpacePoint $generalization): */ public function getIndexedGeneralizations(DimensionSpacePoint $specialization): DimensionSpacePointSet { - if (is_null($this->indexedGeneralizations)) { + if (!isset($this->indexedGeneralizations)) { $this->initializeVariations(); } @@ -291,7 +289,7 @@ public function getIndexedGeneralizations(DimensionSpacePoint $specialization): */ public function getWeightedSpecializations(DimensionSpacePoint $generalization): array { - if (is_null($this->weightedSpecializations)) { + if (!isset($this->weightedSpecializations)) { $this->initializeVariations(); } @@ -305,7 +303,7 @@ public function getWeightedSpecializations(DimensionSpacePoint $generalization): */ public function getWeightedGeneralizations(DimensionSpacePoint $specialization): array { - if (is_null($this->weightedGeneralizations)) { + if (!isset($this->weightedGeneralizations)) { $this->initializeVariations(); } @@ -344,7 +342,7 @@ public function getSpecializationSet( */ public function getPrimaryGeneralization(DimensionSpacePoint $specialization): ?DimensionSpacePoint { - if (is_null($this->primaryGeneralizations)) { + if (!isset($this->primaryGeneralizations)) { $this->initializeVariations(); } @@ -360,7 +358,7 @@ public function getVariantType(DimensionSpacePoint $subject, DimensionSpacePoint return VariantType::TYPE_SAME; } - if (is_null($this->indexedGeneralizations)) { + if (!isset($this->indexedGeneralizations)) { $this->initializeVariations(); } diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePoint.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePoint.php index 270547793a3..8a689481c0c 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePoint.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePoint.php @@ -14,9 +14,6 @@ namespace Neos\ContentRepository\Core\DimensionSpace; -use Neos\ContentRepository\Core\DimensionSpace\AbstractDimensionSpacePoint; -use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; - /** * A node's origin dimension space point. Defines in which point in the dimension space the node originates * (= is "at home"). Every node has exactly ONE OriginDimensionSpacePoint, but one or more {@see DimensionSpacePoint}s @@ -57,6 +54,16 @@ public static function fromArray(array $data): self return self::instance($data); } + /** + * Creates a dimension space point for a zero-dimensional content repository. + * + * This applies to content repositories without any dimensions configured. + */ + public static function createWithoutDimensions(): self + { + return self::fromArray([]); + } + /** * @param string $jsonString A JSON string representation, see jsonSerialize */ diff --git a/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePointSet.php b/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePointSet.php index c0f396b310b..2979c42542c 100644 --- a/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePointSet.php +++ b/Neos.ContentRepository.Core/Classes/DimensionSpace/OriginDimensionSpacePointSet.php @@ -5,7 +5,7 @@ namespace Neos\ContentRepository\Core\DimensionSpace; /* - * This file is part of the Neos.ContentRepository package. + * This file is part of the Neos.ContentRepository.Core package. * * (c) Contributors of the Neos Project - www.neos.io * @@ -31,11 +31,6 @@ final class OriginDimensionSpacePointSet implements \JsonSerializable, \Iterator */ private array $points; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - /** * @param array> $points */ @@ -55,7 +50,6 @@ public function __construct(array $points) } $this->points[$point->hash] = $point; } - $this->iterator = new \ArrayIterator($this->points); } public static function fromDimensionSpacePointSet(DimensionSpacePointSet $dimensionSpacePointSet): self @@ -135,11 +129,11 @@ public function count(): int } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->points; } /** diff --git a/Neos.ContentRepository.Core/Classes/EventStore/Events.php b/Neos.ContentRepository.Core/Classes/EventStore/Events.php index 2c9c13b7e76..05826f0d1cb 100644 --- a/Neos.ContentRepository.Core/Classes/EventStore/Events.php +++ b/Neos.ContentRepository.Core/Classes/EventStore/Events.php @@ -36,9 +36,12 @@ public static function fromArray(array $events): self return new self(...$events); } + /** + * @return \Traversable + */ public function getIterator(): \Traversable { - return new \ArrayIterator($this->events); + yield from $this->events; } /** diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index cc837381021..7397fbf44f4 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -159,12 +159,14 @@ protected function requireRootNodeTypeToBeUnoccupied( /** * @param NodeType $nodeType - * @throws NodeTypeNotFoundException + * @throws NodeTypeNotFoundException the configured child nodeType doesnt exist */ protected function requireTetheredDescendantNodeTypesToExist(NodeType $nodeType): void { - foreach ($nodeType->getAutoCreatedChildNodes() as $childNodeType) { - $this->requireTetheredDescendantNodeTypesToExist($childNodeType); + // this getter throws if any of the child nodeTypes doesnt exist! + $tetheredNodeTypes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType); + foreach ($tetheredNodeTypes as $tetheredNodeType) { + $this->requireTetheredDescendantNodeTypesToExist($tetheredNodeType); } } @@ -174,7 +176,7 @@ protected function requireTetheredDescendantNodeTypesToExist(NodeType $nodeType) */ protected function requireTetheredDescendantNodeTypesToNotBeOfTypeRoot(NodeType $nodeType): void { - foreach ($nodeType->getAutoCreatedChildNodes() as $tetheredChildNodeType) { + foreach ($this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType) as $tetheredChildNodeType) { if ($tetheredChildNodeType->isOfType(NodeTypeName::ROOT_NODE_TYPE_NAME)) { throw new NodeTypeIsOfTypeRoot( 'Node type "' . $nodeType->name->value . '" for tethered descendant is of type root.', @@ -299,12 +301,12 @@ protected function requireNodeTypeConstraintsImposedByParentToBeMet( } if ( $nodeName - && $parentsNodeType->hasAutoCreatedChildNode($nodeName) - && !$parentsNodeType->getTypeOfAutoCreatedChildNode($nodeName)?->name->equals($nodeType->name) + && $parentsNodeType->hasTetheredNode($nodeName) + && !$this->getNodeTypeManager()->getTypeOfTetheredNode($parentsNodeType, $nodeName)->name->equals($nodeType->name) ) { throw new NodeConstraintException( 'Node type "' . $nodeType->name->value . '" does not match configured "' - . $parentsNodeType->getTypeOfAutoCreatedChildNode($nodeName)?->name->value + . $this->getNodeTypeManager()->getTypeOfTetheredNode($parentsNodeType, $nodeName)->name->value . '" for auto created child nodes for parent type "' . $parentsNodeType->name->value . '" with name "' . $nodeName->value . '"' ); @@ -322,8 +324,8 @@ protected function areNodeTypeConstraintsImposedByParentValid( } if ( $nodeName - && $parentsNodeType->hasAutoCreatedChildNode($nodeName) - && !$parentsNodeType->getTypeOfAutoCreatedChildNode($nodeName)?->name->equals($nodeType->name) + && $parentsNodeType->hasTetheredNode($nodeName) + && !$this->getNodeTypeManager()->getTypeOfTetheredNode($parentsNodeType, $nodeName)->name->equals($nodeType->name) ) { return false; } @@ -360,8 +362,8 @@ protected function areNodeTypeConstraintsImposedByGrandparentValid( ): bool { if ( $parentNodeName - && $grandParentsNodeType->hasAutoCreatedChildNode($parentNodeName) - && !$grandParentsNodeType->allowsGrandchildNodeType($parentNodeName->value, $nodeType) + && $grandParentsNodeType->hasTetheredNode($parentNodeName) + && !$this->getNodeTypeManager()->isNodeTypeAllowedAsChildToTetheredNode($grandParentsNodeType, $parentNodeName, $nodeType) ) { return false; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php index 2896af0cd29..fb8e7de7aa0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeAggregateCommandHandler.php @@ -211,8 +211,8 @@ protected function checkConstraintsImposedByAncestors( } if ( $nodeAggregate->nodeName - && $parentsNodeType->hasAutoCreatedChildNode($nodeAggregate->nodeName) - && $parentsNodeType->getTypeOfAutoCreatedChildNode($nodeAggregate->nodeName)?->name + && $parentsNodeType->hasTetheredNode($nodeAggregate->nodeName) + && $this->nodeTypeManager->getTypeOfTetheredNode($parentsNodeType, $nodeAggregate->nodeName)->name !== $command->newNodeTypeName->value ) { throw new NodeConstraintException( @@ -232,9 +232,10 @@ protected function checkConstraintsImposedByAncestors( ); if ( $parentAggregate->nodeName - && $grandParentsNodeType->hasAutoCreatedChildNode($parentAggregate->nodeName) - && !$grandParentsNodeType->allowsGrandchildNodeType( - $parentAggregate->nodeName->value, + && $grandParentsNodeType->hasTetheredNode($parentAggregate->nodeName) + && !$this->nodeTypeManager->isNodeTypeAllowedAsChildToTetheredNode( + $grandParentsNodeType, + $parentAggregate->nodeName, $newNodeType ) ) { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php index 545efc0d80d..8f67052dd59 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -89,6 +90,34 @@ public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPrope ); } + /** + * Specify explicitly the node aggregate ids for the tethered children {@see tetheredDescendantNodeAggregateIds}. + * + * In case you want to create a batch of commands where one creates the node and a succeeding command needs + * a tethered node aggregate id, you need to generate the child node aggregate ids in advance. + * + * _Alternatively you would need to fetch the created tethered node first from the subgraph. + * {@see ContentSubgraphInterface::findChildNodeConnectedThroughEdgeName()}_ + * + * The helper method {@see NodeAggregateIdsByNodePaths::createForNodeType()} will generate recursively + * node aggregate ids for every tethered child node: + * + * ```php + * $tetheredDescendantNodeAggregateIds = NodeAggregateIdsByNodePaths::createForNodeType( + * $command->nodeTypeName, + * $nodeTypeManager + * ); + * $command = $command->withTetheredDescendantNodeAggregateIds($tetheredDescendantNodeAggregateIds): + * ``` + * + * The generated node aggregate id for the tethered node "main" is this way known before the command is issued: + * + * ```php + * $mainNodeAggregateId = $command->tetheredDescendantNodeAggregateIds->getNodeAggregateId(NodePath::fromString('main')); + * ``` + * + * Generating the node aggregate ids from user land is totally optional. + */ public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self { return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php index 1eba8ab7399..620360b7725 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePaths.php @@ -1,7 +1,5 @@ $array */ @@ -95,7 +110,34 @@ public static function fromJsonString(string $jsonString): self public function merge(self $other): self { - return new self(array_merge($this->nodeAggregateIds, $other->getNodeAggregateIds())); + return new self(array_merge($this->nodeAggregateIds, $other->nodeAggregateIds)); + } + + public function completeForNodeOfType(NodeTypeName $nodeTypeName, NodeTypeManager $nodeTypeManager): self + { + return self::createForNodeType($nodeTypeName, $nodeTypeManager) + ->merge($this); + } + + /** + * @return array + */ + private static function createNodeAggregateIdsForNodeType( + NodeTypeName $nodeTypeName, + NodeTypeManager $nodeTypeManager, + ?string $pathPrefix = null + ): array { + $nodeAggregateIds = []; + foreach ($nodeTypeManager->getTetheredNodesConfigurationForNodeType($nodeTypeManager->getNodeType($nodeTypeName)) as $nodeName => $childNodeType) { + $path = $pathPrefix ? $pathPrefix . '/' . $nodeName : $nodeName; + $nodeAggregateIds[$path] = NodeAggregateId::create(); + $nodeAggregateIds = array_merge( + $nodeAggregateIds, + self::createNodeAggregateIdsForNodeType($childNodeType->name, $nodeTypeManager, $path) + ); + } + + return $nodeAggregateIds; } public function getNodeAggregateId(NodePath $nodePath): ?NodeAggregateId diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php index 46ef4e6a46b..739a7b38a5c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php @@ -31,6 +31,7 @@ use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\Infrastructure\Property\PropertyType; use Neos\ContentRepository\Core\NodeType\NodeType; +use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; @@ -61,6 +62,8 @@ abstract protected function requireNodeTypeToBeOfTypeRoot(NodeType $nodeType): v abstract protected function getPropertyConverter(): PropertyConverter; + abstract protected function getNodeTypeManager(): NodeTypeManager; + private function handleCreateNodeAggregateWithNode( CreateNodeAggregateWithNode $command, ContentRepository $contentRepository @@ -201,9 +204,9 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( $contentRepository ); } - $descendantNodeAggregateIds = self::populateNodeAggregateIds( - $nodeType, - $command->tetheredDescendantNodeAggregateIds + $descendantNodeAggregateIds = $command->tetheredDescendantNodeAggregateIds->completeForNodeOfType( + $command->nodeTypeName, + $this->nodeTypeManager ); // Write the auto-created descendant node aggregate ids back to the command; // so that when rebasing the command, it stays fully deterministic. @@ -282,7 +285,7 @@ private function handleTetheredChildNodes( ContentRepository $contentRepository, ): Events { $events = []; - foreach ($nodeType->getAutoCreatedChildNodes() as $rawNodeName => $childNodeType) { + foreach ($this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($nodeType) as $rawNodeName => $childNodeType) { assert($childNodeType instanceof NodeType); $nodeName = NodeName::fromString($rawNodeName); $childNodePath = $nodePath @@ -340,29 +343,4 @@ private function createTetheredWithNode( $precedingNodeAggregateId ); } - - protected static function populateNodeAggregateIds( - NodeType $nodeType, - ?NodeAggregateIdsByNodePaths $nodeAggregateIds, - NodePath $childPath = null - ): NodeAggregateIdsByNodePaths { - if ($nodeAggregateIds === null) { - $nodeAggregateIds = NodeAggregateIdsByNodePaths::createEmpty(); - } - // TODO: handle Multiple levels of autocreated child nodes - foreach ($nodeType->getAutoCreatedChildNodes() as $rawChildName => $childNodeType) { - $childName = NodeName::fromString($rawChildName); - $childPath = $childPath - ? $childPath->appendPathSegment($childName) - : NodePath::fromString($childName->value); - if (!$nodeAggregateIds->getNodeAggregateId($childPath)) { - $nodeAggregateIds = $nodeAggregateIds->add( - $childPath, - NodeAggregateId::create() - ); - } - } - - return $nodeAggregateIds; - } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeReferencesSnapshot.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeReferencesSnapshot.php index aa9a8ec034e..f29ea76f26c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeReferencesSnapshot.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeReferencesSnapshot.php @@ -18,7 +18,7 @@ /** * @implements \IteratorAggregate - * @internal not yet finished + * @internal todo not yet finished */ final class NodeReferencesSnapshot implements \IteratorAggregate, \Countable, \JsonSerializable { @@ -27,18 +27,12 @@ final class NodeReferencesSnapshot implements \IteratorAggregate, \Countable, \J */ private array $references; - /** - * @var \ArrayIterator - */ - protected \ArrayIterator $iterator; - /** * @param array $references */ private function __construct(array $references) { $this->references = $references; - $this->iterator = new \ArrayIterator($references); } public function merge(self $other): self @@ -80,6 +74,7 @@ public static function fromArray(array $nodeReferences): self /** * @todo what is this supposed to do? + * Good question. */ public static function fromReferences(References $nodeReferences): self { @@ -89,11 +84,11 @@ public static function fromReferences(References $nodeReferences): self } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->references; } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeSubtreeSnapshot.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeSubtreeSnapshot.php index c627cbca972..d4b42b6c57b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeSubtreeSnapshot.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Dto/NodeSubtreeSnapshot.php @@ -8,7 +8,6 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindReferencesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -51,7 +50,6 @@ public static function fromSubgraphAndStartNode(ContentSubgraphInterface $subgra ) { $childNodes[] = self::fromSubgraphAndStartNode($subgraph, $sourceChildNode); } - /** @var PropertyCollectionInterface $properties */ $properties = $sourceNode->properties; return new self( diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php index 5345f0bfd69..9b1f162e6fe 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Dto/SerializedPropertyValues.php @@ -27,20 +27,14 @@ * @implements \IteratorAggregate * @api used as part of commands/events */ -final class SerializedPropertyValues implements \IteratorAggregate, \Countable, \JsonSerializable +final readonly class SerializedPropertyValues implements \IteratorAggregate, \Countable, \JsonSerializable { - /** - * @var \ArrayIterator - */ - protected \ArrayIterator $iterator; - /** * @param array $values */ private function __construct( - public readonly array $values + public array $values ) { - $this->iterator = new \ArrayIterator($this->values); } public static function createEmpty(): self @@ -146,11 +140,11 @@ public function getProperty(string $propertyName): ?SerializedPropertyValue } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->values; } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php index 43567f8e721..18b426add1b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php @@ -1,7 +1,7 @@ - */ - private \ArrayIterator $iterator; - /** * @param array $values */ private function __construct(array $values) { $this->mappings = $values; - $this->iterator = new \ArrayIterator($values); } /** @@ -72,11 +66,11 @@ public static function create(CoverageNodeMoveMapping ...$coverageNodeMoveMappin /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->mappings; } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php index 1a825553ef5..b7fa09da0eb 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php @@ -27,18 +27,12 @@ final class OriginNodeMoveMappings implements \IteratorAggregate, \Countable, \J */ private array $mappings; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - /** * @param array $values */ private function __construct(array $values) { $this->mappings = $values; - $this->iterator = new \ArrayIterator($values); } /** @@ -73,11 +67,11 @@ public static function create(OriginNodeMoveMapping ...$originNodeMoveMappings): } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->mappings; } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php index d0ea7f49e90..ce969843ef1 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php @@ -25,7 +25,7 @@ final class SetNodeReferences implements CommandInterface * @param ReferenceName $referenceName Name of the reference to set * @param NodeReferencesToWrite $references Unserialized reference(s) to set */ - public function __construct( + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $sourceNodeAggregateId, public readonly OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/NodeReferencesToWrite.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/NodeReferencesToWrite.php index 99b329a2479..fd6f36af88b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/NodeReferencesToWrite.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/NodeReferencesToWrite.php @@ -14,7 +14,6 @@ namespace Neos\ContentRepository\Core\Feature\NodeReferencing\Dto; -use JetBrains\PhpStorm\Internal\TentativeType; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; @@ -24,24 +23,23 @@ * * We expect the value types to match the NodeType's property types (this is validated in the command handler). * - * @implements \IteratorAggregate + * @implements \IteratorAggregate * @api used as part of commands */ -final class NodeReferencesToWrite implements \IteratorAggregate, \JsonSerializable +final readonly class NodeReferencesToWrite implements \IteratorAggregate, \JsonSerializable { /** - * @var array + * @var array */ - public readonly array $references; + public array $references; private function __construct(NodeReferenceToWrite ...$references) { - /** @var array $references */ $this->references = $references; } /** - * @param array $references + * @param array $references */ public static function fromReferences(array $references): self { @@ -65,7 +63,7 @@ public static function fromNodeAggregateIds(NodeAggregateIds $nodeAggregateIds): return new self(...array_map( fn (NodeAggregateId $nodeAggregateId): NodeReferenceToWrite => new NodeReferenceToWrite($nodeAggregateId, null), - $nodeAggregateIds->getIterator()->getArrayCopy() + iterator_to_array($nodeAggregateIds) )); } @@ -78,15 +76,15 @@ public static function fromJsonString(string $jsonString): self } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->references); + yield from $this->references; } /** - * @return array + * @return array */ public function jsonSerialize(): array { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/SerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/SerializedNodeReferences.php index dad3345ef40..85dc99aa39c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/SerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Dto/SerializedNodeReferences.php @@ -20,24 +20,23 @@ /** * A collection of SerializedNodeReference objects, to be used when creating reference relations. * - * @implements \IteratorAggregate + * @implements \IteratorAggregate * @api used as part of commands/events */ -final class SerializedNodeReferences implements \IteratorAggregate, \Countable, \JsonSerializable +final readonly class SerializedNodeReferences implements \IteratorAggregate, \Countable, \JsonSerializable { /** - * @var array + * @var array */ - public readonly array $references; + public array $references; private function __construct(SerializedNodeReference ...$references) { - /** @var array $references */ $this->references = $references; } /** - * @param array $references + * @param array $references */ public static function fromReferences(array $references): self { @@ -45,7 +44,7 @@ public static function fromReferences(array $references): self } /** - * @param array> $referenceData + * @param array> $referenceData */ public static function fromArray(array $referenceData): self { @@ -59,8 +58,8 @@ public static function fromNodeAggregateIds(NodeAggregateIds $nodeAggregateIds): { return new self(...array_map( static fn (NodeAggregateId $nodeAggregateId): SerializedNodeReference - => new SerializedNodeReference($nodeAggregateId, null), - $nodeAggregateIds->getIterator()->getArrayCopy() + => new SerializedNodeReference($nodeAggregateId, null), + iterator_to_array($nodeAggregateIds) )); } @@ -75,11 +74,11 @@ public function merge(self $other): self } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->references); + yield from $this->references; } public function count(): int @@ -88,7 +87,7 @@ public function count(): int } /** - * @return array + * @return array */ public function jsonSerialize(): array { diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php index 060135a4f4e..6c3836dc81c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php @@ -33,31 +33,27 @@ final class RemoveNodeAggregate implements MatchableWithNodeIdToPublishOrDiscardInterface { /** - * @param ContentStreamId $contentStreamId + * @param ContentStreamId $contentStreamId The content stream in which the remove operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to remove + * @param DimensionSpacePoint $coveredDimensionSpacePoint One of the dimension space points covered by the node aggregate in which the user intends to remove it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be removed + * @param NodeAggregateId|null $removalAttachmentPoint Internal. It stores the document node id of the removed node, as that is what the UI needs later on for the change display. {@see self::withRemovalAttachmentPoint()} */ - public function __construct( + private function __construct( public readonly ContentStreamId $contentStreamId, public readonly NodeAggregateId $nodeAggregateId, - /** One of the dimension space points covered by the node aggregate in which the user intends to remove it */ public readonly DimensionSpacePoint $coveredDimensionSpacePoint, public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, - /** - * This is usually the NodeAggregateId of the parent node of the deleted node. It is needed for instance - * in the Neos UI for the following scenario: - * - when removing a node, you still need to be able to publish the removal. - * - For this to work, the Neos UI needs to know the id of the removed Node, **on the page - * where the removal happened** (so that the user can decide to publish a single page INCLUDING the removal - * on the page) - * - Because this command will *remove* the edge, - * we cannot know the position in the tree after doing the removal anymore. - * - * That's why we need this field: For the Neos UI, it stores the document node of the removed node - * (see Remove.php), as that is what the UI needs lateron for the change display. - */ public readonly ?NodeAggregateId $removalAttachmentPoint ) { } + /** + * @param ContentStreamId $contentStreamId The content stream in which the remove operation is to be performed + * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to remove + * @param DimensionSpacePoint $coveredDimensionSpacePoint One of the dimension space points covered by the node aggregate in which the user intends to remove it + * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be removed + */ public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self { return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy, null); @@ -80,6 +76,14 @@ public static function fromArray(array $array): self } /** + * This adds usually the NodeAggregateId of the parent document node of the deleted node. + * It is needed for instance in the Neos UI for the following scenario: + * - when removing a node, you still need to be able to publish the removal. + * - For this to work, the Neos UI needs to know the id of the removed Node, **on the page where the removal happened** + * (so that the user can decide to publish a single page INCLUDING the removal on the page) + * - Because this command will *remove* the edge, + * we cannot know the position in the tree after doing the removal anymore. + * * @param NodeAggregateId $removalAttachmentPoint * @internal */ diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php index f174092536a..16306a537e8 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php @@ -21,11 +21,11 @@ use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\Common\NodeAggregateEventPublisher; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; -use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Event\NodeAggregateTypeWasChanged; use Neos\ContentRepository\Core\NodeType\NodeType; +use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; @@ -36,7 +36,6 @@ use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\EventStore\Model\EventStream\ExpectedVersion; @@ -49,6 +48,8 @@ */ trait NodeTypeChange { + abstract protected function getNodeTypeManager(): NodeTypeManager; + abstract protected function requireProjectedNodeAggregate( ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, @@ -87,12 +88,6 @@ abstract protected function areNodeTypeConstraintsImposedByGrandparentValid( NodeType $nodeType ): bool; - abstract protected static function populateNodeAggregateIds( - NodeType $nodeType, - NodeAggregateIdsByNodePaths $nodeAggregateIds, - NodePath $childPath = null - ): NodeAggregateIdsByNodePaths; - abstract protected function createEventsForMissingTetheredNode( NodeAggregate $parentNodeAggregate, Node $parentNode, @@ -156,9 +151,9 @@ private function handleChangeNodeAggregateType( /************** * Preparation - make the command fully deterministic in case of rebase **************/ - $descendantNodeAggregateIds = static::populateNodeAggregateIds( - $newNodeType, - $command->tetheredDescendantNodeAggregateIds + $descendantNodeAggregateIds = $command->tetheredDescendantNodeAggregateIds->completeForNodeOfType( + $newNodeType->name, + $this->nodeTypeManager ); // Write the auto-created descendant node aggregate ids back to the command; // so that when rebasing the command, it stays fully deterministic. @@ -190,7 +185,7 @@ private function handleChangeNodeAggregateType( } // new tethered child nodes - $expectedTetheredNodes = $newNodeType->getAutoCreatedChildNodes(); + $expectedTetheredNodes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($newNodeType); foreach ($nodeAggregate->getNodes() as $node) { assert($node instanceof Node); foreach ($expectedTetheredNodes as $serializedTetheredNodeName => $expectedTetheredNodeType) { @@ -371,7 +366,7 @@ private function deleteObsoleteTetheredNodesWhenChangingNodeType( NodeType $newNodeType, ContentRepository $contentRepository ): Events { - $expectedTetheredNodes = $newNodeType->getAutoCreatedChildNodes(); + $expectedTetheredNodes = $this->getNodeTypeManager()->getTetheredNodesConfigurationForNodeType($newNodeType); $events = []; // find disallowed tethered nodes diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index d3bd1557328..7fc7d47f176 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -476,6 +476,10 @@ private function extractCommandsFromContentStreamMetadata( $commandToRebaseClass ), 1547815341); } + /** + * The "fromArray" might be declared via {@see RebasableToOtherContentStreamsInterface::fromArray()} + * or any other command can just implement it. + */ $commands[] = $commandToRebaseClass::fromArray($commandToRebasePayload); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php index 873d00e5925..5f4100b6e2f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php @@ -29,29 +29,13 @@ final class PublishIndividualNodesFromWorkspace implements CommandInterface /** * @param WorkspaceName $workspaceName Name of the affected workspace * @param NodeIdsToPublishOrDiscard $nodesToPublish Ids of the nodes to publish or discard - * @param ContentStreamId $contentStreamIdForMatchingPart The id of the new content stream that will contain all events to be published - * @param ContentStreamId $contentStreamIdForRemainingPart The id of the new content stream that will contain all remaining events + * @param ContentStreamId $contentStreamIdForMatchingPart The id of the new content stream that will contain all events to be published {@see self::withContentStreamIdForMatchingPart()} + * @param ContentStreamId $contentStreamIdForRemainingPart The id of the new content stream that will contain all remaining events {@see self::withContentStreamIdForRemainingPart()} */ private function __construct( public readonly WorkspaceName $workspaceName, public readonly NodeIdsToPublishOrDiscard $nodesToPublish, - /** - * during the publish process, we sort the events so that the events we want to publish - * come first. In this process, two new content streams are generated: - * - the first one contains all events which we want to publish - * - the second one is based on the first one, and contains all the remaining events (which we want to keep - * in the user workspace). - * - * This property contains the ID of the first content stream, so that this command - * can run fully deterministic - we need this for the test cases. - */ public readonly ContentStreamId $contentStreamIdForMatchingPart, - /** - * See the description of {@see $contentStreamIdForMatchingPart}. - * - * This property contains the ID of the second content stream, so that this command - * can run fully deterministic - we need this for the test cases. - */ public readonly ContentStreamId $contentStreamIdForRemainingPart ) { } @@ -70,11 +54,27 @@ public static function create(WorkspaceName $workspaceName, NodeIdsToPublishOrDi ); } + /** + * During the publish process, we sort the events so that the events we want to publish + * come first. In this process, two new content streams are generated: + * - the first one contains all events which we want to publish + * - the second one is based on the first one, and contains all the remaining events (which we want to keep + * in the user workspace). + * + * This method adds the ID of the first content stream, so that the command + * can run fully deterministic - we need this for the test cases. + */ public function withContentStreamIdForMatchingPart(ContentStreamId $contentStreamIdForMatchingPart): self { return new self($this->workspaceName, $this->nodesToPublish, $contentStreamIdForMatchingPart, $this->contentStreamIdForRemainingPart); } + /** + * See the description of {@see self::withContentStreamIdForMatchingPart()}. + * + * This property adds the ID of the second content stream, so that the command + * can run fully deterministic - we need this for the test cases. + */ public function withContentStreamIdForRemainingPart(ContentStreamId $contentStreamIdForRemainingPart): self { return new self($this->workspaceName, $this->nodesToPublish, $this->contentStreamIdForMatchingPart, $contentStreamIdForRemainingPart); diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdsToPublishOrDiscard.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdsToPublishOrDiscard.php index 92579c409d0..a5bd6a04264 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdsToPublishOrDiscard.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdsToPublishOrDiscard.php @@ -17,22 +17,17 @@ /** * A collection of NodeIdToPublish objects, to be used when publishing or discarding a set of nodes * - * @implements \IteratorAggregate + * @implements \IteratorAggregate * @api used as part of commands */ -final class NodeIdsToPublishOrDiscard implements \IteratorAggregate, \Countable, \JsonSerializable +final readonly class NodeIdsToPublishOrDiscard implements \IteratorAggregate, \Countable, \JsonSerializable { - /** - * @var array - */ - public readonly array $nodeIds; - /** * @param array $nodeIds */ - private function __construct(array $nodeIds) - { - $this->nodeIds = $nodeIds; + private function __construct( + public array $nodeIds + ) { } public static function create(NodeIdToPublishOrDiscard ...$nodeIds): self @@ -41,7 +36,7 @@ public static function create(NodeIdToPublishOrDiscard ...$nodeIds): self } /** - * @param array> $nodeIdData + * @param array> $nodeIdData */ public static function fromArray(array $nodeIdData): self { @@ -57,11 +52,11 @@ public function merge(self $other): self } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->nodeIds); + yield from $this->nodeIds; } public function count(): int @@ -70,7 +65,7 @@ public function count(): int } /** - * @return array + * @return array */ public function jsonSerialize(): array { diff --git a/Neos.ContentRepository.Core/Classes/NodeType/ConstraintCheck.php b/Neos.ContentRepository.Core/Classes/NodeType/ConstraintCheck.php new file mode 100644 index 00000000000..91058e9b8b8 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/NodeType/ConstraintCheck.php @@ -0,0 +1,137 @@ + $constraints + */ + public function __construct( + private readonly array $constraints + ) { + } + + public function isNodeTypeAllowed(NodeType $nodeType): bool + { + $directConstraintsResult = $this->isNodeTypeAllowedByDirectConstraints($nodeType); + if ($directConstraintsResult !== null) { + return $directConstraintsResult; + } + + $inheritanceConstraintsResult = $this->isNodeTypeAllowedByInheritanceConstraints($nodeType); + if ($inheritanceConstraintsResult !== null) { + return $inheritanceConstraintsResult; + } + + if (isset($this->constraints['*'])) { + return (bool)$this->constraints['*']; + } + + return false; + } + + /** + * @return boolean|null true if the passed $nodeType is allowed by the $constraints, null if couldn't be decided + */ + protected function isNodeTypeAllowedByDirectConstraints(NodeType $nodeType): ?bool + { + if ($this->constraints === []) { + return true; + } + + if ( + array_key_exists($nodeType->name->value, $this->constraints) + && $this->constraints[$nodeType->name->value] === true + ) { + return true; + } + + if ( + array_key_exists($nodeType->name->value, $this->constraints) + && $this->constraints[$nodeType->name->value] === false + ) { + return false; + } + + return null; + } + + /** + * This method loops over the constraints and finds node types that the given node type inherits from. For all + * matched super types, their super types are traversed to find the closest super node with a constraint which + * is used to evaluated if the node type is allowed. It finds the closest results for true and false, and uses + * the distance to choose which one wins (lowest). If no result is found the node type is allowed. + * + * @return ?boolean (null if no constraint matched) + */ + protected function isNodeTypeAllowedByInheritanceConstraints(NodeType $nodeType): ?bool + { + $constraintDistanceForTrue = null; + $constraintDistanceForFalse = null; + foreach ($this->constraints as $superType => $constraint) { + if ($nodeType->isOfType($superType)) { + $distance = $this->traverseSuperTypes($nodeType, $superType, 0); + + if ( + $constraint === true + && ($constraintDistanceForTrue === null || $constraintDistanceForTrue > $distance) + ) { + $constraintDistanceForTrue = $distance; + } + if ( + $constraint === false + && ($constraintDistanceForFalse === null || $constraintDistanceForFalse > $distance) + ) { + $constraintDistanceForFalse = $distance; + } + } + } + + if ($constraintDistanceForTrue !== null && $constraintDistanceForFalse !== null) { + return $constraintDistanceForTrue < $constraintDistanceForFalse; + } + + if ($constraintDistanceForFalse !== null) { + return false; + } + + if ($constraintDistanceForTrue !== null) { + return true; + } + + return null; + } + + /** + * This method traverses the given node type to find the first super type that matches the constraint node type. + * In case the hierarchy has more than one way of finding a path to the node type it's not taken into account, + * since the first matched is returned. This is accepted on purpose for performance reasons and due to the fact + * that such hierarchies should be avoided. + * + * Returns null if no NodeType matched + */ + protected function traverseSuperTypes( + NodeType $currentNodeType, + string $constraintNodeTypeName, + int $distance + ): ?int { + if ($currentNodeType->name->value === $constraintNodeTypeName) { + return $distance; + } + + $distance++; + foreach ($currentNodeType->getDeclaredSuperTypes() as $superType) { + $result = $this->traverseSuperTypes($superType, $constraintNodeTypeName, $distance); + if ($result !== null) { + return $result; + } + } + + return null; + } +} diff --git a/Neos.ContentRepository.Core/Classes/NodeType/Exception/TetheredNodeNotConfigured.php b/Neos.ContentRepository.Core/Classes/NodeType/Exception/TetheredNodeNotConfigured.php new file mode 100644 index 00000000000..00f6c4fd3e1 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/NodeType/Exception/TetheredNodeNotConfigured.php @@ -0,0 +1,10 @@ + $declaredSuperTypes Parent types of this node type * @param array $configuration the configuration for this node type which is defined in the schema * @throws \InvalidArgumentException + * + * @internal */ public function __construct( NodeTypeName $name, array $declaredSuperTypes, array $configuration, - private readonly NodeTypeManager $nodeTypeManager, private readonly NodeLabelGeneratorFactoryInterface $nodeLabelGeneratorFactory ) { $this->name = $name; @@ -223,15 +217,6 @@ protected function applyPostprocessing(array $fullConfiguration): array return $fullConfiguration; } - /** - * Returns the name of this node type - * @deprecated use "name" property directly - */ - public function getName(): string - { - return $this->name->value; - } - /** * Return boolean true if marked abstract */ @@ -290,19 +275,23 @@ public function isAggregate(): bool * @return boolean true if this node type is of the given kind, otherwise false * @api */ - public function isOfType(string $nodeType): bool + public function isOfType(string|NodeTypeName $nodeTypeName): bool { - if ($nodeType === $this->name->value) { + if (!is_string($nodeTypeName)) { + $nodeTypeName = $nodeTypeName->value; + } + if ($nodeTypeName === $this->name->value) { return true; } - if (array_key_exists($nodeType, $this->declaredSuperTypes) && $this->declaredSuperTypes[$nodeType] === null) { + if (array_key_exists($nodeTypeName, $this->declaredSuperTypes) && $this->declaredSuperTypes[$nodeTypeName] === null) { return false; } foreach ($this->declaredSuperTypes as $superType) { - if ($superType !== null && $superType->isOfType($nodeType) === true) { + if ($superType !== null && $superType->isOfType($nodeTypeName) === true) { return true; } } + return false; } @@ -328,6 +317,7 @@ public function getLocalConfiguration(): array public function getFullConfiguration(): array { $this->initialize(); + return $this->fullConfiguration; } @@ -351,6 +341,7 @@ public function hasConfiguration(string $configurationPath): bool public function getConfiguration(string $configurationPath): mixed { $this->initialize(); + return ObjectAccess::getPropertyPath($this->fullConfiguration, $configurationPath); } @@ -463,234 +454,50 @@ public function getDefaultValuesForProperties(): array } /** - * Return an array with child nodes which should be automatically created - * - * @return array the key of this array is the name of the child, and the value its NodeType. - * @api + * @return bool true if $nodeName is an autocreated child node, false otherwise */ - public function getAutoCreatedChildNodes(): array + public function hasTetheredNode(NodeName $nodeName): bool { $this->initialize(); - if (!isset($this->fullConfiguration['childNodes'])) { - return []; - } - - $autoCreatedChildNodes = []; - foreach ($this->fullConfiguration['childNodes'] as $childNodeName => $childNodeConfiguration) { - if (isset($childNodeConfiguration['type'])) { - $autoCreatedChildNodes[NodeName::transliterateFromString($childNodeName)->value] - = $this->nodeTypeManager->getNodeType($childNodeConfiguration['type']); + foreach ($this->fullConfiguration['childNodes'] ?? [] as $rawChildNodeName => $configurationForChildNode) { + if (isset($configurationForChildNode['type'])) { + if (NodeName::transliterateFromString($rawChildNodeName)->equals($nodeName)) { + return true; + } } } - - return $autoCreatedChildNodes; + return false; } /** - * @return bool true if $nodeName is an autocreated child node, false otherwise + * @throws TetheredNodeNotConfigured if the requested tethred node is not configured. Check via {@see NodeType::hasTetheredNode()}. */ - public function hasAutoCreatedChildNode(NodeName $nodeName): bool + public function getNodeTypeNameOfTetheredNode(NodeName $nodeName): NodeTypeName { $this->initialize(); - return isset($this->fullConfiguration['childNodes'][$nodeName->value]); - } - - /** - * @throws NodeTypeNotFoundException - */ - public function getTypeOfAutoCreatedChildNode(NodeName $nodeName): ?NodeType - { - return isset($this->fullConfiguration['childNodes'][$nodeName->value]['type']) - ? $this->nodeTypeManager->getNodeType($this->fullConfiguration['childNodes'][$nodeName->value]['type']) - : null; + foreach ($this->fullConfiguration['childNodes'] ?? [] as $rawChildNodeName => $configurationForChildNode) { + if (isset($configurationForChildNode['type'])) { + if (NodeName::transliterateFromString($rawChildNodeName)->equals($nodeName)) { + return NodeTypeName::fromString($configurationForChildNode['type']); + } + } + } + throw new TetheredNodeNotConfigured(sprintf('The child node "%s" is not configured for node type "%s"', $nodeName->value, $this->name->value), 1694786811); } - /** * Checks if the given NodeType is acceptable as sub-node with the configured constraints, * not taking constraints of auto-created nodes into account. Thus, this method only returns * the correct result if called on NON-AUTO-CREATED nodes! * - * Otherwise, allowsGrandchildNodeType() needs to be called on the *parent node type*. + * Otherwise, isNodeTypeAllowedAsChildToTetheredNode() needs to be called on the *parent node type*. * * @return boolean true if the $nodeType is allowed as child node, false otherwise. */ public function allowsChildNodeType(NodeType $nodeType): bool { $constraints = $this->getConfiguration('constraints.nodeTypes') ?: []; - - return $this->isNodeTypeAllowedByConstraints($nodeType, $constraints); - } - - /** - * Checks if the given $nodeType is allowed as a childNode of the given $childNodeName - * (which must be auto-created in $this NodeType). - * - * Only allowed to be called if $childNodeName is auto-created. - * - * @param string $childNodeName The name of a configured childNode of this NodeType - * @param NodeType $nodeType The NodeType to check constraints for. - * @return bool true if the $nodeType is allowed as grandchild node, false otherwise. - * @throws \InvalidArgumentException If the given $childNodeName is not configured to be auto-created in $this. - */ - public function allowsGrandchildNodeType(string $childNodeName, NodeType $nodeType): bool - { - $autoCreatedChildNodes = $this->getAutoCreatedChildNodes(); - if (!isset($autoCreatedChildNodes[$childNodeName])) { - throw new \InvalidArgumentException( - 'The method "allowsGrandchildNodeType" can only be used on auto-created childNodes, ' - . 'given $childNodeName "' . $childNodeName . '" is not auto-created.', - 1403858395 - ); - } - $constraints = $autoCreatedChildNodes[$childNodeName]->getConfiguration('constraints.nodeTypes') ?: []; - - $childNodeConfiguration = []; - foreach ($this->getConfiguration('childNodes') as $name => $configuration) { - $childNodeConfiguration[NodeName::transliterateFromString($name)->value] = $configuration; - } - $childNodeConstraintConfiguration = ObjectAccess::getPropertyPath( - $childNodeConfiguration, - $childNodeName . '.constraints.nodeTypes' - ) ?: []; - - $constraints = Arrays::arrayMergeRecursiveOverrule($constraints, $childNodeConstraintConfiguration); - - return $this->isNodeTypeAllowedByConstraints($nodeType, $constraints); - } - - /** - * Internal method to check whether the passed-in $nodeType is allowed by the $constraints array. - * - * $constraints is an associative array where the key is the Node Type Name. If the value is "true", - * the node type is explicitly allowed. If the value is "false", the node type is explicitly denied. - * If nothing is specified, the fallback "*" is used. If that one is also not specified, we DENY by - * default. - * - * Super types of the given node types are also checked, so if a super type is constrained - * it will also take affect on the inherited node types. The closest constrained super type match is used. - * - * @param array $constraints - */ - protected function isNodeTypeAllowedByConstraints(NodeType $nodeType, array $constraints): bool - { - $directConstraintsResult = $this->isNodeTypeAllowedByDirectConstraints($nodeType, $constraints); - if ($directConstraintsResult !== null) { - return $directConstraintsResult; - } - - $inheritanceConstraintsResult = $this->isNodeTypeAllowedByInheritanceConstraints($nodeType, $constraints); - if ($inheritanceConstraintsResult !== null) { - return $inheritanceConstraintsResult; - } - - if (isset($constraints['*'])) { - return (bool)$constraints['*']; - } - - return false; - } - - /** - * @param array $constraints - * @return boolean true if the passed $nodeType is allowed by the $constraints - */ - protected function isNodeTypeAllowedByDirectConstraints(NodeType $nodeType, array $constraints): ?bool - { - if ($constraints === []) { - return true; - } - - if ( - array_key_exists($nodeType->name->value, $constraints) - && $constraints[$nodeType->name->value] === true - ) { - return true; - } - - if ( - array_key_exists($nodeType->name->value, $constraints) - && $constraints[$nodeType->name->value] === false - ) { - return false; - } - - return null; - } - - /** - * This method loops over the constraints and finds node types that the given node type inherits from. For all - * matched super types, their super types are traversed to find the closest super node with a constraint which - * is used to evaluated if the node type is allowed. It finds the closest results for true and false, and uses - * the distance to choose which one wins (lowest). If no result is found the node type is allowed. - * - * @param array $constraints - * @return ?boolean (null if no constraint matched) - */ - protected function isNodeTypeAllowedByInheritanceConstraints(NodeType $nodeType, array $constraints): ?bool - { - $constraintDistanceForTrue = null; - $constraintDistanceForFalse = null; - foreach ($constraints as $superType => $constraint) { - if ($nodeType->isOfType($superType)) { - $distance = $this->traverseSuperTypes($nodeType, $superType, 0); - - if ( - $constraint === true - && ($constraintDistanceForTrue === null || $constraintDistanceForTrue > $distance) - ) { - $constraintDistanceForTrue = $distance; - } - if ( - $constraint === false - && ($constraintDistanceForFalse === null || $constraintDistanceForFalse > $distance) - ) { - $constraintDistanceForFalse = $distance; - } - } - } - - if ($constraintDistanceForTrue !== null && $constraintDistanceForFalse !== null) { - return $constraintDistanceForTrue < $constraintDistanceForFalse; - } - - if ($constraintDistanceForFalse !== null) { - return false; - } - - if ($constraintDistanceForTrue !== null) { - return true; - } - - return null; - } - - /** - * This method traverses the given node type to find the first super type that matches the constraint node type. - * In case the hierarchy has more than one way of finding a path to the node type it's not taken into account, - * since the first matched is returned. This is accepted on purpose for performance reasons and due to the fact - * that such hierarchies should be avoided. - * - * Returns null if no NodeType matched - */ - protected function traverseSuperTypes( - NodeType $currentNodeType, - string $constraintNodeTypeName, - int $distance - ): ?int { - if ($currentNodeType->getName() === $constraintNodeTypeName) { - return $distance; - } - - $distance++; - foreach ($currentNodeType->getDeclaredSuperTypes() as $superType) { - $result = $this->traverseSuperTypes($superType, $constraintNodeTypeName, $distance); - if ($result !== null) { - return $result; - } - } - - return null; + return (new ConstraintCheck($constraints))->isNodeTypeAllowed($nodeType); } /** diff --git a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php index a2f2be011a8..ba6ec1cfd8e 100644 --- a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php +++ b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php @@ -14,9 +14,13 @@ namespace Neos\ContentRepository\Core\NodeType; +use Neos\ContentRepository\Core\NodeType\Exception\TetheredNodeNotConfigured; use Neos\ContentRepository\Core\SharedModel\Exception\NodeConfigurationException; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeIsFinalException; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; +use Neos\ContentRepository\Core\SharedModel\Node\NodeName; +use Neos\Utility\Arrays; +use Neos\Utility\Exception\PropertyNotAccessibleException; /** * Manager for node types @@ -40,8 +44,7 @@ class NodeTypeManager public function __construct( private readonly \Closure $nodeTypeConfigLoader, - private readonly NodeLabelGeneratorFactoryInterface $nodeLabelGeneratorFactory, - private readonly ?string $fallbackNodeTypeName + private readonly NodeLabelGeneratorFactoryInterface $nodeLabelGeneratorFactory ) { } @@ -120,28 +123,13 @@ public function getNodeType(string|NodeTypeName $nodeTypeName): NodeType return $this->cachedNodeTypes[$nodeTypeName]; } - if ($this->fallbackNodeTypeName === null) { - throw new NodeTypeNotFoundException( - sprintf( - 'The node type "%s" is not available and no fallback NodeType is configured.', - $nodeTypeName - ), - 1316598370 - ); - } - - if (!$this->hasNodeType($this->fallbackNodeTypeName)) { - throw new NodeTypeNotFoundException( - sprintf( - 'The node type "%s" is not available and the configured fallback NodeType "%s" is not available.', - $nodeTypeName, - $this->fallbackNodeTypeName - ), - 1438166322 - ); - } - - return $this->getNodeType($this->fallbackNodeTypeName); + throw new NodeTypeNotFoundException( + sprintf( + 'The node type "%s" is not available', + $nodeTypeName + ), + 1316598370 + ); } /** @@ -169,6 +157,9 @@ protected function loadNodeTypes(): void { $completeNodeTypeConfiguration = ($this->nodeTypeConfigLoader)(); + // the root node type must always exist + $completeNodeTypeConfiguration[NodeTypeName::ROOT_NODE_TYPE_NAME] ??= []; + foreach (array_keys($completeNodeTypeConfiguration) as $nodeTypeName) { if (!is_string($nodeTypeName)) { continue; @@ -198,6 +189,80 @@ public function overrideNodeTypes(array $completeNodeTypeConfiguration): void } } + /** + * @param NodeType $nodeType + * @param NodeName $tetheredNodeName + * @return NodeType + *@throws TetheredNodeNotConfigured if the requested tethered node is not configured. Check via {@see NodeType::hasTetheredNode()}. + */ + public function getTypeOfTetheredNode(NodeType $nodeType, NodeName $tetheredNodeName): NodeType + { + $nameOfTetheredNode = $nodeType->getNodeTypeNameOfTetheredNode($tetheredNodeName); + return $this->getNodeType($nameOfTetheredNode); + } + + /** + * Return an array with child nodes which should be automatically created + * + * @return array the key of this array is the name of the child, and the value its NodeType. + * @api + */ + public function getTetheredNodesConfigurationForNodeType(NodeType $nodeType): array + { + $childNodeConfiguration = $nodeType->getConfiguration('childNodes'); + $autoCreatedChildNodes = []; + foreach ($childNodeConfiguration ?? [] as $childNodeName => $configurationForChildNode) { + if (isset($configurationForChildNode['type'])) { + $autoCreatedChildNodes[NodeName::transliterateFromString($childNodeName)->value] = $this->getNodeType($configurationForChildNode['type']); + } + } + return $autoCreatedChildNodes; + } + + /** + * Checks if the given $nodeType is allowed as a childNode of the given $tetheredNodeName + * (which must be tethered in $parentNodeType). + * + * Only allowed to be called if $tetheredNodeName is actually tethered. + * + * @param NodeType $parentNodeType The NodeType to check constraints based on. + * @param NodeName $tetheredNodeName The name of a configured tethered node of this NodeType + * @param NodeType $nodeType The NodeType to check constraints for. + * @return bool true if the $nodeType is allowed as grandchild node, false otherwise. + * @throws \InvalidArgumentException if the requested tethered node is not configured in the parent NodeType. Check via {@see NodeType::hasTetheredNode()}. + */ + public function isNodeTypeAllowedAsChildToTetheredNode(NodeType $parentNodeType, NodeName $tetheredNodeName, NodeType $nodeType): bool + { + try { + $typeOfTetheredNode = $this->getTypeOfTetheredNode($parentNodeType, $tetheredNodeName); + } catch (TetheredNodeNotConfigured $exception) { + throw new \InvalidArgumentException( + sprintf( + 'Cannot determine if grandchild is allowed in %s. Because the given child node name "%s" is not auto-created.', + $parentNodeType->name->value, + $tetheredNodeName->value + ), + 1403858395, + $exception + ); + } + + // Constraints configured on the NodeType for the child node + $constraints = $typeOfTetheredNode->getConfiguration('constraints.nodeTypes') ?: []; + + // Constraints configured at the childNode configuration of the parent. + try { + $childNodeConstraintConfiguration = $parentNodeType->getConfiguration('childNodes.' . $tetheredNodeName->value . '.constraints.nodeTypes') ?? []; + } catch (PropertyNotAccessibleException $exception) { + // We ignore this because the configuration might just not have any constraints, if the childNode was not configured the exception above would have been thrown. + $childNodeConstraintConfiguration = []; + } + + $constraints = Arrays::arrayMergeRecursiveOverrule($constraints, $childNodeConstraintConfiguration); + + return (new ConstraintCheck($constraints))->isNodeTypeAllowed($nodeType); + } + /** * Load one node type, if it is not loaded yet. * @@ -254,7 +319,6 @@ protected function loadNodeType(string $nodeTypeName, array &$completeNodeTypeCo NodeTypeName::fromString($nodeTypeName), $superTypes, $nodeTypeConfiguration, - $this, $this->nodeLabelGeneratorFactory ); diff --git a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeNames.php b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeNames.php index 28057faeae5..df9afdd9467 100644 --- a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeNames.php +++ b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeNames.php @@ -28,7 +28,6 @@ final class NodeTypeNames implements \IteratorAggregate private function __construct(NodeTypeName ...$nodeTypeNames) { - /** @var array $nodeTypeNames */ $this->nodeTypeNames = $nodeTypeNames; } @@ -73,11 +72,11 @@ public function withAdditionalNodeTypeName(NodeTypeName $nodeTypeName): self } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->nodeTypeNames); + yield from $this->nodeTypeNames; } /** diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php index 4ecb5a60ed6..66c66bd80ff 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphInterface.php @@ -94,15 +94,6 @@ public function findNodeAggregateById( */ public function findUsedNodeTypeNames(): iterable; - /** - * @internal - */ - public function findNodeByIdAndOriginDimensionSpacePoint( - ContentStreamId $contentStreamId, - NodeAggregateId $nodeAggregateId, - OriginDimensionSpacePoint $originDimensionSpacePoint - ): ?Node; - /** * @internal only for consumption inside the Command Handler */ diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphWithRuntimeCaches/ContentSubgraphWithRuntimeCaches.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphWithRuntimeCaches/ContentSubgraphWithRuntimeCaches.php index 5d81da82a05..85c2c94b614 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphWithRuntimeCaches/ContentSubgraphWithRuntimeCaches.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentGraphWithRuntimeCaches/ContentSubgraphWithRuntimeCaches.php @@ -227,6 +227,12 @@ public function countAncestorNodes(NodeAggregateId $entryNodeAggregateId, Filter return $this->wrappedContentSubgraph->countAncestorNodes($entryNodeAggregateId, $filter); } + public function findClosestNode(NodeAggregateId $entryNodeAggregateId, Filter\FindClosestNodeFilter $filter): ?Node + { + // TODO: Implement findClosestNode() method. + return $this->wrappedContentSubgraph->findClosestNode($entryNodeAggregateId, $filter); + } + public function findDescendantNodes(NodeAggregateId $entryNodeAggregateId, FindDescendantNodesFilter $filter): Nodes { // TODO: implement runtime caches diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentSubgraphInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentSubgraphInterface.php index 395538e96fa..55a5572edf8 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentSubgraphInterface.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/ContentSubgraphInterface.php @@ -109,6 +109,14 @@ public function findAncestorNodes(NodeAggregateId $entryNodeAggregateId, Filter\ */ public function countAncestorNodes(NodeAggregateId $entryNodeAggregateId, Filter\CountAncestorNodesFilter $filter): int; + /** + * Find the closest matching node, the entry node itself or the first ancestors of the $entryNodeAggregateId, that match the specified $filter and return it + * Note: in contrast to {@see findAncestorNodes()} the resulting node will be the entry node if it matches the filter! + * + * @return Node|null the closest node that matches the given $filter, or NULL if no matching node was found + */ + public function findClosestNode(NodeAggregateId $entryNodeAggregateId, Filter\FindClosestNodeFilter $filter): ?Node; + /** * Recursively find all nodes underneath the $entryNodeAggregateId that match the specified $filter and return them as a flat list * diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/CoverageByOrigin.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/CoverageByOrigin.php index e5934cb9ccd..acbe9a2acd5 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/CoverageByOrigin.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/CoverageByOrigin.php @@ -37,18 +37,12 @@ final class CoverageByOrigin implements \IteratorAggregate, \JsonSerializable */ private array $coverage; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - /** * @param array $coverage */ private function __construct(array $coverage) { $this->coverage = $coverage; - $this->iterator = new \ArrayIterator($coverage); } /** @@ -75,11 +69,11 @@ public function getCoverage(OriginDimensionSpacePoint $originDimensionSpacePoint } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->coverage; } /** diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/FindClosestNodeFilter.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/FindClosestNodeFilter.php new file mode 100644 index 00000000000..1db23c0d90f --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Filter/FindClosestNodeFilter.php @@ -0,0 +1,42 @@ + + * @implements \IteratorAggregate */ -final class Ordering implements IteratorAggregate, JsonSerializable +final class Ordering implements \IteratorAggregate, \JsonSerializable { /** * @var OrderingField[] @@ -61,9 +57,12 @@ public function andByTimestampField(TimestampField $timestampField, OrderingDire return new self(...[...$this->fields, OrderingField::byTimestampField($timestampField, $direction)]); } - public function getIterator(): Traversable + /** + * @return \Traversable + */ + public function getIterator(): \Traversable { - return new ArrayIterator($this->fields); + yield from $this->fields; } /** diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php index 428b6c01933..d29f4191ec9 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Node.php @@ -34,45 +34,40 @@ * * @api Note: The constructor is not part of the public API */ -final class Node +final readonly class Node { /** - * @internal + * @param ContentSubgraphIdentity $subgraphIdentity This is part of the node's "Read Model" identity which is defined by: {@see self::subgraphIdentity} and {@see self::nodeAggregateId} + * @param NodeAggregateId $nodeAggregateId NodeAggregateId (identifier) of this node. This is part of the node's "Read Model" identity which is defined by: {@see self::subgraphIdentity} and {@see self::nodeAggregateId} + * @param OriginDimensionSpacePoint $originDimensionSpacePoint The DimensionSpacePoint the node originates in. Usually needed to address a Node in a NodeAggregate in order to update it. + * @param NodeAggregateClassification $classification The classification (regular, root, tethered) of this node + * @param NodeTypeName $nodeTypeName The node's node type name; always set, even if unknown to the NodeTypeManager + * @param NodeType|null $nodeType The node's node type, null if unknown to the NodeTypeManager - @deprecated Don't rely on this too much, as the capabilities of the NodeType here will probably change a lot; Ask the {@see NodeTypeManager} instead + * @param PropertyCollection $properties All properties of this node. References are NOT part of this API; To access references, {@see ContentSubgraphInterface::findReferences()} can be used; To read the serialized properties, call properties->serialized(). + * @param NodeName|null $nodeName The optional name of this node {@see ContentSubgraphInterface::findChildNodeConnectedThroughEdgeName()} + * @param Timestamps $timestamps Creation and modification timestamps of this node */ - public function __construct( - public readonly ContentSubgraphIdentity $subgraphIdentity, - /** - * NodeAggregateId (identifier) of this node - * This is part of the node's "Read Model" identity, whis is defined by: - * - {@see getSubgraphIdentitity} - * - {@see getNodeAggregateId} (this method) - * - * With the above information, you can fetch a Subgraph using {@see ContentGraphInterface::getSubgraph()}. - * or {@see \Neos\ContentRepositoryRegistry\ContentRepositoryRegistry::subgraphForNode()} - */ - public readonly NodeAggregateId $nodeAggregateId, - /** - * returns the DimensionSpacePoint the node is at home in. Usually needed to address a Node in a NodeAggregate - * in order to update it. - */ - public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, - public readonly NodeAggregateClassification $classification, - public readonly NodeTypeName $nodeTypeName, - public readonly NodeType $nodeType, - /** - * Returns all properties of this node. References are NOT part of this API; - * there you need to check getReference() and getReferences(). - * - * To read the serialized properties, call properties->serialized(). - * - * @return PropertyCollectionInterface Property values, indexed by their name - */ - public readonly PropertyCollectionInterface $properties, - public readonly ?NodeName $nodeName, - public readonly Timestamps $timestamps, + private function __construct( + public ContentSubgraphIdentity $subgraphIdentity, + public NodeAggregateId $nodeAggregateId, + public OriginDimensionSpacePoint $originDimensionSpacePoint, + public NodeAggregateClassification $classification, + public NodeTypeName $nodeTypeName, + public ?NodeType $nodeType, + public PropertyCollection $properties, + public ?NodeName $nodeName, + public Timestamps $timestamps, ) { } + /** + * @internal The signature of this method can change in the future! + */ + public static function create(ContentSubgraphIdentity $subgraphIdentity, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateClassification $classification, NodeTypeName $nodeTypeName, ?NodeType $nodeType, PropertyCollection $properties, ?NodeName $nodeName, Timestamps $timestamps): self + { + return new self($subgraphIdentity, $nodeAggregateId, $originDimensionSpacePoint, $classification, $nodeTypeName, $nodeType, $properties, $nodeName, $timestamps); + } + /** * Returns the specified property. * @@ -108,7 +103,7 @@ public function hasProperty(string $propertyName): bool */ public function getLabel(): string { - return $this->nodeType->getNodeLabelGenerator()->getLabel($this); + return $this->nodeType?->getNodeLabelGenerator()->getLabel($this) ?: $this->nodeTypeName->value; } public function equals(Node $other): bool diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregates.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregates.php index e7befe6b45a..20fd0de79d5 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregates.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeAggregates.php @@ -17,19 +17,19 @@ /** * An immutable, type-safe collection of NodeAggregate objects * - * @implements \IteratorAggregate + * @implements \IteratorAggregate * * @api */ final class NodeAggregates implements \IteratorAggregate, \Countable { /** - * @var array + * @var array */ private array $nodeAggregates; /** - * @param iterable $collection + * @param iterable $collection */ private function __construct(iterable $collection) { @@ -48,7 +48,7 @@ private function __construct(iterable $collection) } /** - * @param array $nodeAggregates + * @param array $nodeAggregates */ public static function fromArray(array $nodeAggregates): self { @@ -61,11 +61,11 @@ public static function createEmpty(): self } /** - * @return \ArrayIterator|NodeAggregate[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->nodeAggregates); + yield from $this->nodeAggregates; } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTypeConstraints.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTypeConstraints.php index 8709e95a734..114496f9e81 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTypeConstraints.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTypeConstraints.php @@ -56,11 +56,25 @@ private function __construct( ) { } + /** + * We recommended to call this method with named arguments to better + * understand the distinction between allowed and disallowed NodeTypeNames + */ public static function create( - NodeTypeNames $explicitlyAllowedNodeTypeNames, - NodeTypeNames $explicitlyDisallowedNodeTypeNames + NodeTypeNames $allowed, + NodeTypeNames $disallowed ): self { - return new self($explicitlyAllowedNodeTypeNames, $explicitlyDisallowedNodeTypeNames); + return new self($allowed, $disallowed); + } + + public static function createWithAllowedNodeTypeNames(NodeTypeNames $nodeTypeNames): self + { + return new self($nodeTypeNames, NodeTypeNames::createEmpty()); + } + + public static function createWithDisallowedNodeTypeNames(NodeTypeNames $nodeTypeNames): self + { + return new self(NodeTypeNames::createEmpty(), $nodeTypeNames); } public static function fromFilterString(string $serializedFilters): self diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index b19bc3a95af..adb5887378b 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -67,11 +67,11 @@ public function offsetGet(mixed $offset): ?Node } /** - * @return \ArrayIterator|Node[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->nodes); + yield from $this->nodes; } public function offsetExists(mixed $offset): bool @@ -106,7 +106,7 @@ public function first(): ?Node public function merge(self $other): self { - $nodes = array_merge($this->nodes, $other->getIterator()->getArrayCopy()); + $nodes = array_merge($this->nodes, $other->nodes); return self::fromArray($nodes); } diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/OriginByCoverage.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/OriginByCoverage.php index b68544f62f4..4be4b97ca0d 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/OriginByCoverage.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/OriginByCoverage.php @@ -36,18 +36,12 @@ final class OriginByCoverage implements \IteratorAggregate, \JsonSerializable */ private array $origins; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - /** * @param array $coverage */ private function __construct(array $coverage) { $this->origins = $coverage; - $this->iterator = new \ArrayIterator($coverage); } /** @@ -83,11 +77,11 @@ public function getOrigin(DimensionSpacePoint $coveredDimensionSpacePoint): ?Ori } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->origins; } /** diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollection.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollection.php index 543c17ebac1..f673a3cfc5d 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollection.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollection.php @@ -18,10 +18,13 @@ use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; /** - * The property collection implementation - * @internal + * The property collection that provides access to the serialized and deserialized properties of a node + * + * @implements \ArrayAccess + * @implements \IteratorAggregate + * @api This object should not be instantiated by 3rd parties, but it is part of the {@see Node} read model */ -final class PropertyCollection implements PropertyCollectionInterface +final class PropertyCollection implements \ArrayAccess, \IteratorAggregate { /** * Properties from Nodes diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollectionInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollectionInterface.php deleted file mode 100644 index 67f1dab108c..00000000000 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/PropertyCollectionInterface.php +++ /dev/null @@ -1,31 +0,0 @@ - - * @extends \IteratorAggregate - * - * @api - */ -interface PropertyCollectionInterface extends \ArrayAccess, \IteratorAggregate -{ - /** - * Retrieve the serialized property values - */ - public function serialized(): SerializedPropertyValues; -} diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Reference.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Reference.php index 47a0819ae17..6235614d503 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Reference.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Reference.php @@ -28,7 +28,7 @@ final class Reference public function __construct( public readonly Node $node, public readonly ReferenceName $name, - public readonly ?PropertyCollectionInterface $properties + public readonly ?PropertyCollection $properties ) { } } diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/References.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/References.php index 2b72178a389..2917e5eeda1 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/References.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/References.php @@ -38,18 +38,17 @@ * * @api */ -final class References implements \IteratorAggregate, \ArrayAccess, \Countable +final readonly class References implements \IteratorAggregate, \ArrayAccess, \Countable { /** * @var array */ - public readonly array $references; + public array $references; private function __construct( Reference ...$references ) { - /** @var array $references */ - $this->references = $references; + $this->references = array_values($references); } /** @@ -69,11 +68,11 @@ public function getNodes(): Nodes } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator($this->references); + return yield from $this->references; } public function offsetExists(mixed $offset): bool diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtree.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtree.php index 74588368b40..a6330fbcd8c 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtree.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtree.php @@ -10,20 +10,12 @@ final class Subtree { /** - * @param Subtree[] $children + * @param array $children */ public function __construct( public readonly int $level, public readonly Node $node, - public array $children = [] + public readonly array $children ) { } - - /** - * @internal - */ - public function add(Subtree $subtree): void - { - $this->children[] = $subtree; - } } diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtrees.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtrees.php deleted file mode 100644 index 2670b5f268e..00000000000 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Subtrees.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * @api returned by {@see ContentSubgraphInterface} - */ -final class Subtrees implements \IteratorAggregate, \Countable -{ - /** - * @var array - */ - private array $subtrees; - - /** - * @param iterable $collection - */ - private function __construct(iterable $collection) - { - $subtrees = []; - foreach ($collection as $item) { - if (!$item instanceof Subtree) { - throw new \InvalidArgumentException( - 'Subtrees can only consist of ' . Subtree::class . ' objects.', - 1662037183 - ); - } - $subtrees[] = $item; - } - - $this->subtrees = $subtrees; - } - - public static function createEmpty(): self - { - return new self([]); - } - - /** - * @param Subtree[] $subtrees - * @return static - */ - public static function fromArray(array $subtrees): self - { - return new self($subtrees); - } - - /** - * @internal - */ - public function add(Subtree $subtree): void - { - $this->subtrees[] = $subtree; - } - - /** - * @return \ArrayIterator|Subtree[] - */ - public function getIterator(): \ArrayIterator - { - return new \ArrayIterator($this->subtrees); - } - - public function count(): int - { - return count($this->subtrees); - } - - public function first(): ?Subtree - { - if (count($this->subtrees) > 0) { - $array = $this->subtrees; - return reset($array); - } - - return null; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Projection/ProjectionInterface.php b/Neos.ContentRepository.Core/Classes/Projection/ProjectionInterface.php index 61f96e5fee3..249683514cf 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ProjectionInterface.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ProjectionInterface.php @@ -4,14 +4,10 @@ namespace Neos\ContentRepository\Core\Projection; -use Neos\ContentRepository\Core\CommandHandler\PendingProjections; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\EventStore\CatchUp\CheckpointStorageInterface; use Neos\EventStore\Model\EventEnvelope; -use Neos\EventStore\Model\EventStream\EventStreamInterface; -use Neos\EventStore\Model\Event\SequenceNumber; -use Neos\EventStore\Model\Event; /** * Common interface for a Content Repository projection. This API is NOT exposed to the outside world, but is @@ -20,7 +16,7 @@ * If the Projection needs to be notified that a catchup is about to happen, you can additionally * implement {@see WithMarkStaleInterface}. This is useful f.e. to disable runtime caches in the ProjectionState. * - * @template TState of ProjectionStateInterface + * @template-covariant TState of ProjectionStateInterface * @api you can write custom projections */ interface ProjectionInterface diff --git a/Neos.ContentRepository.Core/Classes/Projection/Projections.php b/Neos.ContentRepository.Core/Classes/Projection/Projections.php index 5e343fa6e3e..1d5d2d6f431 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/Projections.php +++ b/Neos.ContentRepository.Core/Classes/Projection/Projections.php @@ -13,16 +13,16 @@ final class Projections implements \IteratorAggregate { /** - * @var array> + * @var array>, ProjectionInterface> */ private array $projections; /** - * @param array $projections - * @phpstan-ignore-next-line + * @param ProjectionInterface ...$projections */ private function __construct(ProjectionInterface ...$projections) { + // @phpstan-ignore-next-line $this->projections = $projections; } @@ -60,7 +60,8 @@ public static function fromArray(array $projections): self */ public function get(string $projectionClassName): ProjectionInterface { - if (!$this->has($projectionClassName)) { + $projection = $this->projections[$projectionClassName] ?? null; + if (!$projection instanceof $projectionClassName) { throw new \InvalidArgumentException( sprintf( 'a projection of type "%s" is not registered in this content repository instance.', @@ -69,8 +70,7 @@ public function get(string $projectionClassName): ProjectionInterface 1650120813 ); } - // @phpstan-ignore-next-line - return $this->projections[$projectionClassName]; + return $projection; } public function has(string $projectionClassName): bool @@ -79,11 +79,10 @@ public function has(string $projectionClassName): bool } /** - * @return \Traversable - * @phpstan-ignore-next-line + * @return \Traversable> */ public function getIterator(): \Traversable { - return new \ArrayIterator($this->projections); + yield from $this->projections; } } diff --git a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspace.php b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspace.php index ac4bf644a74..e2a294126d5 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspace.php +++ b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspace.php @@ -37,7 +37,7 @@ class Workspace public function __construct( public readonly WorkspaceName $workspaceName, public readonly ?WorkspaceName $baseWorkspaceName, - public readonly ?WorkspaceTitle $workspaceTitle, + public readonly WorkspaceTitle $workspaceTitle, public readonly WorkspaceDescription $workspaceDescription, public readonly ContentStreamId $currentContentStreamId, public readonly WorkspaceStatus $status, diff --git a/Neos.ContentRepository.Core/Classes/Projection/Workspace/WorkspaceFinder.php b/Neos.ContentRepository.Core/Classes/Projection/Workspace/WorkspaceFinder.php index db8414b0875..724b3c4ab84 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/Workspace/WorkspaceFinder.php +++ b/Neos.ContentRepository.Core/Classes/Projection/Workspace/WorkspaceFinder.php @@ -91,32 +91,6 @@ public function findOneByCurrentContentStreamId( return $workspace; } - /** - * @return array - */ - public function findByPrefix(WorkspaceName $prefix): array - { - $result = []; - - $connection = $this->client->getConnection(); - $workspaceRows = $connection->executeQuery( - ' - SELECT * FROM ' . $this->tableName . ' - WHERE workspaceName LIKE :workspaceNameLike - ', - [ - 'workspaceNameLike' => $prefix->value . '%' - ] - )->fetchAllAssociative(); - - foreach ($workspaceRows as $workspaceRow) { - $similarlyNamedWorkspace = $this->createWorkspaceFromDatabaseRow($workspaceRow); - $result[$similarlyNamedWorkspace->workspaceName->value] = $similarlyNamedWorkspace; - } - - return $result; - } - /** * @return array * @throws \Doctrine\DBAL\DBALException @@ -218,7 +192,7 @@ private function createWorkspaceFromDatabaseRow(array $row): Workspace return new Workspace( WorkspaceName::fromString($row['workspacename']), !empty($row['baseworkspacename']) ? WorkspaceName::fromString($row['baseworkspacename']) : null, - !empty($row['workspacetitle']) ? WorkspaceTitle::fromString($row['workspacetitle']) : null, + WorkspaceTitle::fromString($row['workspacetitle']), WorkspaceDescription::fromString($row['workspacedescription']), ContentStreamId::fromString($row['currentcontentstreamid']), WorkspaceStatus::from($row['status']), diff --git a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php index 9abddaec49e..f8fea6db6db 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php +++ b/Neos.ContentRepository.Core/Classes/Projection/Workspace/Workspaces.php @@ -70,9 +70,6 @@ public function get(WorkspaceName $workspaceName): ?Workspace /** * Get all base workspaces (if they are included in this result set). - * - * @param WorkspaceName $workspaceName - * @return Workspaces */ public function getBaseWorkspaces(WorkspaceName $workspaceName): Workspaces { @@ -96,11 +93,11 @@ public function getBaseWorkspaces(WorkspaceName $workspaceName): Workspaces } /** - * @return \ArrayIterator|Workspace[] + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return new \ArrayIterator(array_values($this->workspaces)); + yield from array_values($this->workspaces); } public function count(): int diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeAggregateIds.php b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeAggregateIds.php index 66a8016be69..01f89fa2401 100644 --- a/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeAggregateIds.php +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Node/NodeAggregateIds.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\Core\SharedModel\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; /** * An immutable collection of NodeAggregateIds, indexed by their value @@ -29,16 +30,10 @@ final class NodeAggregateIds implements \IteratorAggregate, \JsonSerializable */ private array $nodeAggregateIds; - /** - * @var \ArrayIterator - */ - private \ArrayIterator $iterator; - private function __construct(NodeAggregateId ...$nodeAggregateIds) { /** @var array $nodeAggregateIds */ $this->nodeAggregateIds = $nodeAggregateIds; - $this->iterator = new \ArrayIterator($nodeAggregateIds); } public static function createEmpty(): self @@ -46,12 +41,11 @@ public static function createEmpty(): self return new self(...[]); } - - public static function create(NodeAggregateId ...$nodeAggregateIds): self { return self::fromArray($nodeAggregateIds); } + /** * @param array $array */ @@ -74,13 +68,10 @@ public static function fromJsonString(string $jsonString): self return self::fromArray(\json_decode($jsonString, true)); } - /** - * @param Node[] $nodes - */ - public static function fromNodes(array $nodes): self + public static function fromNodes(Nodes $nodes): self { return self::fromArray( - array_map(fn(Node $node) => $node->nodeAggregateId, $nodes) + array_map(fn(Node $node) => $node->nodeAggregateId, iterator_to_array($nodes)) ); } @@ -88,10 +79,15 @@ public function merge(self $other): self { return new self(...array_merge( $this->nodeAggregateIds, - $other->getIterator()->getArrayCopy() + $other->nodeAggregateIds )); } + public function contain(NodeAggregateId $nodeAggregateId): bool + { + return array_key_exists($nodeAggregateId->value, $this->nodeAggregateIds); + } + /** * @return array */ @@ -114,10 +110,10 @@ public function toStringArray(): array } /** - * @return \ArrayIterator + * @return \Traversable */ - public function getIterator(): \ArrayIterator + public function getIterator(): \Traversable { - return $this->iterator; + yield from $this->nodeAggregateIds; } } diff --git a/Neos.ContentRepository.Core/Tests/Unit/Dimension/ContentDimensionTest.php b/Neos.ContentRepository.Core/Tests/Unit/Dimension/ContentDimensionTest.php index 959c110c6e8..98845ee7692 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Dimension/ContentDimensionTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Dimension/ContentDimensionTest.php @@ -61,7 +61,7 @@ protected function setUp(): void $this->subject = new Dimension\ContentDimension( $dimensionIdentifier, $this->values, - new Dimension\ContentDimensionValueVariationEdges([$euEdge, $deEdge, $usEdge]) + new Dimension\ContentDimensionValueVariationEdges($euEdge, $deEdge, $usEdge) ); } diff --git a/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/Fixtures/VariationExampleDimensionSource.php b/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/Fixtures/VariationExampleDimensionSource.php index a298e93fc39..4ad98461fc8 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/Fixtures/VariationExampleDimensionSource.php +++ b/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/Fixtures/VariationExampleDimensionSource.php @@ -45,11 +45,11 @@ protected function initializeDimensions() $dimensionAValue12->value => $dimensionAValue12, $dimensionAValue111->value => $dimensionAValue111 ]), - new Dimension\ContentDimensionValueVariationEdges([ + new Dimension\ContentDimensionValueVariationEdges( new Dimension\ContentDimensionValueVariationEdge($dimensionAValue11, $dimensionAValue1), new Dimension\ContentDimensionValueVariationEdge($dimensionAValue12, $dimensionAValue1), new Dimension\ContentDimensionValueVariationEdge($dimensionAValue111, $dimensionAValue11) - ]) + ) ), 'dimensionB' => new Dimension\ContentDimension( new Dimension\ContentDimensionId('dimensionB'), @@ -59,11 +59,11 @@ protected function initializeDimensions() $dimensionBValue12->value => $dimensionBValue12, $dimensionBValue111->value => $dimensionBValue111 ]), - new Dimension\ContentDimensionValueVariationEdges([ + new Dimension\ContentDimensionValueVariationEdges( new Dimension\ContentDimensionValueVariationEdge($dimensionBValue11, $dimensionBValue1), new Dimension\ContentDimensionValueVariationEdge($dimensionBValue12, $dimensionBValue1), new Dimension\ContentDimensionValueVariationEdge($dimensionBValue111, $dimensionBValue11) - ]) + ) ) ]; } diff --git a/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php new file mode 100644 index 00000000000..04d9f727cf6 --- /dev/null +++ b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php @@ -0,0 +1,110 @@ + $expectedNodeAggregateIdsByPath, null if the actual value is not important + * @dataProvider subjectProvider + */ + public function testCompleteForNodeOfType(NodeAggregateIdsByNodePaths $subject, array $expectedNodeAggregateIdsByPath): void + { + $nodeTypeManager = new NodeTypeManager( + fn (): array => [ + 'Neos.ContentRepository.Testing:Content' => [], + 'Neos.ContentRepository.Testing:LeafDocument' => [ + 'childNodes' => [ + 'grandchild1' => [ + 'type' => 'Neos.ContentRepository.Testing:Content' + ], + 'grandchild2' => [ + 'type' => 'Neos.ContentRepository.Testing:Content' + ] + ] + ], + 'Neos.ContentRepository.Testing:Document' => [ + 'childNodes' => [ + 'child1' => [ + 'type' => 'Neos.ContentRepository.Testing:LeafDocument' + ], + 'child2' => [ + 'type' => 'Neos.ContentRepository.Testing:LeafDocument' + ] + ] + ] + ], + new DefaultNodeLabelGeneratorFactory() + ); + + $completeSubject = $subject->completeForNodeOfType( + NodeTypeName::fromString('Neos.ContentRepository.Testing:Document'), + $nodeTypeManager + ); + + foreach ($expectedNodeAggregateIdsByPath as $path => $explicitExpectedNodeAggregateId) { + $actualNodeAggregateId = $completeSubject->getNodeAggregateId(NodePath::fromString($path)); + self::assertInstanceOf(NodeAggregateId::class, $actualNodeAggregateId); + if ($explicitExpectedNodeAggregateId instanceof NodeAggregateId) { + self::assertTrue($actualNodeAggregateId->equals($explicitExpectedNodeAggregateId)); + } + } + } + + public static function subjectProvider(): iterable + { + yield 'emptySubject' => [ + 'subject' => NodeAggregateIdsByNodePaths::createEmpty(), + 'expectedNodeAggregateIdsByPath' => [ + 'child1' => null, + 'child2' => null, + 'child1/grandchild1' => null, + 'child1/grandchild2' => null, + 'child2/grandchild1' => null, + 'child2/grandchild2' => null, + ] + ]; + + yield 'alreadyCompleteSubject' => [ + 'subject' => NodeAggregateIdsByNodePaths::fromArray([ + 'child1' => NodeAggregateId::fromString('child-1'), + 'child2' => NodeAggregateId::fromString('child-2'), + 'child1/grandchild1' => NodeAggregateId::fromString('grandchild-1-1'), + 'child1/grandchild2' => NodeAggregateId::fromString('grandchild-1-2'), + 'child2/grandchild1' => NodeAggregateId::fromString('grandchild-2-1'), + 'child2/grandchild2' => NodeAggregateId::fromString('grandchild-2-1'), + ]), + 'expectedNodeAggregateIdsByPath' => [ + 'child1' => NodeAggregateId::fromString('child-1'), + 'child2' => NodeAggregateId::fromString('child-2'), + 'child1/grandchild1' => NodeAggregateId::fromString('grandchild-1-1'), + 'child1/grandchild2' => NodeAggregateId::fromString('grandchild-1-2'), + 'child2/grandchild1' => NodeAggregateId::fromString('grandchild-2-1'), + 'child2/grandchild2' => NodeAggregateId::fromString('grandchild-2-1'), + ] + ]; + } +} diff --git a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php index 0dc9812c21c..3184fb5275a 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php @@ -12,6 +12,8 @@ */ use Neos\ContentRepository\Core\NodeType\DefaultNodeLabelGeneratorFactory; +use Neos\ContentRepository\Core\NodeType\NodeType; +use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Exception\NodeConfigurationException; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeIsFinalException; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; @@ -38,12 +40,11 @@ public function setUp(): void * * @param array $nodeTypesFixtureData */ - protected function prepareNodeTypeManager(array $nodeTypesFixtureData, string $fallbackNodeTypeName = '') + protected function prepareNodeTypeManager(array $nodeTypesFixtureData) { $this->nodeTypeManager = new NodeTypeManager( fn() => $nodeTypesFixtureData, - new DefaultNodeLabelGeneratorFactory(), - $fallbackNodeTypeName + new DefaultNodeLabelGeneratorFactory() ); } @@ -122,6 +123,11 @@ protected function prepareNodeTypeManager(array $nodeTypesFixtureData, string $f ], 'Neos.ContentRepository.Testing:Page2' => [ 'superTypes' => ['Neos.ContentRepository.Testing:Document' => true], + 'childNodes' => [ + 'nodeName' => [ + 'type' => 'Neos.ContentRepository.Testing:Document' + ] + ] ], 'Neos.ContentRepository.Testing:Page3' => [ 'superTypes' => ['Neos.ContentRepository.Testing:Document' => true], @@ -133,8 +139,7 @@ protected function prepareNodeTypeManager(array $nodeTypesFixtureData, string $f 'Neos.ContentRepository.Testing:Page2' => false, 'Neos.ContentRepository.Testing:Page3' => null ] - ], - 'Neos.ContentRepository:FallbackNode' => [] + ] ]; /** @@ -173,37 +178,6 @@ public function getNodeTypeThrowsExceptionForUnknownNodeType() $this->nodeTypeManager->getNodeType('Neos.ContentRepository.Testing:TextFooBarNotHere'); } - /** - * @test - */ - public function getNodeTypeThrowsExceptionIfNoFallbackNodeTypeIsConfigured() - { - $this->expectException(NodeTypeNotFoundException::class); - $this->nodeTypeManager->getNodeType('Neos.ContentRepository.Testing:TextFooBarNotHere'); - } - - /** - * @test - */ - public function getNodeTypeThrowsExceptionIfConfiguredFallbackNodeTypeCantBeFound() - { - $this->expectException(NodeTypeNotFoundException::class); - $this->prepareNodeTypeManager($this->nodeTypesFixture, 'Neos.ContentRepository:NonExistingFallbackNode'); - $this->nodeTypeManager->getNodeType('Neos.ContentRepository.Testing:TextFooBarNotHere'); - } - - /** - * @test - */ - public function getNodeTypeReturnsFallbackNodeTypeIfConfigured() - { - $this->prepareNodeTypeManager($this->nodeTypesFixture, 'Neos.ContentRepository:FallbackNode'); - - $expectedNodeType = $this->nodeTypeManager->getNodeType('Neos.ContentRepository:FallbackNode'); - $fallbackNodeType = $this->nodeTypeManager->getNodeType('Neos.ContentRepository.Testing:TextFooBarNotHere'); - self::assertSame($expectedNodeType, $fallbackNodeType); - } - /** * @test */ @@ -244,7 +218,7 @@ public function getNodeTypesReturnsRegisteredNodeTypes() 'Neos.ContentRepository.Testing:Page2', 'Neos.ContentRepository.Testing:Page3', 'Neos.ContentRepository.Testing:DocumentWithSupertypes', - 'Neos.ContentRepository:FallbackNode' + 'Neos.ContentRepository:Root' // is always present ]; self::assertEquals($expectedNodeTypes, array_keys($this->nodeTypeManager->getNodeTypes())); } @@ -369,4 +343,28 @@ public function getSubNodeTypesWithDifferentIncludeFlagValuesReturnsCorrectValue $subNodeTypes = $this->nodeTypeManager->getSubNodeTypes('Neos.ContentRepository.Testing:ContentObject', false); self::assertArrayNotHasKey('Neos.ContentRepository.Testing:AbstractType', $subNodeTypes); } + + /** + * @test + */ + public function getAutoCreatedChildNodesReturnsLowercaseNames() + { + $parentNodeType = $this->nodeTypeManager->getNodeType(NodeTypeName::fromString('Neos.ContentRepository.Testing:Page2')); + $autoCreatedChildNodes = $this->nodeTypeManager->getTetheredNodesConfigurationForNodeType($parentNodeType); + // This is configured as "nodeName" above, but should be normalized to "nodename" + self::assertArrayHasKey('nodename', $autoCreatedChildNodes); + } + + /** + * @test + */ + public function rootNodeTypeIsAlwaysPresent() + { + $nodeTypeManager = new NodeTypeManager( + fn() => [], + new DefaultNodeLabelGeneratorFactory() + ); + self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); + self::assertInstanceOf(NodeType::class, $nodeTypeManager->getNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); + } } diff --git a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeTest.php b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeTest.php index bd38fc10066..3777e0c725c 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeTest.php @@ -22,7 +22,6 @@ * Testcase for the "NodeType" domain model */ class NodeTypeTest extends TestCase - { /** * example node types @@ -130,9 +129,7 @@ class NodeTypeTest extends TestCase */ public function aNodeTypeHasAName() { - $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository.Testing:Text'), [], [], - $this->getMockBuilder(NodeTypeManager::class) - ->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository.Testing:Text'), [], [], new DefaultNodeLabelGeneratorFactory()); self::assertSame('Neos.ContentRepository.Testing:Text', $nodeType->name->value); } @@ -142,9 +139,7 @@ public function aNodeTypeHasAName() public function setDeclaredSuperTypesExpectsAnArrayOfNodeTypesAsKeys() { $this->expectException(\InvalidArgumentException::class); - new NodeType(NodeTypeName::fromString('ContentRepository:Folder'), ['foo' => true], [], - $this->getMockBuilder(NodeTypeManager::class) - ->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() + new NodeType(NodeTypeName::fromString('ContentRepository:Folder'), ['foo' => true], [], new DefaultNodeLabelGeneratorFactory() ); } @@ -154,8 +149,7 @@ public function setDeclaredSuperTypesExpectsAnArrayOfNodeTypesAsKeys() public function setDeclaredSuperTypesAcceptsAnArrayOfNodeTypes() { $this->expectException(\InvalidArgumentException::class); - new NodeType(NodeTypeName::fromString('ContentRepository:Folder'), ['foo'], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + new NodeType(NodeTypeName::fromString('ContentRepository:Folder'), ['foo'], [], new DefaultNodeLabelGeneratorFactory()); } /** @@ -163,13 +157,11 @@ public function setDeclaredSuperTypesAcceptsAnArrayOfNodeTypes() */ public function nodeTypesCanHaveAnyNumberOfSuperTypes() { - $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], new DefaultNodeLabelGeneratorFactory()); $timeableNodeType = new NodeType( NodeTypeName::fromString('Neos.ContentRepository.Testing:TimeableContent'), - [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() + [], [], new DefaultNodeLabelGeneratorFactory() ); $documentType = new NodeType( NodeTypeName::fromString('Neos.ContentRepository.Testing:Document'), @@ -177,13 +169,12 @@ public function nodeTypesCanHaveAnyNumberOfSuperTypes() 'Neos.ContentRepository:Base' => $baseType, 'Neos.ContentRepository.Testing:TimeableContent' => $timeableNodeType, ], - [], $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() + [], new DefaultNodeLabelGeneratorFactory() ); $hideableNodeType = new NodeType( NodeTypeName::fromString('Neos.ContentRepository.Testing:HideableContent'), - [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() + [], [], new DefaultNodeLabelGeneratorFactory() ); $pageType = new NodeType( NodeTypeName::fromString('Neos.ContentRepository.Testing:Page'), @@ -193,7 +184,6 @@ public function nodeTypesCanHaveAnyNumberOfSuperTypes() 'Neos.ContentRepository.Testing:TimeableContent' => null, ], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() ); @@ -219,8 +209,7 @@ public function nodeTypesCanHaveAnyNumberOfSuperTypes() */ public function labelIsEmptyStringByDefault() { - $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], new DefaultNodeLabelGeneratorFactory()); self::assertSame('', $baseType->getLabel()); } @@ -229,8 +218,7 @@ public function labelIsEmptyStringByDefault() */ public function propertiesAreEmptyArrayByDefault() { - $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], new DefaultNodeLabelGeneratorFactory()); self::assertSame([], $baseType->getProperties()); } @@ -243,7 +231,7 @@ public function hasConfigurationReturnsTrueIfSpecifiedConfigurationPathExists() 'someKey' => [ 'someSubKey' => 'someValue' ] - ], $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + ], new DefaultNodeLabelGeneratorFactory()); self::assertTrue($nodeType->hasConfiguration('someKey.someSubKey')); } @@ -252,8 +240,7 @@ public function hasConfigurationReturnsTrueIfSpecifiedConfigurationPathExists() */ public function hasConfigurationReturnsFalseIfSpecifiedConfigurationPathDoesNotExist() { - $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], new DefaultNodeLabelGeneratorFactory()); self::assertFalse($nodeType->hasConfiguration('some.nonExisting.path')); } @@ -266,7 +253,7 @@ public function getConfigurationReturnsTheConfigurationWithTheSpecifiedPath() 'someKey' => [ 'someSubKey' => 'someValue' ] - ], $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + ], new DefaultNodeLabelGeneratorFactory()); self::assertSame('someValue', $nodeType->getConfiguration('someKey.someSubKey')); } @@ -275,8 +262,7 @@ public function getConfigurationReturnsTheConfigurationWithTheSpecifiedPath() */ public function getConfigurationReturnsNullIfTheSpecifiedPathDoesNotExist() { - $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory()); + $nodeType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [], new DefaultNodeLabelGeneratorFactory()); self::assertNull($nodeType->getConfiguration('some.nonExisting.path')); } @@ -401,25 +387,7 @@ protected function getNodeType(string $nodeTypeName): ?NodeType NodeTypeName::fromString($nodeTypeName), $declaredSuperTypes, $configuration, - $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(), new DefaultNodeLabelGeneratorFactory() ); } - - /** - * @test - */ - public function getAutoCreatedChildNodesReturnsLowercasePaths() - { - $childNodeConfiguration = ['type' => 'Neos.ContentRepository:Base']; - $mockNodeTypeManager = $this->getMockBuilder(NodeTypeManager::class)->disableOriginalConstructor()->getMock(); - $baseType = new NodeType(NodeTypeName::fromString('Neos.ContentRepository:Base'), [], [ - 'childNodes' => ['nodeName' => $childNodeConfiguration] - ], $mockNodeTypeManager, new DefaultNodeLabelGeneratorFactory()); - $mockNodeTypeManager->expects(self::any())->method('getNodeType')->will(self::returnValue($baseType)); - - $autoCreatedChildNodes = $mockNodeTypeManager->getNodeType('Neos.ContentRepository:Base')->getAutoCreatedChildNodes(); - - self::assertArrayHasKey('nodename', $autoCreatedChildNodes); - } } diff --git a/Neos.ContentRepository.Core/composer.json b/Neos.ContentRepository.Core/composer.json index 4436974a8f7..8a7598b4d7b 100644 --- a/Neos.ContentRepository.Core/composer.json +++ b/Neos.ContentRepository.Core/composer.json @@ -15,7 +15,8 @@ "doctrine/dbal": "^2.6", "symfony/serializer": "*", "psr/clock": "^1", - "behat/transliterator": "~1.0" + "behat/transliterator": "~1.0", + "ramsey/uuid": "^3.0 || ^4.0" }, "require-dev": { "roave/security-advisories": "dev-latest", diff --git a/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageAdjustments.php b/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageAdjustments.php index 7527eb150bb..7e1b45a82db 100644 --- a/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageAdjustments.php +++ b/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageAdjustments.php @@ -7,13 +7,13 @@ /** * @implements \IteratorAggregate */ -final class SerializedImageAdjustments implements \IteratorAggregate, \JsonSerializable +final readonly class SerializedImageAdjustments implements \IteratorAggregate, \JsonSerializable { /** * @param array $serializedAdjustments */ private function __construct( - private readonly array $serializedAdjustments, + private array $serializedAdjustments, ) {} /** @@ -35,12 +35,11 @@ public static function fromArray(array $array): self } /** - * @return \Traversable|SerializedImageAdjustment[] - * @noinspection PhpDocSignatureInspection + * @return \Traversable */ public function getIterator(): \Traversable { - return new \ArrayIterator($this->serializedAdjustments); + yield from $this->serializedAdjustments; } /** diff --git a/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageVariant.php b/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageVariant.php index 916e39d2043..12b5a86b7fa 100644 --- a/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageVariant.php +++ b/Neos.ContentRepository.Export/src/Asset/ValueObject/SerializedImageVariant.php @@ -71,11 +71,6 @@ public static function fromArray(array $array): self public function matches(ImageVariant $imageVariant): bool { - if (self::fromImageVariant($imageVariant)->toJson() !== $this->toJson()) { - \Neos\Flow\var_dump(self::fromImageVariant($imageVariant)->toJson()); - \Neos\Flow\var_dump($this->toJson()); - exit; - } return self::fromImageVariant($imageVariant)->toJson() === $this->toJson(); } diff --git a/Neos.ContentRepository.Export/src/ImportServiceFactory.php b/Neos.ContentRepository.Export/src/ImportServiceFactory.php index bd140489c1a..01dcd295bbd 100644 --- a/Neos.ContentRepository.Export/src/ImportServiceFactory.php +++ b/Neos.ContentRepository.Export/src/ImportServiceFactory.php @@ -25,8 +25,7 @@ public function __construct( private readonly ResourceRepository $resourceRepository, private readonly ResourceManager $resourceManager, private readonly PersistenceManagerInterface $persistenceManager, - ) - { + ) { } public function build(ContentRepositoryServiceFactoryDependencies $serviceFactoryDependencies): ImportService diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/Command/CrCommandController.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/Command/CrCommandController.php index fabefad1565..b3b7e1a11d6 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/Command/CrCommandController.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/Command/CrCommandController.php @@ -40,13 +40,6 @@ class CrCommandController extends CommandController { - - /** - * @var array - */ - #[Flow\InjectConfiguration(package: 'Neos.Flow')] - protected array $flowSettings; - public function __construct( private readonly Connection $connection, private readonly Environment $environment, @@ -96,6 +89,7 @@ public function migrateLegacyDataCommand(bool $verbose = false, string $config = $siteRows = $connection->fetchAllAssociativeIndexed('SELECT nodename, name, siteresourcespackagekey FROM neos_neos_domain_model_site'); $siteNodeName = $this->output->select('Which site to migrate?', array_map(static fn (array $siteRow) => $siteRow['name'] . ' (' . $siteRow['siteresourcespackagekey'] . ')', $siteRows)); + assert(is_string($siteNodeName)); $siteRow = $siteRows[$siteNodeName]; $site = $this->siteRepository->findOneByNodeName($siteNodeName); @@ -208,6 +202,7 @@ private function determineResourcesPath(): string private static function defaultResourcesPath(): string { + // @phpstan-ignore-next-line return FLOW_PATH_DATA . 'Persistent/Resources'; } } diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/AssetExtractor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/AssetExtractor.php index f7479da4c39..89ce5152c53 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/AssetExtractor.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/AssetExtractor.php @@ -12,6 +12,9 @@ final class AssetExtractor { + /** + * @var array + */ private array $processedAssetIds = []; public function __construct( @@ -19,7 +22,8 @@ public function __construct( ) {} /** - * @param iterable $nodeDataRows + * @param iterable> $nodeDataRows + * @return iterable */ public function run(iterable $nodeDataRows): iterable { @@ -48,11 +52,14 @@ public function run(iterable $nodeDataRows): iterable /** ----------------------------- */ + /** + * @return iterable + */ private function extractAssets(mixed $propertyValue): iterable { if ($propertyValue instanceof Asset) { + /** @var string|null $assetId */ $assetId = $propertyValue->getIdentifier(); - \Neos\Flow\var_dump($assetId, '$assetId'); if ($assetId === null) { // TODO exception/error return; @@ -75,7 +82,6 @@ private function extractAssets(mixed $propertyValue): iterable foreach ($matches as $match) { $assetId = $match['assetId']; $asset = ($this->findAssetByIdentifier)($assetId); - \Neos\Flow\var_dump($asset, '$asset ' . $assetId); if ($asset === null) { // TODO exception/error continue; diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/NodeDataLoader.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/NodeDataLoader.php index 52d54cdbf20..904f5700184 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/NodeDataLoader.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/Helpers/NodeDataLoader.php @@ -4,16 +4,21 @@ namespace Neos\ContentRepository\LegacyNodeMigration\Helpers; use Doctrine\DBAL\Connection; -use Traversable; +/** + * @implements \IteratorAggregate> + */ final class NodeDataLoader implements \IteratorAggregate { - public function __construct( private readonly Connection $connection, - ) {} + ) { + } - public function getIterator(): Traversable + /** + * @return \Traversable> + */ + public function getIterator(): \Traversable { $query = $this->connection->executeQuery(' SELECT diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationService.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationService.php index b72b8e40d0a..15d1be1d8c4 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationService.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationService.php @@ -58,8 +58,7 @@ public function __construct( private readonly PropertyConverter $propertyConverter, private readonly EventStoreInterface $eventStore, private readonly ContentStreamId $contentStreamId, - ) - { + ) { } public function runAllProcessors(\Closure $outputLineFn, bool $verbose = false): void @@ -88,7 +87,7 @@ public function runAllProcessors(\Closure $outputLineFn, bool $verbose = false): }); $result = $processor->run(); if ($result->severity === Severity::ERROR) { - throw new \RuntimeException($label . ': ' . $result->message ?? ''); + throw new \RuntimeException($label . ': ' . $result->message); } $outputLineFn(' ' . $result->message); $outputLineFn(); diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationServiceFactory.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationServiceFactory.php index b8b2ba82655..67bd7df05c5 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationServiceFactory.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/LegacyMigrationServiceFactory.php @@ -41,8 +41,7 @@ public function __construct( private readonly ResourceManager $resourceManager, private readonly PropertyMapper $propertyMapper, private readonly ContentStreamId $contentStreamId, - ) - { + ) { } public function build( diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToAssetsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToAssetsProcessor.php index a1495d6174e..0d60b591cee 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToAssetsProcessor.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToAssetsProcessor.php @@ -17,9 +17,18 @@ final class NodeDataToAssetsProcessor implements ProcessorInterface { + /** + * @var array + */ private array $processedAssetIds = []; + /** + * @var array<\Closure> + */ private array $callbacks = []; + /** + * @param iterable> $nodeDataRows + */ public function __construct( private readonly NodeTypeManager $nodeTypeManager, private readonly AssetExporter $assetExporter, @@ -84,12 +93,10 @@ public function run(): ProcessorResult private function extractAssetIdentifiers(string $type, mixed $value): array { if (($type === 'string' || is_subclass_of($type, \Stringable::class, true)) && is_string($value)) { - // @phpstan-ignore-next-line preg_match_all('/asset:\/\/(?[\w-]*)/i', (string)$value, $matches, PREG_SET_ORDER); return array_map(static fn(array $match) => $match['assetId'], $matches); } if (is_subclass_of($type, ResourceBasedInterface::class, true)) { - // @phpstan-ignore-next-line return isset($value['__identifier']) ? [$value['__identifier']] : []; } diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php index 6e827a4eb69..4f8bb63a3e9 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php @@ -5,6 +5,7 @@ namespace Neos\ContentRepository\LegacyNodeMigration; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; +use Doctrine\DBAL\Types\ConversionException; use League\Flysystem\Filesystem; use League\Flysystem\FilesystemException; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; @@ -45,20 +46,21 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet; -use Neos\ContentRepository\Core\SharedModel\Node\PropertyName; use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\Flow\Persistence\Doctrine\DataTypes\JsonArrayType; use Neos\Flow\Property\PropertyMapper; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Ramsey\Uuid\Uuid; use Webmozart\Assert\Assert; final class NodeDataToEventsProcessor implements ProcessorInterface { - + /** + * @var array<\Closure> + */ private array $callbacks = []; private NodeTypeName $sitesNodeTypeName; private ContentStreamId $contentStreamId; @@ -78,6 +80,9 @@ final class NodeDataToEventsProcessor implements ProcessorInterface */ private $eventFileResource; + /** + * @param iterable> $nodeDataRows + */ public function __construct( private readonly NodeTypeManager $nodeTypeManager, private readonly PropertyMapper $propertyMapper, @@ -87,7 +92,7 @@ public function __construct( private readonly Filesystem $files, private readonly iterable $nodeDataRows, ) { - $this->sitesNodeTypeName = NodeTypeName::fromString('Neos.Neos:Sites'); + $this->sitesNodeTypeName = NodeTypeNameFactory::forSites(); $this->contentStreamId = ContentStreamId::create(); $this->visitedNodes = new VisitedNodeAggregates(); } @@ -99,6 +104,13 @@ public function setContentStreamId(ContentStreamId $contentStreamId): void public function setSitesNodeType(NodeTypeName $nodeTypeName): void { + $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); + if (!$nodeType->isOfType(NodeTypeNameFactory::NAME_SITES)) { + throw new \InvalidArgumentException( + sprintf('Sites NodeType "%s" must be of type "%s"', $nodeTypeName->value, NodeTypeNameFactory::NAME_SITES), + 1695802415 + ); + } $this->sitesNodeTypeName = $nodeTypeName; } @@ -149,7 +161,7 @@ private function resetRuntimeState(): void $this->nodeReferencesWereSetEvents = []; $this->numberOfExportedEvents = 0; $this->metaDataExported = false; - $this->eventFileResource = fopen('php://temp/maxmemory:5242880', 'rb+'); + $this->eventFileResource = fopen('php://temp/maxmemory:5242880', 'rb+') ?: null; Assert::resource($this->eventFileResource, null, 'Failed to create temporary event file resource'); } @@ -161,10 +173,14 @@ private function exportEvent(EventInterface $event): void json_decode($this->eventNormalizer->getEventData($event)->value, true), [] ); + assert($this->eventFileResource !== null); fwrite($this->eventFileResource, $exportedEvent->toJson() . chr(10)); $this->numberOfExportedEvents ++; } + /** + * @param array $nodeDataRow + */ private function exportMetaData(array $nodeDataRow): void { if ($this->files->fileExists('meta.json')) { @@ -180,7 +196,7 @@ private function exportMetaData(array $nodeDataRow): void } /** - * @param array $nodeDataRow + * @param array $nodeDataRow */ private function processNodeData(array $nodeDataRow): void { @@ -222,10 +238,9 @@ private function processNodeData(array $nodeDataRow): void /** - * @param NodePath $nodePath * @param OriginDimensionSpacePoint $originDimensionSpacePoint * @param NodeAggregateId $nodeAggregateId - * @param array $nodeDataRow + * @param array $nodeDataRow * @return NodeName[]|void * @throws \JsonException */ @@ -239,10 +254,18 @@ public function processNodeDataWithoutFallbackToEmptyDimension(NodeAggregateId $ } $pathParts = $nodePath->getParts(); $nodeName = end($pathParts); + assert($nodeName !== false); $nodeTypeName = NodeTypeName::fromString($nodeDataRow['nodetype']); $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); $serializedPropertyValuesAndReferences = $this->extractPropertyValuesAndReferences($nodeDataRow, $nodeType); + $isSiteNode = $nodeDataRow['parentpath'] === '/sites'; + if ($isSiteNode && !$nodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) { + throw new MigrationException(sprintf( + 'The site node "%s" (type: "%s") must be of type "%s"', $nodeDataRow['identifier'], $nodeTypeName->value, NodeTypeNameFactory::NAME_SITE + ), 1695801620); + } + if ($this->isAutoCreatedChildNode($parentNodeAggregate->nodeTypeName, $nodeName) && !$this->visitedNodes->containsNodeAggregate($nodeAggregateId)) { // Create tethered node if the node was not found before. // If the node was already visited, we want to create a node variant (and keep the tethering status) @@ -266,13 +289,20 @@ public function processNodeDataWithoutFallbackToEmptyDimension(NodeAggregateId $ $this->visitedNodes->add($nodeAggregateId, new DimensionSpacePointSet([$originDimensionSpacePoint->toDimensionSpacePoint()]), $nodeTypeName, $nodePath, $parentNodeAggregate->nodeAggregateId); } + /** + * @param array $nodeDataRow + */ public function extractPropertyValuesAndReferences(array $nodeDataRow, NodeType $nodeType): SerializedPropertyValuesAndReferences { $properties = []; $references = []; // Note: We use a PostgreSQL platform because the implementation is forward-compatible, @see JsonArrayType::convertToPHPValue() - $decodedProperties = (new JsonArrayType())->convertToPHPValue($nodeDataRow['properties'], new PostgreSQL100Platform()); + try { + $decodedProperties = (new JsonArrayType())->convertToPHPValue($nodeDataRow['properties'], new PostgreSQL100Platform()); + } catch (ConversionException $exception) { + throw new MigrationException(sprintf('Failed to decode properties %s of node "%s" (type: "%s"): %s', json_encode($nodeDataRow['properties']), $nodeDataRow['identifier'], $nodeType->name->value, $exception->getMessage()), 1695391558, $exception); + } if (!is_array($decodedProperties)) { throw new MigrationException(sprintf('Failed to decode properties %s of node "%s" (type: "%s")', json_encode($nodeDataRow['properties']), $nodeDataRow['identifier'], $nodeType->name->value), 1656057035); } @@ -357,7 +387,10 @@ private function createNodeVariant(NodeAggregateId $nodeAggregateId, OriginDimen // When we specialize/generalize, we create a node variant at exactly the same tree location as the source node // If the parent node aggregate id differs, we need to move the just created variant to the new location $nodeAggregate = $this->visitedNodes->getByNodeAggregateId($nodeAggregateId); - if (!$parentNodeAggregate->nodeAggregateId->equals($nodeAggregate->getVariant($variantSourceOriginDimensionSpacePoint)->parentNodeAggregateId)) { + if ( + $variantSourceOriginDimensionSpacePoint && + !$parentNodeAggregate->nodeAggregateId->equals($nodeAggregate->getVariant($variantSourceOriginDimensionSpacePoint)->parentNodeAggregateId) + ) { $this->exportEvent(new NodeAggregateWasMoved( $this->contentStreamId, $nodeAggregateId, @@ -388,7 +421,7 @@ private function isAutoCreatedChildNode(NodeTypeName $parentNodeTypeName, NodeNa return false; } $nodeTypeOfParent = $this->nodeTypeManager->getNodeType($parentNodeTypeName); - return $nodeTypeOfParent->hasAutoCreatedChildNode($nodeName); + return $nodeTypeOfParent->hasTetheredNode($nodeName); } private function dispatch(Severity $severity, string $message, mixed ...$args): void diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php index 84035677337..53b87836684 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php @@ -10,9 +10,16 @@ use League\Flysystem\Filesystem; use League\Flysystem\InMemory\InMemoryFilesystemAdapter; use Neos\Behat\Tests\Behat\FlowContextTrait; +use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; +use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; +use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\EventNormalizer; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\Core\Factory\ContentRepositoryId; +use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; +use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Export\Asset\AssetExporter; use Neos\ContentRepository\Export\Asset\AssetLoaderInterface; use Neos\ContentRepository\Export\Asset\ResourceLoaderInterface; @@ -24,9 +31,8 @@ use Neos\ContentRepository\Export\Severity; use Neos\ContentRepository\LegacyNodeMigration\NodeDataToAssetsProcessor; use Neos\ContentRepository\LegacyNodeMigration\NodeDataToEventsProcessor; -use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepositoryRegistry\TestSuite\Behavior\CRRegistrySubjectProvider; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Property\PropertyMapper; use Neos\Flow\ResourceManagement\PersistentResource; use PHPUnit\Framework\Assert; @@ -39,7 +45,7 @@ class FeatureContext implements Context { use FlowContextTrait; use CRTestSuiteTrait; - use CRRegistrySubjectProvider; + use CRBehavioralTestsSubjectProvider; protected $isolated = false; @@ -53,18 +59,26 @@ class FeatureContext implements Context private ProcessorResult|null $lastMigrationResult = null; + /** + * @var array + */ + private array $loggedErrors = []; + private ContentRepository $contentRepository; + protected ContentRepositoryRegistry $contentRepositoryRegistry; + public function __construct() { if (self::$bootstrap === null) { self::$bootstrap = $this->initializeFlow(); } $this->objectManager = self::$bootstrap->getObjectManager(); + $this->contentRepositoryRegistry = $this->objectManager->get(ContentRepositoryRegistry::class); + $this->mockFilesystemAdapter = new InMemoryFilesystemAdapter(); $this->mockFilesystem = new Filesystem($this->mockFilesystemAdapter); $this->setupCRTestSuiteTrait(); - } /** @@ -73,7 +87,10 @@ public function __construct() public function failIfLastMigrationHasErrors(): void { if ($this->lastMigrationResult !== null && $this->lastMigrationResult->severity === Severity::ERROR) { - Assert::fail(sprintf('The last migration run led to an error: %s', $this->lastMigrationResult->message)); + throw new \RuntimeException(sprintf('The last migration run led to an error: %s', $this->lastMigrationResult->message)); + } + if ($this->loggedErrors !== []) { + throw new \RuntimeException(sprintf('The last migration run logged %d error%s', count($this->loggedErrors), count($this->loggedErrors) === 1 ? '' : 's')); } } @@ -126,6 +143,11 @@ public function iRunTheEventMigration(string $contentStream = null): void if ($contentStream !== null) { $migration->setContentStreamId(ContentStreamId::fromString($contentStream)); } + $migration->onMessage(function (Severity $severity, string $message) { + if ($severity === Severity::ERROR) { + $this->loggedErrors[] = $message; + } + }); $this->lastMigrationResult = $migration->run(); } @@ -166,6 +188,15 @@ public function iExpectTheFollowingEventsToBeExported(TableNode $table): void Assert::assertCount(count($table->getHash()), $exportedEvents, 'Expected number of events does not match actual number'); } + /** + * @Then I expect the following errors to be logged + */ + public function iExpectTheFollwingErrorsToBeLogged(TableNode $table): void + { + Assert::assertSame($this->loggedErrors, $table->getColumn(0), 'Expected logged errors do not match'); + $this->loggedErrors = []; + } + /** * @Then I expect a MigrationError * @Then I expect a MigrationError with the message @@ -278,6 +309,11 @@ public function findAssetById(string $assetId): SerializedAsset|SerializedImageV $this->mockFilesystemAdapter->deleteEverything(); $assetExporter = new AssetExporter($this->mockFilesystem, $mockAssetLoader, $mockResourceLoader); $migration = new NodeDataToAssetsProcessor($nodeTypeManager, $assetExporter, $this->nodeDataRows); + $migration->onMessage(function (Severity $severity, string $message) { + if ($severity === Severity::ERROR) { + $this->loggedErrors[] = $message; + } + }); $this->lastMigrationResult = $migration->run(); } @@ -345,4 +381,24 @@ private function parseJsonTable(TableNode $table): array }, $row); }, $table->getHash()); } + + protected function getContentRepositoryService( + ContentRepositoryServiceFactoryInterface $factory + ): ContentRepositoryServiceInterface { + return $this->contentRepositoryRegistry->buildService( + $this->currentContentRepository->id, + $factory + ); + } + + protected function createContentRepository( + ContentRepositoryId $contentRepositoryId + ): ContentRepository { + $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); + $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + GherkinTableNodeBasedContentDimensionSourceFactory::reset(); + GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + + return $contentRepository; + } } diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature index 02864fc4d62..bc5cf9671ea 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Assets.feature @@ -8,7 +8,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources And using the following node types: """yaml 'unstructured': {} - 'Some.Package:SomeNodeType': + 'Neos.Neos:Site': {} + 'Some.Package:Homepage': + superTypes: + 'Neos.Neos:Site': true properties: 'string': type: string @@ -43,7 +46,7 @@ Feature: Export of used Assets, Image Variants and Persistent Resources When I have the following node data rows: | Identifier | Path | Node Type | Properties | | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"string": "asset:\/\/variant1"} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"string": "asset:\/\/variant1"} | And I run the asset migration Then I expect the following Assets to be exported: """ @@ -87,10 +90,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources When I have the following node data rows: | Identifier | Path | Node Type | Dimension Values | Properties | | sites-node-id | /sites | unstructured | | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | | {"string": "asset:\/\/asset1"} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} | {"image": {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} | {"assets": [{"__flow_object_type": "Neos\\Media\\Domain\\Model\\Document", "__identifier": "asset3"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\ImageVariant", "__identifier": "variant1"}]} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} | {"string": "some text with an asset link"} | + | site-node-id | /sites/test-site | Some.Package:Homepage | | {"string": "asset:\/\/asset1"} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | {"image": {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} | {"assets": [{"__flow_object_type": "Neos\\Media\\Domain\\Model\\Document", "__identifier": "asset3"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\Image", "__identifier": "asset2"}, {"__flow_object_type": "Neos\\Media\\Domain\\Model\\ImageVariant", "__identifier": "variant1"}]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | {"string": "some text with an asset link"} | And I run the asset migration Then I expect the following Assets to be exported: """ @@ -178,8 +181,10 @@ Feature: Export of used Assets, Image Variants and Persistent Resources When I have the following node data rows: | Identifier | Path | Node Type | Properties | | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"string": "asset:\/\/non-existing-asset"} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"string": "asset:\/\/non-existing-asset"} | And I run the asset migration Then I expect no Assets to be exported And I expect no ImageVariants to be exported And I expect no PersistentResources to be exported + And I expect the following errors to be logged + | Failed to extract assets of property "string" of node "site-node-id" (type: "Some.Package:Homepage"): Failed to find mock asset with id "non-existing-asset" | diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature index 20462bc12b0..3623e2fe61a 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Basic.feature @@ -5,7 +5,11 @@ Feature: Simple migrations without content dimensions Given using no content dimensions And using the following node types: """yaml - 'Some.Package:SomeNodeType': + 'unstructured': {} + 'Neos.Neos:Site': {} + 'Some.Package:Homepage': + superTypes: + 'Neos.Neos:Site': true properties: 'text': type: string @@ -18,9 +22,9 @@ Feature: Simple migrations without content dimensions When I have the following node data rows: | Identifier | Path | Node Type | Properties | | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"text": "foo"} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"text": "foo"} | And I run the event migration for content stream "cs-id" Then I expect the following events to be exported | Type | Payload | | RootNodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} | - | NodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular", "initialPropertyValues": {"text": {"type": "string", "value": "foo"}}} | + | NodeAggregateWithNodeWasCreated | {"contentStreamId": "cs-id", "nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular", "initialPropertyValues": {"text": {"type": "string", "value": "foo"}}} | diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature new file mode 100644 index 00000000000..4cf57e96a4c --- /dev/null +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Errors.feature @@ -0,0 +1,151 @@ +@contentrepository +Feature: Exceptional cases during migrations + + Background: + Given using no content dimensions + And using the following node types: + """yaml + 'unstructured': {} + 'Neos.Neos:Site': {} + 'Some.Package:Homepage': + superTypes: + 'Neos.Neos:Site': true + properties: + 'text': + type: string + defaultValue: 'My default text' + 'Some.Package:SomeNodeType': + properties: + 'text': + type: string + 'Some.Package:SomeOtherHomepage': + superTypes: + 'Neos.Neos:Site': true + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + + Scenario: Node variant with different type + Given I change the content dimensions in content repository "default" to: + | Identifier | Default | Values | Generalizations | + | language | en | en, de, ch | ch->de | + When I have the following node data rows: + | Identifier | Path | Node Type | Dimension Values | + | sites-node-id | /sites | unstructured | | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | + | site-node-id | /sites/test-site | Some.Package:SomeOtherHomepage | {"language": ["en"]} | + And I run the event migration + Then I expect a MigrationError with the message + """ + Node aggregate with id "site-node-id" has a type of "Some.Package:SomeOtherHomepage" in content dimension [{"language":"en"}]. I was visited previously for content dimension [{"language":"de"}] with the type "Some.Package:Homepage". Node variants must not have different types + """ + + # Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201 + Scenario: Node with missing parent + When I have the following node data rows: + | Identifier | Path | Node Type | + | sites | /sites | unstructured | + | a | /sites/a | Some.Package:Homepage | + | c | /sites/b/c | unstructured | + And I run the event migration + Then I expect the following events to be exported + | Type | Payload | + | RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} | + And I expect the following errors to be logged + | Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. | + + + # Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201 + Scenario: Nodes out of order + When I have the following node data rows: + | Identifier | Path | Node Type | + | sites | /sites | unstructured | + | a | /sites/a | Some.Package:Homepage | + | c | /sites/b/c | unstructured | + | b | /sites/b | Some.Package:Homepage | + And I run the event migration + Then I expect the following events to be exported + | Type | Payload | + | RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "nodeTypeName": "Some.Package:Homepage", "parentNodeAggregateId": "sites"} | + And I expect the following errors to be logged + | Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. | + + + Scenario: Invalid dimension configuration (unknown value) + Given I change the content dimensions in content repository "default" to: + | Identifier | Default | Values | Generalizations | + | language | en | en, de, ch | ch->de | + When I have the following node data rows: + | Identifier | Path | Dimension Values | + | sites | /sites | | + | a | /sites/a | {"language": ["unknown"]} | + And I run the event migration + Then I expect the following events to be exported + | Type | Payload | + | RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} | + And I expect the following errors to be logged + | Failed to find parent node for node with id "a" and dimensions: {"language":"unknown"}. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. | + + Scenario: Invalid dimension configuration (no json) + When I have the following node data rows: + | Identifier | Path | Dimension Values | + | sites | /sites | | + | a | /sites/a | not json | + And I run the event migration + Then I expect a MigrationError + + Scenario: Invalid node properties (no JSON) + When I have the following node data rows: + | Identifier | Path | Properties | Node Type | + | sites | /sites | | | + | a | /sites/a | not json | Some.Package:SomeNodeType | + And I run the event migration + Then I expect a MigrationError with the message + """ + Failed to decode properties "not json" of node "a" (type: "Some.Package:SomeNodeType"): Could not convert database value "not json" to Doctrine Type flow_json_array + """ + + Scenario: Node variants with the same dimension + Given I change the content dimensions in content repository "default" to: + | Identifier | Default | Values | Generalizations | + | language | en | en, de, ch | ch->de | + When I have the following node data rows: + | Identifier | Path | Node Type | Dimension Values | + | sites-node-id | /sites | unstructured | | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | + And I run the event migration + Then I expect a MigrationError with the message + """ + Node "site-node-id" with dimension space point "{"language":"ch"}" was already visited before + """ + + Scenario: Duplicate nodes + Given I change the content dimensions in content repository "default" to: + | Identifier | Default | Values | Generalizations | + | language | en | en, de, ch | ch->de | + When I have the following node data rows: + | Identifier | Path | Node Type | Dimension Values | + | sites-node-id | /sites | unstructured | | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | + And I run the event migration + Then I expect a MigrationError with the message + """ + Node "site-node-id" for dimension {"language":"de"} was already created previously + """ + + Scenario: Homepage node is not of type "Neos.Neos:Site" + When I have the following node data rows: + | Identifier | Path | Node Type | + | sites-node-id | /sites | unstructured | + | site-node-id | /sites/test-site | unstructured | + And I run the event migration + Then I expect a MigrationError with the message + """ + The site node "site-node-id" (type: "unstructured") must be of type "Neos.Neos:Site" + """ diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Exceptions.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Exceptions.feature deleted file mode 100644 index 000c88bcf6c..00000000000 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Exceptions.feature +++ /dev/null @@ -1,119 +0,0 @@ -@contentrepository -Feature: Exceptional cases during migrations - - Background: - Given using no content dimensions - And using the following node types: - """yaml - 'unstructured': [] - 'Some.Package:SomeNodeType': - properties: - 'text': - type: string - defaultValue: 'My default text' - 'Some.Package:SomeOtherNodeType': [] - """ - And using identifier "default", I define a content repository - And I am in content repository "default" - - Scenario: Node variant with different type - Given I change the content dimensions in content repository "default" to: - | Identifier | Default | Values | Generalizations | - | language | en | en, de, ch | ch->de | - When I have the following node data rows: - | Identifier | Path | Node Type | Dimension Values | - | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} | - | site-node-id | /sites/test-site | Some.Package:SomeOtherNodeType | {"language": ["en"]} | - And I run the event migration - Then I expect a MigrationError with the message - """ - Node aggregate with id "site-node-id" has a type of "Some.Package:SomeOtherNodeType" in content dimension [{"language":"en"}]. I was visited previously for content dimension [{"language":"de"}] with the type "Some.Package:SomeNodeType". Node variants must not have different types - """ - - Scenario: Node with missing parent - When I have the following node data rows: - | Identifier | Path | - | sites | /sites | - | a | /sites/a | - | c | /sites/b/c | - And I run the event migration - Then I expect a MigrationError with the message - """ - Failed to find parent node for node with id "c" and dimensions: []. Did you properly configure your dimensions setup to be in sync with the old setup? - """ - - # TODO: is it possible that nodes are processed in an order where a ancestor node is processed after a child node? -> in that case the following example should work (i.e. the scenario should fail) - Scenario: Nodes out of order - When I have the following node data rows: - | Identifier | Path | - | sites | /sites | - | a | /sites/a | - | c | /sites/b/c | - | b | /sites/b | - And I run the event migration - Then I expect a MigrationError with the message - """ - Failed to find parent node for node with id "c" and dimensions: []. Did you properly configure your dimensions setup to be in sync with the old setup? - """ - - Scenario: Invalid dimension configuration (unknown value) - Given I change the content dimensions in content repository "default" to: - | Identifier | Default | Values | Generalizations | - | language | en | en, de, ch | ch->de | - When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites | /sites | | - | a | /sites/a | {"language": ["unknown"]} | - And I run the event migration - Then I expect a MigrationError - - Scenario: Invalid dimension configuration (no json) - When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites | /sites | | - | a | /sites/a | not json | - And I run the event migration - Then I expect a MigrationError - - Scenario: Invalid node properties (no JSON) - When I have the following node data rows: - | Identifier | Path | Properties | Node Type | - | sites | /sites | | | - | a | /sites/a | not json | Some.Package:SomeNodeType | - And I run the event migration - Then I expect a MigrationError with the message - """ - Failed to decode properties "not json" of node "a" (type: "Some.Package:SomeNodeType") - """ - - Scenario: Node variants with the same dimension - Given I change the content dimensions in content repository "default" to: - | Identifier | Default | Values | Generalizations | - | language | en | en, de, ch | ch->de | - When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites-node-id | /sites | | - | site-node-id | /sites/test-site | {"language": ["de"]} | - | site-node-id | /sites/test-site | {"language": ["ch"]} | - | site-node-id | /sites/test-site | {"language": ["ch"]} | - And I run the event migration - Then I expect a MigrationError with the message - """ - Node "site-node-id" with dimension space point "{"language":"ch"}" was already visited before - """ - - Scenario: Duplicate nodes - Given I change the content dimensions in content repository "default" to: - | Identifier | Default | Values | Generalizations | - | language | en | en, de, ch | ch->de | - When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites-node-id | /sites | | - | site-node-id | /sites/test-site | {"language": ["de"]} | - | site-node-id | /sites/test-site | {"language": ["de"]} | - And I run the event migration - Then I expect a MigrationError with the message - """ - Node "site-node-id" for dimension {"language":"de"} was already created previously - """ diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature index e9dcb7dfc60..7c67812eb50 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/References.feature @@ -5,7 +5,11 @@ Feature: Migrations that contain nodes with "reference" or "references propertie Given using no content dimensions And using the following node types: """yaml - 'Some.Package:Homepage': [] + 'unstructured': {} + 'Neos.Neos:Site': {} + 'Some.Package:Homepage': + superTypes: + 'Neos.Neos:Site': true 'Some.Package:SomeNodeType': properties: 'text': diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature index f5a1299ec0b..e6285a44323 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature @@ -8,27 +8,26 @@ Feature: Migrating nodes with content dimensions And using the following node types: """yaml 'unstructured': {} - 'Some.Package:SomeNodeType': - properties: - 'text': - type: string - defaultValue: 'My default text' + 'Neos.Neos:Site': {} + 'Some.Package:Homepage': + superTypes: + 'Neos.Neos:Site': true """ And using identifier "default", I define a content repository And I am in content repository "default" Scenario: Node specialization variants are prioritized over peer variants When I have the following node data rows: - | Identifier | Path | Node Type | Dimension Values | - | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} | + | Identifier | Path | Node Type | Dimension Values | + | sites-node-id | /sites | unstructured | | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | And I run the event migration Then I expect the following events to be exported | Type | Payload | | RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "coveredDimensionSpacePoints": [{"language": "en"},{"language": "de"},{"language": "ch"}], "nodeAggregateClassification": "root"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "de"}, "coveredDimensionSpacePoints": [{"language": "de"},{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "de"}, "coveredDimensionSpacePoints": [{"language": "de"},{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} | | NodePeerVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "de"}, "peerOrigin": {"language": "en"}, "peerCoverage": [{"language": "en"}]} | | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationCoverage": [{"language": "ch"}]} | @@ -36,14 +35,14 @@ Feature: Migrating nodes with content dimensions When I have the following node data rows: | Identifier | Path | Node Type | Dimension Values | | sites-node-id | /sites | unstructured | | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["ch"]} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["en"]} | - | site-node-id | /sites/test-site | Some.Package:SomeNodeType | {"language": ["de"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["ch"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["en"]} | + | site-node-id | /sites/test-site | Some.Package:Homepage | {"language": ["de"]} | And I run the event migration Then I expect the following events to be exported | Type | Payload | | RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites-node-id", "nodeTypeName": "Neos.Neos:Sites", "coveredDimensionSpacePoints": [{"language": "en"},{"language": "de"},{"language": "ch"}], "nodeAggregateClassification": "root"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:SomeNodeType", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "ch"}, "coveredDimensionSpacePoints": [{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site-node-id", "nodeTypeName": "Some.Package:Homepage", "nodeName": "test-site", "originDimensionSpacePoint": {"language": "ch"}, "coveredDimensionSpacePoints": [{"language": "ch"}], "parentNodeAggregateId": "sites-node-id", "nodeAggregateClassification": "regular"} | | NodePeerVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "ch"}, "peerOrigin": {"language": "en"}, "peerCoverage": [{"language": "en"}]} | | NodeGeneralizationVariantWasCreated | {"nodeAggregateId": "site-node-id", "sourceOrigin": {"language": "ch"}, "generalizationOrigin": {"language": "de"}, "generalizationCoverage": [{"language": "de"}]} | @@ -52,10 +51,10 @@ Feature: Migrating nodes with content dimensions | Identifier | Default | Values | Generalizations | | language | mul | mul, en, de, ch | ch->de->mul | When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites | /sites | | - | site | /sites/site | {"language": ["mul"]} | - | site | /sites/site | {"language": ["de"]} | + | Identifier | Path | Node Type | Dimension Values | + | sites | /sites | unstructured | | + | site | /sites/site | Some.Package:Homepage | {"language": ["mul"]} | + | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} | And I run the event migration Then I expect the following events to be exported | Type | Payload | @@ -65,13 +64,13 @@ Feature: Migrating nodes with content dimensions Scenario: Node variant with different parent node (moved) When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites | /sites | | - | site | /sites/site | {"language": ["de"]} | - | a | /sites/site/a | {"language": ["de"]} | - | a1 | /sites/site/a/a1 | {"language": ["de"]} | - | b | /sites/site/b | {"language": ["de"]} | - | a1 | /sites/site/b/a1 | {"language": ["ch"]} | + | Identifier | Path | Node Type | Dimension Values | + | sites | /sites | unstructured | | + | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} | + | a | /sites/site/a | unstructured | {"language": ["de"]} | + | a1 | /sites/site/a/a1 | unstructured | {"language": ["de"]} | + | b | /sites/site/b | unstructured | {"language": ["de"]} | + | a1 | /sites/site/b/a1 | unstructured | {"language": ["ch"]} | And I run the event migration Then I expect the following events to be exported | Type | Payload | @@ -86,14 +85,14 @@ Feature: Migrating nodes with content dimensions Scenario: Node variant with different grand parent node (ancestor node was moved) - Note: There is only NodeAggregateWasMoved event for "a" and not for "a1" When I have the following node data rows: - | Identifier | Path | Dimension Values | - | sites | /sites | | - | site | /sites/site | {"language": ["de"]} | - | a | /sites/site/a | {"language": ["de"]} | - | a1 | /sites/site/a/a1 | {"language": ["de"]} | - | b | /sites/site/b | {"language": ["de"]} | - | a | /sites/site/b/a | {"language": ["ch"]} | - | a1 | /sites/site/b/a/a1 | {"language": ["ch"]} | + | Identifier | Path | Node Type | Dimension Values | + | sites | /sites | unstructured | | + | site | /sites/site | Some.Package:Homepage | {"language": ["de"]} | + | a | /sites/site/a | unstructured | {"language": ["de"]} | + | a1 | /sites/site/a/a1 | unstructured | {"language": ["de"]} | + | b | /sites/site/b | unstructured | {"language": ["de"]} | + | a | /sites/site/b/a | unstructured | {"language": ["ch"]} | + | a1 | /sites/site/b/a/a1 | unstructured | {"language": ["ch"]} | And I run the event migration Then I expect the following events to be exported | Type | Payload | diff --git a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php index dcf0d4233c3..d0677eb075c 100644 --- a/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php +++ b/Neos.ContentRepository.NodeAccess/Classes/FlowQueryOperations/ParentsOperation.php @@ -11,6 +11,10 @@ * source code. */ +use Neos\ContentRepository\Core\NodeType\NodeTypeNames; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; +use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTypeConstraints; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -61,31 +65,29 @@ public function canEvaluate($context) * * @param FlowQuery $flowQuery the FlowQuery object * @param array $arguments the arguments for this operation - * @todo Compare to node type Neos.Neos:Site instead of path once it is available * @return void */ public function evaluate(FlowQuery $flowQuery, array $arguments) { - $parents = []; + $parents = Nodes::createEmpty(); + $findAncestorNodesFilter = FindAncestorNodesFilter::create( + NodeTypeConstraints::createWithDisallowedNodeTypeNames( + NodeTypeNames::fromStringArray(['Neos.ContentRepository:Root']) + ) + ); + /* @var Node $contextNode */ foreach ($flowQuery->getContext() as $contextNode) { - $node = $contextNode; - do { - $node = $this->contentRepositoryRegistry->subgraphForNode($node) - ->findParentNode($node->nodeAggregateId); - if ($node === null) { - // no parent found - break; - } - // stop at sites - if ($node->nodeTypeName === NodeTypeName::fromString('Neos.Neos:Sites')) { - break; - } - $parents[] = $node; - } while (true); + $ancestorNodes = $this->contentRepositoryRegistry + ->subgraphForNode($contextNode) + ->findAncestorNodes( + $contextNode->nodeAggregateId, + $findAncestorNodesFilter + ); + $parents = $parents->merge($ancestorNodes); } - $flowQuery->setContext($parents); + $flowQuery->setContext(iterator_to_array($parents)); if (isset($arguments[0]) && !empty($arguments[0])) { $flowQuery->pushOperation('filter', $arguments); diff --git a/Neos.ContentRepository.NodeAccess/Configuration/NodeTypes.yaml b/Neos.ContentRepository.NodeAccess/Configuration/NodeTypes.yaml deleted file mode 100644 index f9a14e30517..00000000000 --- a/Neos.ContentRepository.NodeAccess/Configuration/NodeTypes.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# # -# ContentRepository Node Types # -# # - -'unstructured': - abstract: false - constraints: - nodeTypes: - '*': true - -'Neos.ContentRepository:Root': - abstract: true diff --git a/Neos.ContentRepository.NodeMigration/src/Filter/DimensionSpacePointsFilterFactory.php b/Neos.ContentRepository.NodeMigration/src/Filter/DimensionSpacePointsFilterFactory.php index c6b072c2a0d..1c05d28cafc 100644 --- a/Neos.ContentRepository.NodeMigration/src/Filter/DimensionSpacePointsFilterFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Filter/DimensionSpacePointsFilterFactory.php @@ -14,7 +14,6 @@ namespace Neos\ContentRepository\NodeMigration\Filter; -use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\InterDimensionalVariationGraph; use Neos\ContentRepository\Core\DimensionSpace\VariantType; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet; diff --git a/Neos.ContentRepository.NodeMigration/src/Filter/PropertyValueFilterFactory.php b/Neos.ContentRepository.NodeMigration/src/Filter/PropertyValueFilterFactory.php index 6d390551c7f..06a5f7fa936 100644 --- a/Neos.ContentRepository.NodeMigration/src/Filter/PropertyValueFilterFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Filter/PropertyValueFilterFactory.php @@ -15,7 +15,6 @@ namespace Neos\ContentRepository\NodeMigration\Filter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; /** * Filter nodes having the given property and its value not empty. @@ -45,7 +44,6 @@ public function matches(Node $node): bool if (is_null($this->propertyName) || !$node->hasProperty($this->propertyName)) { return false; } - /** @var PropertyCollectionInterface $properties */ $properties = $node->properties; $serializedPropertyValue = $properties->serialized()->getProperty($this->propertyName); if (!$serializedPropertyValue) { diff --git a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php index 57296c6aa65..ccf503359f6 100644 --- a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php +++ b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php @@ -14,7 +14,6 @@ use Neos\ContentRepository\NodeMigration\Transformation\TransformationsFactory; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceTitle; @@ -54,8 +53,7 @@ public function __construct( private readonly ContentRepository $contentRepository, private readonly FiltersFactory $filterFactory, private readonly TransformationsFactory $transformationFactory - ) - { + ) { } public function executeMigration(ExecuteMigration $command): void @@ -98,8 +96,7 @@ protected function executeSubMigrationAndBlock( array $migrationDescription, ContentStreamId $contentStreamForReading, ContentStreamId $contentStreamForWriting - ): void - { + ): void { $filters = $this->filterFactory->buildFilterConjunction($migrationDescription['filters'] ?? []); $transformations = $this->transformationFactory->buildTransformation( $migrationDescription['transformations'] ?? [] diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php index 72a23fd9db8..c40da53c40a 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php @@ -22,7 +22,6 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; -use Neos\ContentRepository\Core\SharedModel\User\UserId; class AddNewPropertyTransformationFactory implements TransformationFactoryInterface { diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php index 13eed059459..ca1b472827a 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php @@ -20,7 +20,6 @@ use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\NodeType\NodeTypeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; /** @codingStandardsIgnoreStart */ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php index 2512f716ee6..442b010e902 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php @@ -20,10 +20,8 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; -use Neos\ContentRepository\Core\SharedModel\User\UserId; /** * Change the value of a given property. @@ -107,7 +105,6 @@ public function execute( ContentStreamId $contentStreamForWriting ): ?CommandResult { if ($node->hasProperty($this->propertyName)) { - /** @var PropertyCollectionInterface $properties */ $properties = $node->properties; $currentProperty = $properties->serialized()->getProperty($this->propertyName); /** @var \Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue $currentProperty safe since Node::hasProperty */ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php index 6b0e2595c16..bd97abc0574 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php @@ -22,7 +22,6 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\User\UserId; /** * Remove Node diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php index 0a362e82dad..783cfa7a5f6 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php @@ -19,7 +19,6 @@ use Neos\ContentRepository\Core\Feature\NodeRenaming\Command\ChangeNodeAggregateName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; class RenameNodeAggregateTransformationFactory implements TransformationFactoryInterface diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php index e20ab2d7298..dcb67f6749f 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php @@ -17,13 +17,10 @@ use Neos\ContentRepository\Core\CommandHandler\CommandResult; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; -use Neos\ContentRepository\Core\Feature\NodeAggregateCommandHandler; -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; -use Neos\ContentRepository\Core\SharedModel\User\UserId; +use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; /** * Remove the property @@ -64,7 +61,6 @@ public function execute( ): ?CommandResult { if ($node->hasProperty($this->from)) { - /** @var PropertyCollectionInterface $properties */ $properties = $node->properties; return $this->contentRepository->handle( SetSerializedNodeProperties::create( diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php index a617713c9ed..1484827576b 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php @@ -17,13 +17,11 @@ use Neos\ContentRepository\Core\CommandHandler\CommandResult; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetSerializedNodeProperties; -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; -use Neos\ContentRepository\Core\SharedModel\User\UserId; +use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; /** * Strip all tags on a given property @@ -56,9 +54,8 @@ public function execute( ContentStreamId $contentStreamForWriting ): ?CommandResult { if ($node->hasProperty($this->propertyName)) { - /** @var PropertyCollectionInterface $properties */ $properties = $node->properties; - /** @var \Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue $serializedPropertyValue safe since Node::hasProperty */ + /** @var SerializedPropertyValue $serializedPropertyValue safe since Node::hasProperty */ $serializedPropertyValue = $properties->serialized()->getProperty($this->propertyName); $propertyValue = $serializedPropertyValue->value; if (!is_string($propertyValue)) { diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php index 3f0c1271ed8..66143d2ee4e 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/TransformationsFactory.php @@ -20,8 +20,7 @@ class TransformationsFactory public function __construct( private readonly ContentRepository $contentRepository - ) - { + ) { } public function registerTransformation(string $transformationIdentifier, TransformationFactoryInterface $transformationFactory): self diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePrivilege.php deleted file mode 100644 index 985e9b89a40..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePrivilege.php +++ /dev/null @@ -1,194 +0,0 @@ - $parameters - */ - public function __construct( - PrivilegeTarget $privilegeTarget, - string $matcher, - string $permission, - array $parameters - ) { - parent::__construct($privilegeTarget, $matcher, $permission, $parameters); - $this->cacheEntryIdentifier = ''; - } - - /** - * @return void - */ - public function initialize() - { - if ($this->initialized) { - return; - } - $this->initialized = true; - /** @var CompilingEvaluator $eelCompilingEvaluator */ - $eelCompilingEvaluator = $this->objectManager->get(CompilingEvaluator::class); - $this->eelCompilingEvaluator = $eelCompilingEvaluator; - /** @var NodePrivilegeContext $nodeContext */ - $nodeContext = new $this->nodeContextClassName(); - $this->nodeContext = $nodeContext; - $this->initializeMethodPrivilege(); - } - - /** - * @return void - */ - protected function buildCacheEntryIdentifier() - { - $this->cacheEntryIdentifier = md5($this->privilegeTarget->getIdentifier() - . '__methodPrivilege' . '|' . $this->buildMethodPrivilegeMatcher()); - } - - /** - * Unique identifier of this privilege - * - * @return string - */ - public function getCacheEntryIdentifier(): string - { - if ($this->cacheEntryIdentifier === '') { - $this->buildCacheEntryIdentifier(); - } - - return $this->cacheEntryIdentifier; - } - - /** - * @param PrivilegeSubjectInterface|NodePrivilegeSubject|MethodPrivilegeSubject $subject - * (one of NodePrivilegeSubject or MethodPrivilegeSubject) - * @return boolean - * @throws InvalidPrivilegeTypeException - */ - public function matchesSubject(PrivilegeSubjectInterface $subject) - { - if (!$subject instanceof NodePrivilegeSubject && !$subject instanceof MethodPrivilegeSubject) { - throw new InvalidPrivilegeTypeException(sprintf( - 'Privileges of type "%s" only support subjects of type "%s" or "%s",' - . ' but we got a subject of type: "%s".', - AbstractNodePrivilege::class, - NodePrivilegeSubject::class, - MethodPrivilegeSubject::class, - get_class($subject) - ), 1417014368); - } - - if ($subject instanceof MethodPrivilegeSubject) { - $this->initializeMethodPrivilege(); - return $this->methodPrivilege->matchesSubject($subject); - } - - $this->initialize(); - $nodeContext = new $this->nodeContextClassName($subject->getNode()); - $eelContext = new Context($nodeContext); - - return $this->eelCompilingEvaluator->evaluate($this->getParsedMatcher(), $eelContext); - } - - /** - * @param string $className - * @param string $methodName - * @return boolean - */ - public function matchesMethod($className, $methodName) - { - $this->initializeMethodPrivilege(); - return $this->methodPrivilege->matchesMethod($className, $methodName); - } - - /** - * @return PointcutFilterInterface - */ - public function getPointcutFilterComposite() - { - $this->initializeMethodPrivilege(); - return $this->methodPrivilege->getPointcutFilterComposite(); - } - - /** - * @throws \Neos\Flow\Security\Exception - */ - protected function initializeMethodPrivilege(): void - { - if ($this->methodPrivilege !== null) { - return; - } - $methodPrivilegeMatcher = $this->buildMethodPrivilegeMatcher(); - $methodPrivilegeTarget = new PrivilegeTarget( - $this->privilegeTarget->getIdentifier() . '__methodPrivilege', - MethodPrivilege::class, - $methodPrivilegeMatcher - ); - $methodPrivilegeTarget->injectObjectManager($this->objectManager); - /** @var MethodPrivilegeInterface $methodPrivilege */ - $methodPrivilege = $methodPrivilegeTarget->createPrivilege( - $this->getPermission(), - $this->getParameters() - ); - $this->methodPrivilege = $methodPrivilege; - } - - /** - * Evaluates the matcher with this objects nodeContext and returns the result. - * - * @return mixed - */ - protected function evaluateNodeContext() - { - $eelContext = new Context($this->nodeContext); - return $this->eelCompilingEvaluator->evaluate($this->getParsedMatcher(), $eelContext); - } - - /** - * @return string - */ - abstract protected function buildMethodPrivilegeMatcher(); -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePropertyPrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePropertyPrivilege.php deleted file mode 100644 index 438f61e7152..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/AbstractNodePropertyPrivilege.php +++ /dev/null @@ -1,97 +0,0 @@ - - */ - protected array $methodNameToPropertyMapping = []; - - /** - * @param PrivilegeSubjectInterface|PropertyAwareNodePrivilegeSubject|MethodPrivilegeSubject $subject - * @throws InvalidPrivilegeTypeException - */ - public function matchesSubject(PrivilegeSubjectInterface $subject): bool - { - if (!$subject instanceof PropertyAwareNodePrivilegeSubject && !$subject instanceof MethodPrivilegeSubject) { - throw new InvalidPrivilegeTypeException(sprintf( - 'Privileges of type "%s" only support subjects of type "%s" or "%s",' - . ' but we got a subject of type: "%s".', - ReadNodePropertyPrivilege::class, - PropertyAwareNodePrivilegeSubject::class, - MethodPrivilegeSubject::class, - get_class($subject) - ), 1417018448); - } - - $this->initialize(); - $this->evaluateNodeContext(); - if ($subject instanceof MethodPrivilegeSubject) { - if ($this->methodPrivilege->matchesSubject($subject) === false) { - return false; - } - - $joinPoint = $subject->getJoinPoint(); - - // if the context isn't restricted to certain properties, it matches *all* properties - if ($this->nodeContext->hasProperties()) { - $methodName = $joinPoint->getMethodName(); - $propertyName = $this->methodNameToPropertyMapping[$methodName] - ?? $joinPoint->getMethodArgument('propertyName'); - if (!in_array($propertyName, $this->nodeContext->getNodePropertyNames())) { - return false; - } - } - - /** @var Node $node */ - $node = $joinPoint->getProxy(); - $nodePrivilegeSubject = new NodePrivilegeSubject($node); - return parent::matchesSubject($nodePrivilegeSubject); - } - if ($subject->hasPropertyName() && !in_array( - $subject->getPropertyName(), - $this->nodeContext->getNodePropertyNames() - )) { - return false; - } - return parent::matchesSubject($subject); - } - - /** - * @return array - */ - public function getNodePropertyNames(): array - { - return $this->nodeContext->getNodePropertyNames(); - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilege.php deleted file mode 100644 index cbbfd195d58..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilege.php +++ /dev/null @@ -1,101 +0,0 @@ -initialize(); - $this->evaluateNodeContext(); - if ($subject instanceof MethodPrivilegeSubject) { - if ($this->methodPrivilege->matchesSubject($subject) === false) { - return false; - } - - $joinPoint = $subject->getJoinPoint(); - $allowedCreationNodeTypes = $this->nodeContext->getCreationNodeTypes(); - $actualNodeType = $joinPoint->getMethodName() === 'createNodeFromTemplate' - ? $joinPoint->getMethodArgument('nodeTemplate')->getNodeType()->getName() - : $joinPoint->getMethodArgument('nodeType')->getName(); - - if ($allowedCreationNodeTypes !== [] && !in_array($actualNodeType, $allowedCreationNodeTypes)) { - return false; - } - - /** @var Node $node */ - $node = $joinPoint->getProxy(); - $nodePrivilegeSubject = new NodePrivilegeSubject($node); - return parent::matchesSubject($nodePrivilegeSubject); - } - - $creationNodeType = $subject->getCreationNodeType(); - if ($this->nodeContext->getCreationNodeTypes() === [] - || ($subject->hasCreationNodeType() === false) - || !is_null($creationNodeType) && in_array( - $creationNodeType->getName(), - $this->nodeContext->getCreationNodeTypes() - ) === true) { - return parent::matchesSubject($subject); - } - return false; - } - - /** - * @return array $creationNodeTypes - */ - public function getCreationNodeTypes(): array - { - return $this->nodeContext->getCreationNodeTypes(); - } - - protected function buildMethodPrivilegeMatcher(): string - { - return 'method(' . CreateNodeVariant::class . '->__construct()) && method(' - . CreateNodeAggregateWithNodeAndSerializedProperties::class . '->__construct())'; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeContext.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeContext.php deleted file mode 100644 index b2b086dc7ed..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeContext.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ - protected string|array $creationNodeTypes; - - /** - * @param string|array $creationNodeTypes either an array of supported node type identifiers - * or a single node type identifier (for example "Neos.Neos:Document") - * @return boolean Has to return true, to evaluate the eel expression correctly in any case - */ - public function createdNodeIsOfType(string|array $creationNodeTypes): bool - { - $this->creationNodeTypes = $creationNodeTypes; - - return true; - } - - /** - * @return array $creationNodeTypes - */ - public function getCreationNodeTypes(): array - { - if (is_array($this->creationNodeTypes)) { - return $this->creationNodeTypes; - } - return [$this->creationNodeTypes]; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeSubject.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeSubject.php deleted file mode 100644 index acd5a1307eb..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/CreateNodePrivilegeSubject.php +++ /dev/null @@ -1,50 +0,0 @@ -creationNodeType = $creationNodeType; - parent::__construct($node, $joinPoint); - } - - public function hasCreationNodeType(): bool - { - return ($this->creationNodeType !== null); - } - - public function getCreationNodeType(): ?NodeType - { - return $this->creationNodeType; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePrivilege.php deleted file mode 100644 index 70fb9529486..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePrivilege.php +++ /dev/null @@ -1,84 +0,0 @@ -initializeMethodPrivilege(); - if ($this->methodPrivilege->matchesSubject($subject) === false) { - return false; - } - - /** @var Node $node */ - $node = $subject->getJoinPoint()->getProxy(); - $nodePrivilegeSubject = new NodePrivilegeSubject($node); - return parent::matchesSubject($nodePrivilegeSubject); - } - - return parent::matchesSubject($subject); - } - - /** - * This is the pointcut expression for all methods to intercept. - * It targets all public methods that could change the outer state of a node. - * Note: Node::setIndex() is excluded because that might be called by the system - * when redistributing nodes on one level - * - * @return string - */ - protected function buildMethodPrivilegeMatcher() - { - return 'method(' . SetSerializedNodeProperties::class . '->__construct()) || method(' - . SetNodeReferences::class . '->__construct()) || method(' - . RemoveNodeAggregate::class . '->__construct()) || method(' - . MoveNodeAggregate::class . '->__construct()) || method(' - . EnableNodeAggregate::class . '->__construct()) || method(' - . DisableNodeAggregate::class . '->__construct()) || method(' - . ChangeNodeAggregateName::class . '->__construct()) || method(' - . ChangeNodeAggregateType::class . '->__construct())'; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePropertyPrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePropertyPrivilege.php deleted file mode 100644 index d9fd60f05b9..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/EditNodePropertyPrivilege.php +++ /dev/null @@ -1,47 +0,0 @@ - - */ - protected array $methodNameToPropertyMapping = [ - 'setName' => 'name', - 'setHidden' => 'hidden', - 'setHiddenInIndex' => 'hiddenInIndex', - 'setHiddenBeforeDateTime' => 'hiddenBeforeDateTime', - 'setHiddenAfterDateTime' => 'hiddenAfterDateTime', - 'setAccessRoles' => 'accessRoles', - ]; - - protected function buildMethodPrivilegeMatcher(): string - { - return 'method(' . SetSerializedNodeProperties::class . '->__construct()) || method(' - . SetNodeReferences::class . '->__construct()) || method(' - . EnableNodeAggregate::class . '->__construct()) || method(' - . DisableNodeAggregate::class . '->__construct()) || method(' - . ChangeNodeAggregateName::class . '->__construct()) || method(' - . ChangeNodeAggregateType::class . '->__construct())'; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeContext.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeContext.php deleted file mode 100644 index 30d267a93f2..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeContext.php +++ /dev/null @@ -1,223 +0,0 @@ -node = $node; - } - - /** - * Matches if the selected node is an *ancestor* of the given node specified by $nodePathOrIdentifier - * - * Example: isAncestorNodeOf('/sites/some/path') matches for the nodes "/sites", - * "/sites/some" and "/sites/some/path" but not for "/sites/some/other" - * - * @param string $nodePathOrIdentifier The identifier or absolute path of the node to match - * @return boolean true if the given node matches otherwise false - */ - public function isAncestorNodeOf(string $nodePathOrIdentifier): bool - { - $referenceNodeAggregateId = $this->resolveNodeAggregateIdFromNodePathOrId($nodePathOrIdentifier); - if (!$referenceNodeAggregateId) { - return false; - } - - if ($referenceNodeAggregateId->equals($this->node->nodeAggregateId)) { - return true; - } - - foreach ($this->getSubgraph()->findAncestorNodes( - $referenceNodeAggregateId, - FindAncestorNodesFilter::create() - ) as $ancestorNode) { - if ($ancestorNode->nodeAggregateId->equals($this->node->nodeAggregateId)) { - return true; - } - } - - return false; - } - - /** - * Matches if the selected node is a *descendant* of the given node specified by $nodePathOrIdentifier - * - * Example: isDescendantNodeOf('/sites/some/path') matches for the nodes "/sites/some/path", - * "/sites/some/path/subnode" but not for "/sites/some/other" - * - * @param string $nodePathOrIdentifier The identifier or absolute path of the node to match - * @return bool true if the given node matches otherwise false - */ - public function isDescendantNodeOf(string $nodePathOrIdentifier): bool - { - $referenceNodeAggregateId = $this->resolveNodeAggregateIdFromNodePathOrId($nodePathOrIdentifier); - if (!$referenceNodeAggregateId) { - return false; - } - - if ($referenceNodeAggregateId->equals($this->node->nodeAggregateId)) { - return true; - } - - foreach ($this->getSubgraph()->findAncestorNodes( - $this->node->nodeAggregateId, - FindAncestorNodesFilter::create() - ) as $ancestorNode) { - if ($ancestorNode->nodeAggregateId->equals($referenceNodeAggregateId)) { - return true; - } - } - - return false; - } - - /** - * Matches if the selected node is a *descendant* or *ancestor* of the given node specified by $nodePathOrIdentifier - * - * Example: isAncestorOrDescendantNodeOf('/sites/some') matches for the nodes "/sites", "/sites/some", - * "/sites/some/sub" but not "/sites/other" - * - * @param string $nodePathOrIdentifier The identifier or absolute path of the node to match - * @return bool true if the given node matches otherwise false - */ - public function isAncestorOrDescendantNodeOf(string $nodePathOrIdentifier): bool - { - return $this->isAncestorNodeOf($nodePathOrIdentifier) || $this->isDescendantNodeOf($nodePathOrIdentifier); - } - - /** - * Matches if the selected node is of the given NodeType(s). - * If multiple types are specified, only one entry has to match - * - * Example: nodeIsOfType(['Neos.ContentRepository:NodeType1', 'Neos.ContentRepository:NodeType2'] matches, - * if the selected node is of (sub) type *Neos.ContentRepository:NodeType1* or *Neos.ContentRepository:NodeType1* - * - * @param string|array $nodeTypes A single or an array of fully qualified NodeType name(s), - * e.g. "Neos.Neos:Document" - * @return bool true if the selected node matches the $nodeTypes, otherwise false - */ - public function nodeIsOfType(string|array $nodeTypes): bool - { - if (!is_array($nodeTypes)) { - $nodeTypes = [$nodeTypes]; - } - - foreach ($nodeTypes as $nodeType) { - if ($this->node->nodeType->isOfType($nodeType)) { - return true; - } - } - return false; - } - - /** - * Matches if the selected node belongs to one of the given $workspaceNames - * - * Example: isInWorkspace(['live', 'user-admin']) matches, - * if the selected node is in one of the workspaces "user-admin" or "live" - * - * @param array $workspaceNames An array of workspace names, e.g. ["live", "user-admin"] - * @return bool true if the selected node matches the $workspaceNames, otherwise false - */ - public function isInWorkspace(array $workspaceNames): bool - { - $contentRepository = $this->contentRepositoryRegistry->get($this->node->subgraphIdentity->contentRepositoryId); - - $workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId( - $this->node->subgraphIdentity->contentStreamId - ); - return !is_null($workspace) && in_array($workspace->workspaceName->value, $workspaceNames); - } - - /** - * Matches if the currently-selected preset in the passed $dimensionName is one of $presets. - * - * Example: isInDimensionPreset('language', 'de') checks whether the currently-selected language - * preset (in the Neos backend) is "de". - * - * Implementation Note: We deliberately work on the Dimension Preset Name, and not on the - * dimension values itself; as the preset is user-visible and the actual dimension-values - * for a preset are just implementation details. - * - * @param string|array $presets - */ - public function isInDimensionPreset(string $dimensionName, string|array $presets): bool - { - if (!is_array($presets)) { - $presets = [$presets]; - } - - return in_array( - $this->node->subgraphIdentity->dimensionSpacePoint->getCoordinate( - new ContentDimensionId($dimensionName) - ), - $presets - ); - } - - /** - * Resolves the given $nodePathOrIdentifier and returns its node aggregate id if possible - * - * @param string $nodePathOrIdentifier identifier or absolute path for the node to resolve - * @return NodeAggregateId|null depending on whether the given string can be resolved or not - */ - protected function resolveNodeAggregateIdFromNodePathOrId(string $nodePathOrIdentifier): ?NodeAggregateId - { - if (AbsoluteNodePath::patternIsMatchedByString($nodePathOrIdentifier)) { - return $this->getSubgraph()->findNodeByAbsolutePath( - AbsoluteNodePath::fromString($nodePathOrIdentifier) - )?->nodeAggregateId; - } else { - return NodeAggregateId::fromString($nodePathOrIdentifier); - } - } - - private function getSubgraph(): ContentSubgraphInterface - { - if (is_null($this->subgraph)) { - $this->subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->node); - } - - return $this->subgraph; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeSubject.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeSubject.php deleted file mode 100644 index 51035f43f0a..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/NodePrivilegeSubject.php +++ /dev/null @@ -1,48 +0,0 @@ -node = $node; - $this->joinPoint = $joinPoint; - } - - public function getNode(): Node - { - return $this->node; - } - - public function getJoinPoint(): ?JoinPointInterface - { - return $this->joinPoint; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeContext.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeContext.php deleted file mode 100644 index 5d055ccfa40..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeContext.php +++ /dev/null @@ -1,53 +0,0 @@ - - */ - protected array $propertyNames = []; - - /** - * @param string|array $propertyNames - * @return boolean - */ - public function nodePropertyIsIn(string|array $propertyNames): bool - { - if (!is_array($propertyNames)) { - $propertyNames = [$propertyNames]; - } - $this->propertyNames = $propertyNames; - return true; - } - - /** - * @return array - */ - public function getNodePropertyNames(): array - { - return $this->propertyNames; - } - - /** - * Whether or not this context is bound to specific properties - */ - public function hasProperties(): bool - { - return $this->propertyNames !== []; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeSubject.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeSubject.php deleted file mode 100644 index a39801606ed..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/PropertyAwareNodePrivilegeSubject.php +++ /dev/null @@ -1,42 +0,0 @@ -propertyName = $propertyName; - parent::__construct($node, $joinPoint); - } - - public function getPropertyName(): ?string - { - return $this->propertyName; - } - - public function hasPropertyName(): bool - { - return $this->propertyName !== null; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePrivilege.php deleted file mode 100644 index a6256586393..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePrivilege.php +++ /dev/null @@ -1,51 +0,0 @@ -getNode()); - $eelContext = new Context($nodeContext); - /** @var CompilingEvaluator $eelCompilingEvaluator */ - $eelCompilingEvaluator = $this->objectManager->get(CompilingEvaluator::class); - return $eelCompilingEvaluator->evaluate($this->getParsedMatcher(), $eelContext); - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePropertyPrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePropertyPrivilege.php deleted file mode 100644 index 3e848cf8835..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/ReadNodePropertyPrivilege.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ - protected array $methodNameToPropertyMapping = [ - 'getName' => 'name', - 'isHidden' => 'hidden', - 'isHiddenInIndex' => 'hiddenInIndex', - 'getHiddenBeforeDateTime' => 'hiddenBeforeDateTime', - 'getHiddenAfterDateTime' => 'hiddenAfterDateTime', - 'getAccessRoles' => 'accessRoles', - ]; - - protected function buildMethodPrivilegeMatcher(): string - { - return 'within(' . Node::class . ') && method(.*->(getProperty|getProperties)())'; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/RemoveNodePrivilege.php b/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/RemoveNodePrivilege.php deleted file mode 100644 index 1c4c0826cbe..00000000000 --- a/Neos.ContentRepository.Security/Classes/Authorization/Privilege/Node/RemoveNodePrivilege.php +++ /dev/null @@ -1,63 +0,0 @@ -initializeMethodPrivilege(); - if ($this->methodPrivilege->matchesSubject($subject) === false) { - return false; - } - /** @var Node $node */ - $node = $subject->getJoinPoint()->getProxy(); - $nodePrivilegeSubject = new NodePrivilegeSubject($node); - return parent::matchesSubject($nodePrivilegeSubject); - } - return parent::matchesSubject($subject); - } - - /** - * @return string - */ - protected function buildMethodPrivilegeMatcher() - { - return 'method(' . RemoveNodeAggregate::class . '->__construct())'; - } -} diff --git a/Neos.ContentRepository.Security/Classes/Service/AuthorizationService.php b/Neos.ContentRepository.Security/Classes/Service/AuthorizationService.php deleted file mode 100644 index c95ff197d5f..00000000000 --- a/Neos.ContentRepository.Security/Classes/Service/AuthorizationService.php +++ /dev/null @@ -1,184 +0,0 @@ -privilegeManager->isGranted(EditNodePrivilege::class, new NodePrivilegeSubject($node)); - } - - /** - * Returns true if the currently authenticated user is allowed to create a node of type $typeOfNewNode within the given $referenceNode - * - * @param Node $referenceNode - * @param NodeType $typeOfNewNode - * @return boolean - */ - public function isGrantedToCreateNode(Node $referenceNode, NodeType $typeOfNewNode = null) - { - return $this->privilegeManager->isGranted(CreateNodePrivilege::class, new CreateNodePrivilegeSubject($referenceNode, $typeOfNewNode)); - } - - /** - * Returns the node types that the currently authenticated user is *denied* to create within the given $referenceNode - * - * @param Node $referenceNode - * @return string[] Array of granted node type names - */ - public function getNodeTypeNamesDeniedForCreation(Node $referenceNode) - { - $privilegeSubject = new CreateNodePrivilegeSubject($referenceNode); - - $contentRepository = $this->contentRepositoryRegistry->get($referenceNode->subgraphIdentity->contentRepositoryId); - $allNodeTypes = $contentRepository->getNodeTypeManager()->getNodeTypes(); - - $deniedCreationNodeTypes = []; - $grantedCreationNodeTypes = []; - $abstainedCreationNodeTypes = []; - foreach ($this->securityContext->getRoles() as $role) { - /** @var CreateNodePrivilege $createNodePrivilege */ - foreach ($role->getPrivilegesByType(CreateNodePrivilege::class) as $createNodePrivilege) { - if (!$createNodePrivilege->matchesSubject($privilegeSubject)) { - continue; - } - - if ($createNodePrivilege->getCreationNodeTypes() !== []) { - $affectedNodeTypes = $createNodePrivilege->getCreationNodeTypes(); - } else { - $affectedNodeTypes = array_map(static fn (NodeType $nodeType) => $nodeType->name->value, $allNodeTypes); - } - - if ($createNodePrivilege->isGranted()) { - $grantedCreationNodeTypes[] = array_merge($grantedCreationNodeTypes, $affectedNodeTypes); - } elseif ($createNodePrivilege->isDenied()) { - $deniedCreationNodeTypes = array_merge($deniedCreationNodeTypes, $affectedNodeTypes); - } else { - $abstainedCreationNodeTypes = array_merge($abstainedCreationNodeTypes, $affectedNodeTypes); - } - } - } - $implicitlyDeniedNodeTypes = array_diff($abstainedCreationNodeTypes, $grantedCreationNodeTypes); - return array_merge($implicitlyDeniedNodeTypes, $deniedCreationNodeTypes); - } - - /** - * Returns true if the currently authenticated user is allowed to remove the given $node - * - * @param Node $node - * @return boolean - */ - public function isGrantedToRemoveNode(Node $node) - { - $privilegeSubject = new NodePrivilegeSubject($node); - return $this->privilegeManager->isGranted(RemoveNodePrivilege::class, $privilegeSubject); - } - - /** - * @param Node $node - * @param string $propertyName - * @return boolean - */ - public function isGrantedToReadNodeProperty(Node $node, $propertyName) - { - $privilegeSubject = new PropertyAwareNodePrivilegeSubject($node, null, $propertyName); - return $this->privilegeManager->isGranted(ReadNodePropertyPrivilege::class, $privilegeSubject); - } - - /** - * @param Node $node - * @param string $propertyName - * @return boolean - */ - public function isGrantedToEditNodeProperty(Node $node, $propertyName) - { - $privilegeSubject = new PropertyAwareNodePrivilegeSubject($node, null, $propertyName); - return $this->privilegeManager->isGranted(EditNodePropertyPrivilege::class, $privilegeSubject); - } - - /** - * @param Node $node - * @return string[] Array of granted node property names - */ - public function getDeniedNodePropertiesForEditing(Node $node) - { - $privilegeSubject = new PropertyAwareNodePrivilegeSubject($node); - - $deniedNodePropertyNames = []; - $grantedNodePropertyNames = []; - $abstainedNodePropertyNames = []; - foreach ($this->securityContext->getRoles() as $role) { - /** @var EditNodePropertyPrivilege $editNodePropertyPrivilege */ - foreach ($role->getPrivilegesByType(EditNodePropertyPrivilege::class) as $editNodePropertyPrivilege) { - if (!$editNodePropertyPrivilege->matchesSubject($privilegeSubject)) { - continue; - } - if ($editNodePropertyPrivilege->isGranted()) { - $grantedNodePropertyNames = array_merge($grantedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); - } elseif ($editNodePropertyPrivilege->isDenied()) { - $deniedNodePropertyNames = array_merge($deniedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); - } else { - $abstainedNodePropertyNames = array_merge($abstainedNodePropertyNames, $editNodePropertyPrivilege->getNodePropertyNames()); - } - } - } - - $implicitlyDeniedNodePropertyNames = array_diff($abstainedNodePropertyNames, $grantedNodePropertyNames); - return array_merge($implicitlyDeniedNodePropertyNames, $deniedNodePropertyNames); - } -} diff --git a/Neos.ContentRepository.Security/Tests/Behavior/Features/Bootstrap/NodeAuthorizationTrait.php b/Neos.ContentRepository.Security/Tests/Behavior/Features/Bootstrap/NodeAuthorizationTrait.php deleted file mode 100644 index 5977c310ad6..00000000000 --- a/Neos.ContentRepository.Security/Tests/Behavior/Features/Bootstrap/NodeAuthorizationTrait.php +++ /dev/null @@ -1,639 +0,0 @@ -nodeAuthorizationService - * * $this->nodeTypeManager - * - * Note: This trait expects the IsolatedBehatStepsTrait to be available! - */ -trait NodeAuthorizationTrait -{ - use CRTestSuiteRuntimeVariables; - - /** - * @Flow\Inject - * @var \Neos\ContentRepository\Security\Service\AuthorizationService - */ - protected $nodeAuthorizationService; - - /** - * @Flow\Inject - * @var \Neos\ContentRepository\Core\NodeType\NodeTypeManager - */ - protected $nodeTypeManager; - - /** - * @param string $expectedResult - * @Given /^I should get (true|false) when asking the node authorization service if editing this node is granted$/ - */ - public function iShouldGetTrueWhenAskingTheNodeAuthorizationServiceIfEditingThisNodeIsGranted($expectedResult) - { - if ($this->isolated === true) { - $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s', 'string', escapeshellarg(trim($expectedResult)))); - } else { - if ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToEditNode($this->currentNode) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } else { - if ($this->nodeAuthorizationService->isGrantedToEditNode($this->currentNode) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } - } - } - - /** - * @Given /^I should get (true|false) when asking the node authorization service if editing the "([^"]*)" property is granted$/ - */ - public function iShouldGetTrueWhenAskingTheNodeAuthorizationServiceIfEditingThePropertyIsGranted( - $expectedResult, - $propertyName - ) { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s', - 'string', - escapeshellarg(trim($expectedResult)), - 'string', - escapeshellarg($propertyName) - ) - ); - } elseif ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToEditNodeProperty( - $this->currentNode, - $propertyName - ) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } elseif ($this->nodeAuthorizationService->isGrantedToEditNodeProperty( - $this->currentNode, - $propertyName - ) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } - - /** - * @param TableNode $table - * @Then /^I should get the following list of denied node properties from the node authorization service:$/ - */ - public function iShouldGetTheFollowingListOfDeniedNodePropertiesFromTheNodeAuthorizationService($table) - { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s', - escapeshellarg(TableNode::class), - escapeshellarg(json_encode($table->getHash())) - ) - ); - } else { - $rows = $table->getHash(); - $deniedPropertyNames = $this->nodeAuthorizationService->getDeniedNodePropertiesForEditing( - $this->currentNode - ); - - if (count($rows) !== count($deniedPropertyNames)) { - Assert::fail( - 'The node authorization service did not return the expected amount of node property names! Got: ' . implode( - ', ', - $deniedPropertyNames - ) - ); - } - - foreach ($rows as $row) { - if (in_array($row['propertyName'], $deniedPropertyNames) === false) { - Assert::fail( - 'The following property name has not been returned by the node authorization service: ' . $row['propertyName'] - ); - } - } - } - } - - /** - * @param string $not - * @throws AccessDeniedException - * @Then /^I should (not )?be granted to set any of the node's attributes$/ - */ - public function iShouldNotBeGrantedToSetAnyOfTheNodesAttributes($not = '') - { - if ($this->isolated === true) { - $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s', 'string', escapeshellarg(trim($not)))); - } else { - try { - $this->currentNode->setName('some-new-name'); - if ($not === 'not') { - Assert::fail('Name should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->removeProperty('title'); - if ($not === 'not') { - Assert::fail('Title should not be removable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setContentObject($this->currentNode->getNodeData()); - if ($not === 'not') { - Assert::fail('Content object should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->unsetContentObject(); - if ($not === 'not') { - Assert::fail('Content object should not be unsettable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $nodeTypeManager = $this->getObjectManager()->get(NodeTypeManager::class); - $this->currentNode->setNodeType($nodeTypeManager->getNodeType('Neos.Neos:Node')); - if ($not === 'not') { - Assert::fail('NodeType should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setHidden(true); - if ($not === 'not') { - Assert::fail('Hidden flag should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setHiddenBeforeDateTime(new \DateTime()); - if ($not === 'not') { - Assert::fail('Hidden before should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setHiddenAfterDateTime(new \DateTime()); - if ($not === 'not') { - Assert::fail('Hidden after should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setHiddenInIndex(true); - if ($not === 'not') { - Assert::fail('Hidden in index should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - - try { - $this->currentNode->setAccessRoles([]); - if ($not === 'not') { - Assert::fail('Access roles in index should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - } - } - - /** - * @param string $not - * @param string $nodeName - * @param string $nodeType - * @throws \Exception - * @Then /^I should (not )?be granted to create a new "([^"]*)" child node of type "([^"]*)"$/ - */ - public function iShouldNotBeGrantedToCreateANewChildNodeOfType($not, $nodeName, $nodeType) - { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s %s %s', - 'string', - escapeshellarg(trim($not)), - 'string', - escapeshellarg($nodeName), - 'string', - escapeshellarg($nodeType) - ) - ); - } else { - /** @var NodeTypeManager $nodeTypeManager */ - $nodeTypeManager = $this->getObjectManager()->get(NodeTypeManager::class); - - try { - $this->currentNode->createNode($nodeName, $nodeTypeManager->getNodeType($nodeType)); - if ($not === 'not') { - Assert::fail('Should not be able to create a child node of type "' . $nodeType . '"!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - } - } - - /** - * @param string $expectedResult - * @param string $nodeName - * @param string $nodeTypeName - * @throws NodeTypeNotFoundException - * @Given /^I should get (true|false) when asking the node authorization service if creating a new "([^"]*)" child node of type "([^"]*)" is granted$/ - */ - public function iShouldGetFalseWhenAskingTheNodeAuthorizationServiceIfCreatingAChildNodeOfTypeIsGranted( - $expectedResult, - $nodeName, - $nodeTypeName - ) { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s %s %s', - 'string', - escapeshellarg(trim($expectedResult)), - 'string', - escapeshellarg($nodeName), - 'string', - escapeshellarg($nodeTypeName) - ) - ); - } else { - /** @var NodeTypeManager $nodeTypeManager */ - $nodeTypeManager = $this->getObjectManager()->get(NodeTypeManager::class); - $nodeType = $nodeTypeManager->getNodeType($nodeTypeName); - - if ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToCreateNode( - $this->currentNode, - $nodeType - ) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } else { - if ($this->nodeAuthorizationService->isGrantedToCreateNode( - $this->currentNode, - $nodeType - ) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } - } - } - - /** - * @Then /^I should get the following list of denied node types for this node from the node authorization service:$/ - */ - public function iShouldGetTheFollowingListOfDeniedNodeTypesForThisNodeFromTheNodeAuthorizationService($table) - { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s', - escapeshellarg(TableNode::class), - escapeshellarg(json_encode($table->getHash())) - ) - ); - } else { - $rows = $table->getHash(); - $deniedNodeTypeNames = $this->nodeAuthorizationService->getNodeTypeNamesDeniedForCreation( - $this->currentNode - ); - - if (count($rows) !== count($deniedNodeTypeNames)) { - Assert::fail( - 'The node authorization service did not return the expected amount of node type names! Got: ' . implode( - ', ', - $deniedNodeTypeNames - ) - ); - } - - foreach ($rows as $row) { - if (in_array($row['nodeTypeName'], $deniedNodeTypeNames) === false) { - Assert::fail( - 'The following node type name has not been returned by the node authorization service: ' . $row['nodeTypeName'] - ); - } - } - } - } - - /** - * @Then /^I should get the list of all available node types as denied node types for this node from the node authorization service$/ - */ - public function iShouldGetTheListOfAllAvailableNodeTypesAsDeniedNodeTypesForThisNodeFromTheNodeAuthorizationService( - ) - { - if ($this->isolated === true) { - $this->callStepInSubProcess(__METHOD__); - } else { - $availableNodeTypes = $this->nodeTypeManager->getNodeTypes(); - $deniedNodeTypeNames = $this->nodeAuthorizationService->getNodeTypeNamesDeniedForCreation( - $this->currentNode - ); - - if (count($availableNodeTypes) !== count($deniedNodeTypeNames)) { - Assert::fail( - 'The node authorization service did not return the expected amount of node type names! Got: ' . implode( - ', ', - $deniedNodeTypeNames - ) - ); - } - - foreach ($availableNodeTypes as $nodeType) { - if (in_array($nodeType, $deniedNodeTypeNames) === false) { - Assert::fail( - 'The following node type name has not been returned by the node authorization service: ' . $nodeType - ); - } - } - } - } - - - /** - * @param string $not - * @Then /^I should (not )?be granted to remove the node$/ - */ - public function iShouldNotBeGrantedToRemoveTheNode($not = '') - { - if ($this->isolated === true) { - $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s', 'string', escapeshellarg(trim($not)))); - } else { - try { - $this->currentNode->remove(); - if ($not === 'not') { - Assert::fail('Name should not be settable on the current node!'); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - } - } - - /** - * @param string $expectedResult - * @Given /^I should get (true|false) when asking the node authorization service if removal of the node is granted$/ - */ - public function iShouldGetFalseWhenAskingTheNodeAuthorizationServiceIfRemovalOfTheNodeIsGranted($expectedResult) - { - if ($this->isolated === true) { - $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s', 'string', escapeshellarg(trim($expectedResult)))); - } else { - if ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToRemoveNode($this->currentNode) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } else { - if ($this->nodeAuthorizationService->isGrantedToRemoveNode($this->currentNode) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } - } - } - - /** - * @Then /^I should (not )?be granted to get the "([^"]*)" property$/ - */ - public function iShouldNotBeGrantedToGetTheProperty($not, $propertyName) - { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf(' %s %s %s %s', 'string', escapeshellarg(trim($not)), 'string', escapeshellarg($propertyName)) - ); - } else { - /** @var Node $currentNode */ - $currentNode = $this->currentNode; - try { - switch ($propertyName) { - case 'name': - $propertyValue = $currentNode->getName(); - break; - case 'hidden': - $propertyValue = $currentNode->isHidden(); - break; - case 'hiddenBeforeDateTime': - $propertyValue = $currentNode->getHiddenBeforeDateTime(); - break; - case 'hiddenAfterDateTime': - $propertyValue = $currentNode->getHiddenAfterDateTime(); - break; - case 'hiddenInIndex': - $propertyValue = $currentNode->isHiddenInIndex(); - break; - case 'accessRoles': - $propertyValue = $currentNode->getAccessRoles(); - break; - default: - $propertyValue = $currentNode->getProperty($propertyName); - break; - } - if ($not === 'not') { - Assert::fail( - 'Property should not be gettable on the current node! But we could read the value: "' . $propertyValue . '"' - ); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - } - } - - /** - * @Given /^I should get (true|false) when asking the node authorization service if getting the "([^"]*)" property is granted$/ - */ - public function iShouldGetFalseWhenAskingTheNodeAuthorizationServiceIfGettingThePropertyIsGranted( - $expectedResult, - $propertyName - ) { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s', - 'string', - escapeshellarg(trim($expectedResult)), - 'string', - escapeshellarg($propertyName) - ) - ); - } elseif ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToReadNodeProperty( - $this->currentNode, - $propertyName - ) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } elseif ($this->nodeAuthorizationService->isGrantedToReadNodeProperty( - $this->currentNode, - $propertyName - ) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } - - /** - * @Then /^I should (not )?be granted to set the "([^"]*)" property to "([^"]*)"$/ - */ - public function iShouldNotBeGrantedToSetThePropertyTo($not, $propertyName, $value) - { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s %s %s', - 'string', - escapeshellarg(trim($not)), - 'string', - escapeshellarg($propertyName), - 'string', - escapeshellarg($value) - ) - ); - } else { - /** @var Node $currentNode */ - $currentNode = $this->currentNode; - try { - switch ($propertyName) { - case 'name': - $currentNode->setName($value); - break; - case 'hidden': - $currentNode->setHidden($value); - break; - case 'hiddenBeforeDateTime': - $currentNode->setHiddenBeforeDateTime(new \DateTime($value)); - break; - case 'hiddenAfterDateTime': - $currentNode->setHiddenAfterDateTime(new \DateTime($value)); - break; - case 'hiddenInIndex': - $currentNode->setHiddenInIndex($value); - break; - case 'accessRoles': - $currentNode->setAccessRoles([$value]); - break; - default: - $currentNode->setProperty($propertyName, $value); - break; - } - if ($not === 'not') { - Assert::fail( - 'Property should not be settable on the current node! But we could set the value of "' . $propertyName . '" to "' . $value . '"' - ); - } - } catch (AccessDeniedException $exception) { - if ($not !== 'not') { - throw $exception; - } - } - } - } - - /** - * @Given /^I should get (true|false) when asking the node authorization service if setting the "([^"]*)" property is granted$/ - */ - public function iShouldGetFalseWhenAskingTheNodeAuthorizationServiceIfSettingThePropertyIsGranted( - $expectedResult, - $propertyName - ) { - if ($this->isolated === true) { - $this->callStepInSubProcess( - __METHOD__, - sprintf( - ' %s %s %s %s', - 'string', - escapeshellarg(trim($expectedResult)), - 'string', - escapeshellarg($propertyName) - ) - ); - } elseif ($expectedResult === 'true') { - if ($this->nodeAuthorizationService->isGrantedToEditNodeProperty( - $this->currentNode, - $propertyName - ) !== true) { - Assert::fail('The node authorization service did not return true!'); - } - } elseif ($this->nodeAuthorizationService->isGrantedToEditNodeProperty( - $this->currentNode, - $propertyName - ) !== false) { - Assert::fail('The node authorization service did not return false!'); - } - } -} diff --git a/Neos.ContentRepository.Security/composer.json b/Neos.ContentRepository.Security/composer.json deleted file mode 100644 index 35f704ed157..00000000000 --- a/Neos.ContentRepository.Security/composer.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "name": "neos/contentrepository-security", - "type": "neos-package", - "description": "Event sourced Site and Workspace for Neos.", - "license": [ - "GPL-3.0-or-later" - ], - "require": { - "neos/neos": "*", - "neos/neos-ui": "*" - }, - "autoload": { - "psr-4": { - "Neos\\ContentRepository\\Security\\": "Classes" - } - }, - "extra": { - "applied-flow-migrations": [ - "TYPO3.TYPO3CR-20150510103823", - "TYPO3.FLOW3-201201261636", - "TYPO3.Fluid-201205031303", - "TYPO3.FLOW3-201205292145", - "TYPO3.FLOW3-201206271128", - "TYPO3.Flow-201211151101", - "TYPO3.Neos.NodeTypes-130516220640", - "TYPO3.TypoScript-130516234520", - "TYPO3.TypoScript-130516235550", - "TYPO3.TYPO3CR-130523180140", - "TYPO3.Neos.NodeTypes-201309111655", - "TYPO3.Neos-201310021548", - "TYPO3.Flow-201310031523", - "TYPO3.Flow-201405111147", - "TYPO3.Neos-201409071922", - "TYPO3.TYPO3CR-140911160326", - "TYPO3.Neos-201410010000", - "TYPO3.TYPO3CR-141101082142", - "TYPO3.Neos-20141113115300", - "TYPO3.Fluid-20141121091700", - "TYPO3.Neos-20141218134700", - "TYPO3.Fluid-20150214130800", - "TYPO3.Neos-201407061038", - "TYPO3.Flow-201212051340", - "TYPO3.Fluid-20141113120800", - "TYPO3.Flow-20141113121400", - "Typo3.Neos.NodeTypes-201309111655", - "TYPO3.TYPO3CR-20140911160326", - "TYPO3.Flow-201209251426", - "TYPO3.FLOW3-201209201112", - "TYPO3.Neos-20150303231600", - "TYPO3.Flow-20151113161300", - "TYPO3.Form-20160601101500", - "TYPO3.Flow-20161115140400", - "TYPO3.Flow-20161115140430", - "Neos.Flow-20161124204700", - "Neos.Flow-20161124204701", - "Neos.Twitter.Bootstrap-20161124204912", - "Neos.Form-20161124205254", - "Neos.Flow-20161124224015", - "Neos.Party-20161124225257", - "Neos.Eel-20161124230101", - "Neos.Kickstart-20161124230102", - "Neos.Setup-20161124230842", - "Neos.Imagine-20161124231742", - "Neos.Media-20161124233100", - "Neos.NodeTypes-20161125002300", - "Neos.SiteKickstarter-20161125002311", - "Neos.Neos-20161125002322", - "Neos.ContentRepository-20161125012000", - "Neos.Fusion-20161125013710", - "Neos.Setup-20161125014759", - "Neos.SiteKickstarter-20161125095901", - "Neos.Fusion-20161125104701", - "Neos.NodeTypes-20161125104800", - "Neos.Neos-20161125104802", - "Neos.Kickstarter-20161125110814", - "Neos.Flow-20161125124112", - "Neos.Neos-20161125122412", - "TYPO3.FluidAdaptor-20161130112935", - "Neos.Fusion-20161201202543", - "Neos.Neos-20161201222211", - "Neos.Fusion-20161202215034", - "Neos.ContentRepository-20161219093512", - "Neos.Fusion-20170120013047", - "Neos.Flow-20180415105700", - "Neos.Fusion-20161219092345", - "Neos.Media-20161219094126", - "Neos.Neos-20161219094403", - "Neos.Neos-20161219122512", - "Neos.Fusion-20161219130100", - "Neos.Neos-20161220163741", - "Neos.Neos-20170115114620", - "Neos.Flow-20170125103800", - "Neos.Seo-20170127154600", - "Neos.Flow-20170127183102", - "Neos.Fusion-20180211175500", - "Neos.Fusion-20180211184832" - ] - } -} diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php index 0dfa463e7ee..1111146fc21 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/DisallowedChildNodeAdjustment.php @@ -7,23 +7,21 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; +use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; +use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; -use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; -use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; -use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePointSet; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; +use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\EventStore\Model\EventStream\ExpectedVersion; class DisallowedChildNodeAdjustment { use RemoveNodeAggregateTrait; - use LoadNodeTypeTrait; public function __construct( private readonly ContentRepository $contentRepository, @@ -37,19 +35,17 @@ public function __construct( */ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generator { - $nodeType = $this->loadNodeType($nodeTypeName); - - if ($nodeType === null) { + if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) { // no adjustments for unknown node types return; } foreach ($this->projectedNodeIterator->nodeAggregatesOfType($nodeTypeName) as $nodeAggregate) { - $nodeType = $this->loadNodeType($nodeAggregate->nodeTypeName); - if ($nodeType === null) { + if (!$this->nodeTypeManager->hasNodeType($nodeAggregate->nodeTypeName)) { // unknown child node type, so we skip this test as we won't be able to find out node type constraints continue; } + $nodeType = $this->nodeTypeManager->getNodeType($nodeAggregate->nodeTypeName); // Here, we iterate over the covered dimension space points of the node aggregate one by one; // as it can happen that the constraint is only violated in e.g. "AT", but not in "DE". @@ -66,13 +62,13 @@ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generat ? $subgraph->findParentNode($parentNode->nodeAggregateId) : null; - $allowedByParent = true; $parentNodeType = null; if ($parentNode !== null) { - $parentNodeType = $this->loadNodeType($parentNode->nodeTypeName); - if ($parentNodeType !== null) { - $allowedByParent = $parentNodeType->allowsChildNodeType($nodeType); + if ($this->nodeTypeManager->hasNodeType($parentNode->nodeTypeName)) { + $parentNodeType = $this->nodeTypeManager->getNodeType($parentNode->nodeTypeName); + $allowedByParent = $parentNodeType->allowsChildNodeType($nodeType) + || $nodeAggregate->nodeName && $parentNodeType->hasTetheredNode($nodeAggregate->nodeName); } } @@ -80,14 +76,15 @@ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generat $grandparentNodeType = null; if ( $parentNode !== null - && $grandparentNode != null + && $grandparentNode !== null && $parentNode->classification->isTethered() && !is_null($parentNode->nodeName) ) { - $grandparentNodeType = $this->loadNodeType($grandparentNode->nodeTypeName); + $grandparentNodeType = $this->nodeTypeManager->hasNodeType($grandparentNode->nodeTypeName) ? $this->nodeTypeManager->getNodeType($grandparentNode->nodeTypeName) : null; if ($grandparentNodeType !== null) { - $allowedByGrandparent = $grandparentNodeType->allowsGrandchildNodeType( - $parentNode->nodeName->value, + $allowedByGrandparent = $this->nodeTypeManager->isNodeTypeAllowedAsChildToTetheredNode( + $grandparentNodeType, + $parentNode->nodeName, $nodeType ); } @@ -101,10 +98,10 @@ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generat $message = sprintf( ' - The parent node type "%s" is not allowing children of type "%s", - and the grandparent node type "%s" is not allowing grandchildren of type "%s". - Thus, the node is invalid at this location and should be removed. - ', + The parent node type "%s" is not allowing children of type "%s", + and the grandparent node type "%s" is not allowing grandchildren of type "%s". + Thus, the node is invalid at this location and should be removed. + ', $parentNodeType !== null ? $parentNodeType->name->value : '', $node->nodeTypeName->value, $grandparentNodeType !== null ? $grandparentNodeType->name->value : '', @@ -127,6 +124,7 @@ function () use ($nodeAggregate, $coveredDimensionSpacePoint) { } } + private function removeNodeInSingleDimensionSpacePoint( NodeAggregate $nodeAggregate, DimensionSpacePoint $dimensionSpacePoint @@ -153,9 +151,4 @@ private function removeNodeInSingleDimensionSpacePoint( ExpectedVersion::ANY() ); } - - protected function getNodeTypeManager(): NodeTypeManager - { - return $this->nodeTypeManager; - } } diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/LoadNodeTypeTrait.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/LoadNodeTypeTrait.php deleted file mode 100644 index 2728d52caad..00000000000 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/LoadNodeTypeTrait.php +++ /dev/null @@ -1,38 +0,0 @@ -getNodeTypeManager()->getNodeType($nodeTypeName->value); - if (!$nodeTypeName->equals($nodeType->name)) { - // the $nodeTypeName was different than the fetched node type; so that means - // that the FallbackNodeType has been returned. - return null; - } - return $nodeType; - } catch (NodeTypeNotFoundException $e) { - // the $nodeTypeName was not found; so we need to remove all nodes of this type. - // This case applies if the fallbackNodeType is not configured. - return null; - } - } -} diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/PropertyAdjustment.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/PropertyAdjustment.php index cdeb6b8d351..f84c7a74524 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/PropertyAdjustment.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/PropertyAdjustment.php @@ -6,22 +6,18 @@ use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; -use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; -use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; -use Neos\ContentRepository\Core\Projection\ContentGraph\PropertyCollectionInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; -use Neos\ContentRepository\Core\SharedModel\User\UserId; -use Neos\EventStore\Model\EventStream\ExpectedVersion; -use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; +use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; +use Neos\EventStore\Model\EventStream\ExpectedVersion; class PropertyAdjustment { - use LoadNodeTypeTrait; - public function __construct( private readonly ProjectedNodeIterator $projectedNodeIterator, private readonly NodeTypeManager $nodeTypeManager @@ -33,18 +29,18 @@ public function __construct( */ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generator { - $nodeType = $this->loadNodeType($nodeTypeName); - if ($nodeType === null) { + if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) { // In case we cannot find the expected tethered nodes, this fix cannot do anything. return; } + $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); + $expectedPropertiesFromNodeType = array_filter($nodeType->getProperties(), fn ($value) => $value !== null); foreach ($this->projectedNodeIterator->nodeAggregatesOfType($nodeTypeName) as $nodeAggregate) { foreach ($nodeAggregate->getNodes() as $node) { $propertyKeysInNode = []; - /** @var PropertyCollectionInterface $properties */ $properties = $node->properties; foreach ($properties->serialized() as $propertyKey => $property) { $propertyKeysInNode[$propertyKey] = $propertyKey; @@ -135,9 +131,4 @@ private function publishNodePropertiesWereSet( ExpectedVersion::ANY() ); } - - protected function getNodeTypeManager(): NodeTypeManager - { - return $this->nodeTypeManager; - } } diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php index 7bff3925f22..994672b390e 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php @@ -32,7 +32,6 @@ class TetheredNodeAdjustments { use NodeVariationInternals; use RemoveNodeAggregateTrait; - use LoadNodeTypeTrait; use TetheredNodeInternals; public function __construct( @@ -48,12 +47,11 @@ public function __construct( */ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generator { - $nodeType = $this->loadNodeType($nodeTypeName); - if ($nodeType === null) { + if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) { // In case we cannot find the expected tethered nodes, this fix cannot do anything. return; } - $expectedTetheredNodes = $nodeType->getAutoCreatedChildNodes(); + $expectedTetheredNodes = $this->nodeTypeManager->getTetheredNodesConfigurationForNodeType($this->nodeTypeManager->getNodeType($nodeTypeName)); foreach ($this->projectedNodeIterator->nodeAggregatesOfType($nodeTypeName) as $nodeAggregate) { // find missing tethered nodes @@ -204,11 +202,6 @@ protected function getInterDimensionalVariationGraph(): DimensionSpace\InterDime return $this->interDimensionalVariationGraph; } - protected function getNodeTypeManager(): NodeTypeManager - { - return $this->nodeTypeManager; - } - /** * array key: name of tethered child node. Value: the Node itself. * @param array $actualTetheredChildNodes diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/UnknownNodeTypeAdjustment.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/UnknownNodeTypeAdjustment.php index 903ae844770..e80657f3602 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/UnknownNodeTypeAdjustment.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/UnknownNodeTypeAdjustment.php @@ -10,7 +10,6 @@ class UnknownNodeTypeAdjustment { use RemoveNodeAggregateTrait; - use LoadNodeTypeTrait; public function __construct( private readonly ProjectedNodeIterator $projectedNodeIterator, @@ -23,8 +22,7 @@ public function __construct( */ public function findAdjustmentsForNodeType(NodeTypeName $nodeTypeName): \Generator { - $nodeType = $this->loadNodeType($nodeTypeName); - if ($nodeType === null) { + if (!$this->nodeTypeManager->hasNodeType($nodeTypeName)) { // node type is not existing right now. yield from $this->removeAllNodesOfType($nodeTypeName); } @@ -47,9 +45,4 @@ function () use ($nodeAggregate) { ); } } - - protected function getNodeTypeManager(): NodeTypeManager - { - return $this->nodeTypeManager; - } } diff --git a/Neos.ContentRepository.StructureAdjustment/src/StructureAdjustmentService.php b/Neos.ContentRepository.StructureAdjustment/src/StructureAdjustmentService.php index 736a9141299..a6fe7ec2018 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/StructureAdjustmentService.php +++ b/Neos.ContentRepository.StructureAdjustment/src/StructureAdjustmentService.php @@ -32,8 +32,7 @@ public function __construct( private readonly EventPersister $eventPersister, NodeTypeManager $nodeTypeManager, InterDimensionalVariationGraph $interDimensionalVariationGraph, - ) - { + ) { $projectedNodeIterator = new ProjectedNodeIterator( $contentRepository->getWorkspaceFinder(), $contentRepository->getContentGraph(), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php index 03ad2356823..6013ed435f0 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php @@ -22,6 +22,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; @@ -52,6 +53,11 @@ trait CRTestSuiteRuntimeVariables protected ?NodeAggregate $currentNodeAggregate = null; + /** + * @var array + */ + protected array $rememberedNodeAggregateIds = []; + /** * @Given /^I am in content repository "([^"]*)"$/ */ @@ -150,6 +156,17 @@ public function getCurrentSubgraph(): ContentSubgraphInterface ); } + /** + * @Given /^I remember NodeAggregateId of node "([^"]*)"s child "([^"]*)" as "([^"]*)"$/ + */ + public function iRememberNodeAggregateIdOfNodesChildAs(string $parentNodeAggregateId, string $childNodeName, string $indexName): void + { + $this->rememberedNodeAggregateIds[$indexName] = $this->getCurrentSubgraph()->findChildNodeConnectedThroughEdgeName( + NodeAggregateId::fromString($parentNodeAggregateId), + NodeName::fromString($childNodeName) + )->nodeAggregateId; + } + protected function getCurrentNodeAggregateId(): NodeAggregateId { assert($this->currentNode instanceof Node); diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php index 51c82feb566..9d7eb8ee253 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php @@ -185,12 +185,15 @@ public function theFollowingCreateNodeAggregateWithNodeCommandsAreExecuted(Table $originDimensionSpacePoint = isset($row['originDimensionSpacePoint']) ? OriginDimensionSpacePoint::fromJsonString($row['originDimensionSpacePoint']) : OriginDimensionSpacePoint::fromDimensionSpacePoint($this->currentDimensionSpacePoint); + $rawParentNodeAggregateId = $row['parentNodeAggregateId']; $command = CreateNodeAggregateWithNode::create( $contentStreamId, NodeAggregateId::fromString($row['nodeAggregateId']), NodeTypeName::fromString($row['nodeTypeName']), $originDimensionSpacePoint, - NodeAggregateId::fromString($row['parentNodeAggregateId']), + \str_starts_with($rawParentNodeAggregateId, '$') + ? $this->rememberedNodeAggregateIds[\mb_substr($rawParentNodeAggregateId, 1)] + : NodeAggregateId::fromString($rawParentNodeAggregateId), isset($row['succeedingSiblingNodeAggregateId']) ? NodeAggregateId::fromString($row['succeedingSiblingNodeAggregateId']) : null, diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php index 61296835fd7..9e4ea82ca59 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php @@ -50,9 +50,12 @@ public function theCommandSetPropertiesIsExecutedWithPayload(TableNode $payloadT $commandArguments['originDimensionSpacePoint'] = $this->currentDimensionSpacePoint->jsonSerialize(); } + $rawNodeAggregateId = $commandArguments['nodeAggregateId']; $command = SetNodeProperties::create( ContentStreamId::fromString($commandArguments['contentStreamId']), - NodeAggregateId::fromString($commandArguments['nodeAggregateId']), + \str_starts_with($rawNodeAggregateId, '$') + ? $this->rememberedNodeAggregateIds[\mb_substr($rawNodeAggregateId, 1)] + : NodeAggregateId::fromString($rawNodeAggregateId), OriginDimensionSpacePoint::fromArray($commandArguments['originDimensionSpacePoint']), $this->deserializeProperties($commandArguments['propertyValues']), ); diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php index 3f9deb68f63..d43d4b26628 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php @@ -66,7 +66,7 @@ public function theCommandSetNodeReferencesIsExecutedWithPayload(TableNode $payl ) ); - $command = new SetNodeReferences( + $command = SetNodeReferences::create( $contentStreamId, NodeAggregateId::fromString($commandArguments['sourceNodeAggregateId']), $sourceOriginDimensionSpacePoint, diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php index 0bc38923894..56cf734547c 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php @@ -29,11 +29,11 @@ /** * The node creation trait for behavioral tests */ -final class GherkinTableNodeBasedContentDimensionSource implements ContentDimensionSourceInterface +final readonly class GherkinTableNodeBasedContentDimensionSource implements ContentDimensionSourceInterface { private function __construct( /** @var array */ - private readonly array $contentDimensions + private array $contentDimensions ) { } @@ -82,7 +82,7 @@ public static function fromGherkinTableNode(TableNode $tableNode): self $dimensions[$dimensionId] = new ContentDimension( new ContentDimensionId($dimensionId), new ContentDimensionValues($dimensionValues), - new ContentDimensionValueVariationEdges($variationEdges), + new ContentDimensionValueVariationEdges(...$variationEdges), $dimensionConfiguration ); } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/NodeDiscriminators.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/NodeDiscriminators.php index 3865c7d3975..2bedcbce70e 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/NodeDiscriminators.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/NodeDiscriminators.php @@ -63,7 +63,7 @@ public static function fromNodes(Nodes $nodes): self public function equal(self $other): bool { - return $this->discriminators == iterator_to_array($other->getIterator()); + return $this->discriminators == $other->discriminators; } public function areSimilarTo(self $other): bool @@ -81,7 +81,7 @@ public function areSimilarTo(self $other): bool */ public function getIterator(): \Traversable { - return new \ArrayIterator($this->discriminators); + yield from $this->discriminators; } public function offsetGet(mixed $offset): ?NodeDiscriminator diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/NodeTraversalTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/NodeTraversalTrait.php index 19477800af5..1e0323c69d2 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/NodeTraversalTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/NodeTraversalTrait.php @@ -26,6 +26,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindBackReferencesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindDescendantNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindReferencesFilter; @@ -283,6 +284,19 @@ public function iExecuteTheFindAncestorNodesQueryIExpectTheFollowingNodes(string Assert::assertSame($expectedTotalCount ?? count($expectedNodeIds), $actualCount, 'countAncestorNodes returned an unexpected result'); } + /** + * @When /^I execute the findClosestNode query for entry node aggregate id "(?[^"]*)"(?: and filter '(?[^']*)')? I expect (?:the node "(?[^"]*)"|no node) to be returned?$/ + */ + public function iExecuteTheFindClosestNodeQueryIExpectTheFollowingNodes(string $entryNodeIdSerialized, string $filterSerialized = '', string $expectedNodeId = null): void + { + $entryNodeAggregateId = NodeAggregateId::fromString($entryNodeIdSerialized); + $filterValues = !empty($filterSerialized) ? json_decode($filterSerialized, true, 512, JSON_THROW_ON_ERROR) : []; + $filter = FindClosestNodeFilter::create(...$filterValues); + $subgraph = $this->getCurrentSubgraph(); + $actualNodeId = $subgraph->findClosestNode($entryNodeAggregateId, $filter)?->nodeAggregateId->value; + Assert::assertSame($expectedNodeId, $actualNodeId, 'findClosestNode returned an unexpected result'); + } + /** * @When I execute the countNodes query I expect the result to be :expectedResult */ diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeAggregateTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeAggregateTrait.php index d2f586f8aab..ab7d13c76e7 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeAggregateTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeAggregateTrait.php @@ -175,7 +175,7 @@ public function iExpectThisNodeAggregateToHaveTheParentNodeAggregates(string $se $this->assertOnCurrentNodeAggregate(function (NodeAggregate $nodeAggregate) use ($expectedNodeAggregateIds) { $expectedDiscriminators = array_values(array_map(function (NodeAggregateId $nodeAggregateId) { return $this->currentContentStreamId->value . ';' . $nodeAggregateId->value; - }, $expectedNodeAggregateIds->getIterator()->getArrayCopy())); + }, iterator_to_array($expectedNodeAggregateIds))); $actualDiscriminators = array_values(array_map( fn (NodeAggregate $parentNodeAggregate): string => $parentNodeAggregate->contentStreamId->value . ';' . $parentNodeAggregate->nodeAggregateId->value, diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php index 990447e538d..e0abd0e1d3c 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\References; use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; +use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -80,19 +81,18 @@ public function iExpectANodeIdentifiedByXToExistInTheContentGraph(string $serial { $nodeDiscriminator = NodeDiscriminator::fromShorthand($serializedNodeDiscriminator); $this->initializeCurrentNodeFromContentGraph(function (ContentGraphInterface $contentGraph) use ($nodeDiscriminator) { - $currentNode = $contentGraph->findNodeByIdAndOriginDimensionSpacePoint( + $currentNodeAggregate = $contentGraph->findNodeAggregateById( $nodeDiscriminator->contentStreamId, - $nodeDiscriminator->nodeAggregateId, - $nodeDiscriminator->originDimensionSpacePoint + $nodeDiscriminator->nodeAggregateId ); - Assert::assertNotNull( - $currentNode, + Assert::assertTrue( + $currentNodeAggregate?->occupiesDimensionSpacePoint($nodeDiscriminator->originDimensionSpacePoint), 'Node with aggregate id "' . $nodeDiscriminator->nodeAggregateId->value . '" and originating in dimension space point "' . $nodeDiscriminator->originDimensionSpacePoint->toJson() . '" was not found in content stream "' . $nodeDiscriminator->contentStreamId->value . '"' ); - return $currentNode; + return $currentNodeAggregate->getNodeByOccupiedDimensionSpacePoint($nodeDiscriminator->originDimensionSpacePoint); }); } diff --git a/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php b/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php index ecf9d8f3160..170db769f12 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php +++ b/Neos.ContentRepository.TestSuite/Classes/Unit/NodeSubjectProvider.php @@ -90,15 +90,15 @@ public function createMinimalNodeOfType( ); } $serializedDefaultPropertyValues = SerializedPropertyValues::fromArray($defaultPropertyValues); - return new Node( + return Node::create( ContentSubgraphIdentity::create( ContentRepositoryId::fromString('default'), ContentStreamId::fromString('cs-id'), - DimensionSpacePoint::fromArray([]), + DimensionSpacePoint::createWithoutDimensions(), VisibilityConstraints::withoutRestrictions() ), NodeAggregateId::create(), - OriginDimensionSpacePoint::fromArray([]), + OriginDimensionSpacePoint::createWithoutDimensions(), NodeAggregateClassification::CLASSIFICATION_REGULAR, $nodeType->name, $nodeType, diff --git a/Neos.ContentRepository.TestSuite/composer.json b/Neos.ContentRepository.TestSuite/composer.json index 939f3cd0a9d..cd68506081d 100644 --- a/Neos.ContentRepository.TestSuite/composer.json +++ b/Neos.ContentRepository.TestSuite/composer.json @@ -10,8 +10,8 @@ "neos/contentrepository-structureadjustment": "*", "neos/contentrepository-nodemigration": "*", "neos/utility-arrays": "*", - "behat/behat": "~3.0", - "phpunit/phpunit": "^10.0" + "behat/behat": "^3.5", + "phpunit/phpunit": "^9.0" }, "autoload": { "psr-4": { diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php index 62005598387..691ebe85b25 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php @@ -39,6 +39,15 @@ public function __construct( parent::__construct(); } + /** + * Refreshes the root node dimensions in the specified content repository for the specified workspace. + * + * In the content repository, the root node has to cover all existing dimension space points. + * With this command, the root node can be updated such that it represents all configured dimensions + * + * @param string $contentRepository The content repository identifier. (Default: 'default') + * @param string $workspace The workspace name. (Default: 'live') + */ public function refreshRootNodeDimensionsCommand(string $contentRepository = 'default', string $workspace = WorkspaceName::WORKSPACE_NAME_LIVE): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); @@ -72,6 +81,22 @@ public function refreshRootNodeDimensionsCommand(string $contentRepository = 'de $this->outputLine('Done!'); } + /** + * Moves a dimension space point from the source to the target in the specified workspace and content repository. + * + * With this command all nodes for a given content dimension can be moved to a different dimension. This can be necessary + * if a dimension configuration has been added or renamed. + * + * *Note:* source and target dimensions have to be specified as JSON, for example: + * ``` + * ./flow content:movedimensionspacepoint '{"language": "de"}' '{"language": "en"}' + * ``` + * + * @param string $source The JSON representation of the source dimension space point. (Example: '{"language": "de"}') + * @param string $target The JSON representation of the target dimension space point. (Example: '{"language": "en"}') + * @param string $contentRepository The content repository identifier. (Default: 'default') + * @param string $workspace The workspace name. (Default: 'live') + */ public function moveDimensionSpacePointCommand(string $source, string $target, string $contentRepository = 'default', string $workspace = WorkspaceName::WORKSPACE_NAME_LIVE): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); @@ -98,6 +123,21 @@ public function moveDimensionSpacePointCommand(string $source, string $target, s $this->outputLine('Done!'); } + /** + * Creates node variants recursively from the source to the target dimension space point in the specified workspace and content repository. + * + * This can be necessary if a new content dimension specialization was added (for example a more specific language) + * + * *Note:* source and target dimensions have to be specified as JSON, for example: + * ``` + * ./flow content:createvariantsrecursively '{"language": "de"}' '{"language": "de_ch"}' + * ``` + * + * @param string $source The JSON representation of the source dimension space point. (Example: '{"language": "de"}') + * @param string $target The JSON representation of the target origin dimension space point. (Example: '{"language": "en"}') + * @param string $contentRepository The content repository identifier. (Default: 'default') + * @param string $workspace The workspace name. (Default: 'live') + */ public function createVariantsRecursivelyCommand(string $source, string $target, string $contentRepository = 'default', string $workspace = WorkspaceName::WORKSPACE_NAME_LIVE): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); @@ -148,7 +188,8 @@ private function createVariantRecursivelyInternal(int $level, NodeAggregateId $p foreach ($childNodes as $childNode) { if ($childNode->classification->isRegular()) { - if ($childNode->nodeType->isOfType('Neos.Neos:Document')) { + $childNodeType = $contentRepository->getNodeTypeManager()->getNodeType($childNode->nodeTypeName); + if ($childNodeType->isOfType('Neos.Neos:Document')) { $this->output("%s- %s\n", [ str_repeat(' ', $level), $childNode->getProperty('uriPathSegment') ?? $childNode->nodeAggregateId->value @@ -163,7 +204,7 @@ private function createVariantRecursivelyInternal(int $level, NodeAggregateId $p $target ))->block(); } catch (DimensionSpacePointIsAlreadyOccupied $e) { - if ($childNode->nodeType->isOfType('Neos.Neos:Document')) { + if ($childNodeType->isOfType('Neos.Neos:Document')) { $this->output("%s (already exists)\n", [ str_repeat(' ', $level) ]); diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php index c50a34e0289..593904438c7 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/CrCommandController.php @@ -90,6 +90,12 @@ public function replayAllCommand(string $contentRepository = 'default', bool $qu } } + /** + * This will completely prune the data of the specified content repository. + * + * @param string $contentRepository name of the content repository where the data should be pruned from. + * @return void + */ public function pruneCommand(string $contentRepository = 'default'): void { if (!$this->output->askConfirmation(sprintf("This will prune your content repository \"%s\". Are you sure to proceed? (y/n) ", $contentRepository), false)) { diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/NodeMigrationCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/NodeMigrationCommandController.php index 6d9c5a0afa3..86955520f8f 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/NodeMigrationCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/NodeMigrationCommandController.php @@ -40,8 +40,7 @@ public function __construct( private readonly ContentRepositoryRegistry $contentRepositoryRegistry, private readonly PackageManager $packageManager, private readonly NodeMigrationGeneratorService $nodeMigrationGeneratorService - ) - { + ) { parent::__construct(); } @@ -53,9 +52,9 @@ public function __construct( * @param boolean $force Confirm application of this migration, only needed if the given migration contains any warnings. * @return void * @throws StopCommandException - * @see neos.contentrepositoryregistry:nodemigration:migrate + * @see neos.contentrepositoryregistry:nodemigration:execute */ - public function migrateCommand(string $version, string $workspace = 'live', bool $force = false, string $contentRepositoryIdentifier = 'default'): void + public function executeCommand(string $version, string $workspace = 'live', bool $force = false, string $contentRepositoryIdentifier = 'default'): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier); @@ -66,7 +65,7 @@ public function migrateCommand(string $version, string $workspace = 'live', bool if ($migrationConfiguration->hasWarnings() && $force === false) { $this->outputLine(); $this->outputLine('Migration has warnings.' - . ' You need to confirm execution by adding the "--confirmation true" option to the command.'); + . ' You need to confirm execution by adding the "--force true" option to the command.'); $this->quit(1); } @@ -94,24 +93,55 @@ public function migrateCommand(string $version, string $workspace = 'live', bool * @throws UnknownPackageException * @throws FilesException * @throws StopCommandException - * @see neos.contentrepositoryregistry:nodemigration:migrationcreate + * @see neos.contentrepositoryregistry:nodemigration:kickstart */ - public function migrationCreateCommand(string $packageKey): void + public function kickstartCommand(string $packageKey): void { - if (!$this->packageManager->isPackageAvailable($packageKey)) { - $this->outputLine('Package "%s" is not available.', [$packageKey]); - $this->quit(1); + if (!$this->packageManager->isPackageAvailable($packageKey)) { + $this->outputLine('Package "%s" is not available.', [$packageKey]); + $this->quit(1); } try { $createdMigration = $this->nodeMigrationGeneratorService->generateBoilerplateMigrationFileInPackage($packageKey); } catch (MigrationException $e) { - $this->outputLine(); - $this->outputLine('Error ' . $e->getMessage()); - $this->quit(1); + $this->outputLine(); + $this->outputLine('Error ' . $e->getMessage()); + $this->quit(1); + } + $this->outputLine($createdMigration); + $this->outputLine('Your node migration has been created successfully.'); + } + + /** + * List available migrations + * + * @see neos.contentrepositoryregistry:nodemigration:list + */ + public function listCommand(): void + { + $availableMigrations = $this->migrationFactory->getAvailableVersions(); + if (count($availableMigrations) === 0) { + $this->outputLine('No migrations available.'); + $this->quit(); + } + + $tableRows = []; + foreach ($availableMigrations as $version => $migration) { + $migrationUpConfigurationComments = $this->migrationFactory->getMigrationForVersion($version)->getComments(); + + $tableRows[] = [ + $version, + $migration['formattedVersionNumber'], + $migration['package']->getPackageKey(), + + wordwrap($migrationUpConfigurationComments, 60) + ]; } - $this->outputLine($createdMigration); - $this->outputLine('Your node migration has been created successfully.'); + + $this->outputLine('Available migrations'); + $this->outputLine(); + $this->output->outputTable($tableRows, ['Version', 'Date', 'Package', 'Comments']); } /** diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/NodeTypesCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/NodeTypesCommandController.php index 6901a5c6132..faf64e498b4 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/NodeTypesCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/NodeTypesCommandController.php @@ -39,11 +39,12 @@ public function showCommand(string $nodeTypeName, ?string $path = null, string $ $contentRepositoryId = ContentRepositoryId::fromString($contentRepository); $nodeTypeManager = $this->contentRepositoryRegistry->get($contentRepositoryId)->getNodeTypeManager(); - $nodeType = $nodeTypeManager->getNodeType($nodeTypeName); - if (!$nodeType) { + if (!$nodeTypeManager->hasNodeType($nodeTypeName)) { $this->outputLine('NodeType "%s" was not found!', [$nodeTypeName]); $this->quit(); } + + $nodeType = $nodeTypeManager->getNodeType($nodeTypeName); $yaml = Yaml::dump( $path ? $nodeType->getConfiguration($path) @@ -71,7 +72,7 @@ public function listCommand(?string $filter = null, bool $includeAbstract = true $nodeTypesFound = 0; $nodeTypeNameSpacesWithNodeTypeNames = []; foreach ($nodeTypeManager->getNodeTypes($includeAbstract) as $nodeType) { - $nodeTypeName = $nodeType->getName(); + $nodeTypeName = $nodeType->name->value; if (!$filter || str_contains($nodeTypeName, $filter)) { [$nameSpace] = explode(":", $nodeTypeName, 2); $nodeTypeNameSpacesWithNodeTypeNames[$nameSpace][] = $nodeTypeName; diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/StructureAdjustmentsCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/StructureAdjustmentsCommandController.php index c99472ac8c2..401b5cd830e 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/StructureAdjustmentsCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/StructureAdjustmentsCommandController.php @@ -29,6 +29,13 @@ final class StructureAdjustmentsCommandController extends CommandController */ protected $contentRepositoryRegistry; + + /** + * Detect required structure adjustments for the specified node type in the given content repository. + * + * @param string|null $nodeType The node type to find structure adjustments for. If not provided, all adjustments will be shown. (Default: null) + * @param string $contentRepositoryIdentifier The content repository identifier. (Default: 'default') + */ public function detectCommand(string $nodeType = null, string $contentRepositoryIdentifier = 'default'): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier); @@ -45,6 +52,13 @@ public function detectCommand(string $nodeType = null, string $contentRepository $this->printErrors($errors); } + /** + * Apply required structure adjustments for the specified node type in the given content repository. + * + * @param string|null $nodeType The node type to apply structure adjustments for. If not provided, all found adjustments will be applied. (Default: null) + * @param string $contentRepositoryIdentifier The content repository identifier. (Default: 'default') + * @return void + */ public function fixCommand(string $nodeType = null, string $contentRepositoryIdentifier = 'default'): void { $contentRepositoryId = ContentRepositoryId::fromString($contentRepositoryIdentifier); diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php index b0ec9ee2d39..a654d053fcc 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/SubprocessProjectionCatchUpCommandController.php @@ -22,6 +22,11 @@ class SubprocessProjectionCatchUpCommandController extends CommandController */ protected $contentRepositoryRegistry; + /** + * @param string $contentRepositoryIdentifier + * @param string $projectionClassName fully qualified class name of the projection to catch up + * @internal + */ public function catchupCommand(string $contentRepositoryIdentifier, string $projectionClassName): void { diff --git a/Neos.ContentRepositoryRegistry/Classes/Configuration/NodeTypeEnrichmentService.php b/Neos.ContentRepositoryRegistry/Classes/Configuration/NodeTypeEnrichmentService.php index 5c09351afb2..57621fc6f9c 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Configuration/NodeTypeEnrichmentService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Configuration/NodeTypeEnrichmentService.php @@ -178,8 +178,7 @@ protected function applyEditorLabels( $editorName, array &$editorOptions, $translationIdGenerator - ) - { + ) { switch ($editorName) { case 'Neos.Neos/Inspector/Editors/SelectBoxEditor': if ($this->shouldFetchTranslation($editorOptions, 'placeholder')) { diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/EventStore/DoctrineEventStoreFactory.php b/Neos.ContentRepositoryRegistry/Classes/Factory/EventStore/DoctrineEventStoreFactory.php index 6dbafd9d2b4..e74bfb15368 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/EventStore/DoctrineEventStoreFactory.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/EventStore/DoctrineEventStoreFactory.php @@ -13,8 +13,7 @@ class DoctrineEventStoreFactory implements EventStoreFactoryInterface { public function __construct( private readonly Connection $connection, - ) - { + ) { } public function build(ContentRepositoryId $contentRepositoryId, array $options, ClockInterface $clock): EventStoreInterface diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php index 2e587e187e6..1486c4ef1ec 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php @@ -7,14 +7,13 @@ use Neos\ContentRepositoryRegistry\Configuration\NodeTypeEnrichmentService; use Neos\Flow\Configuration\ConfigurationManager; -class DefaultNodeTypeManagerFactory implements NodeTypeManagerFactoryInterface +readonly class DefaultNodeTypeManagerFactory implements NodeTypeManagerFactoryInterface { public function __construct( - private readonly ConfigurationManager $configurationManager, - private readonly ObjectManagerBasedNodeLabelGeneratorFactory $nodeLabelGeneratorFactory, - private readonly NodeTypeEnrichmentService $nodeTypeEnrichmentService, - ) - { + private ConfigurationManager $configurationManager, + private ObjectManagerBasedNodeLabelGeneratorFactory $nodeLabelGeneratorFactory, + private NodeTypeEnrichmentService $nodeTypeEnrichmentService, + ) { } public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager @@ -24,8 +23,7 @@ function () { $configuration = $this->configurationManager->getConfiguration('NodeTypes'); return $this->nodeTypeEnrichmentService->enrichNodeTypeLabelsConfiguration($configuration); }, - $this->nodeLabelGeneratorFactory, - $options['fallbackNodeTypeName'] ?? null, + $this->nodeLabelGeneratorFactory ); } } diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php index f735cc414ea..51be1a2631a 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/CatchUpTriggerWithSynchronousOption.php @@ -57,8 +57,7 @@ public static function synchronously(\Closure $fn): void public function __construct( private readonly ContentRepositoryId $contentRepositoryId, private readonly SubprocessProjectionCatchUpTrigger $inner - ) - { + ) { } public function triggerCatchUp(Projections $projections): void diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php index d99d4b9909f..0f63d7c06c9 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/ProjectionCatchUpTrigger/SubprocessProjectionCatchUpTrigger.php @@ -22,8 +22,7 @@ class SubprocessProjectionCatchUpTrigger implements ProjectionCatchUpTriggerInte public function __construct( private readonly ContentRepositoryId $contentRepositoryId - ) - { + ) { } public function triggerCatchUp(Projections $projections): void diff --git a/Neos.ContentRepositoryRegistry/Classes/Migration/Configuration/YamlConfiguration.php b/Neos.ContentRepositoryRegistry/Classes/Migration/Configuration/YamlConfiguration.php index 96d22fc31d2..eea8eb121f3 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Migration/Configuration/YamlConfiguration.php +++ b/Neos.ContentRepositoryRegistry/Classes/Migration/Configuration/YamlConfiguration.php @@ -45,7 +45,6 @@ protected function registerAvailableVersions() { $this->availableVersions = []; foreach ($this->packageManager->getAvailablePackages() as $package) { - $this->registerVersionInDirectory($package, 'TYPO3CR'); $this->registerVersionInDirectory($package, 'ContentRepository'); } ksort($this->availableVersions); diff --git a/Neos.ContentRepositoryRegistry/Classes/Migration/Factory/MigrationFactory.php b/Neos.ContentRepositoryRegistry/Classes/Migration/Factory/MigrationFactory.php index ad0489ce1ba..7040708b228 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Migration/Factory/MigrationFactory.php +++ b/Neos.ContentRepositoryRegistry/Classes/Migration/Factory/MigrationFactory.php @@ -1,4 +1,5 @@ migrationConfiguration->getMigrationVersion($version)); } + + public function getAvailableVersions(): array + { + return $this->migrationConfiguration->getAvailableVersions(); + } } diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/NodeMigrationGeneratorService.php b/Neos.ContentRepositoryRegistry/Classes/Service/NodeMigrationGeneratorService.php index 2313b585842..b96cb1a3226 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/NodeMigrationGeneratorService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/NodeMigrationGeneratorService.php @@ -1,4 +1,5 @@ isOpeningBracket()) { $lexer->consume(); diff --git a/Neos.Fusion.Afx/Classes/Parser/Expression/NodeList.php b/Neos.Fusion.Afx/Classes/Parser/Expression/AfxNodeList.php similarity index 94% rename from Neos.Fusion.Afx/Classes/Parser/Expression/NodeList.php rename to Neos.Fusion.Afx/Classes/Parser/Expression/AfxNodeList.php index a9374936e5e..b53c018feee 100644 --- a/Neos.Fusion.Afx/Classes/Parser/Expression/NodeList.php +++ b/Neos.Fusion.Afx/Classes/Parser/Expression/AfxNodeList.php @@ -16,11 +16,7 @@ use Neos\Fusion\Afx\Parser\AfxParserException; use Neos\Fusion\Afx\Parser\Lexer; -/** - * Class NodeList - * @package Neos\Fusion\Afx\Parser\Expression - */ -class NodeList +class AfxNodeList { /** * @param Lexer $lexer @@ -56,7 +52,7 @@ public static function parse(Lexer $lexer): array $lexer->rewind(); $contents[] = [ 'type' => 'node', - 'payload' => Node::parse($lexer) + 'payload' => AfxNode::parse($lexer) ]; $currentText = ''; continue; diff --git a/Neos.Fusion.Afx/Classes/Parser/Parser.php b/Neos.Fusion.Afx/Classes/Parser/Parser.php index ded207f58a6..afd06f038db 100644 --- a/Neos.Fusion.Afx/Classes/Parser/Parser.php +++ b/Neos.Fusion.Afx/Classes/Parser/Parser.php @@ -39,6 +39,6 @@ public function __construct($string) */ public function parse(): array { - return Expression\NodeList::parse($this->lexer); + return Expression\AfxNodeList::parse($this->lexer); } } diff --git a/Neos.Fusion.Afx/README.md b/Neos.Fusion.Afx/README.md index 16581d02069..8bfcadec7ea 100644 --- a/Neos.Fusion.Afx/README.md +++ b/Neos.Fusion.Afx/README.md @@ -354,10 +354,10 @@ Neos.Fusion:Join { ## Examples -### Rendering of Collections with `Neos.Fusion:Collection` +### Rendering of Collections with `Neos.Fusion:Loop` For rendering of lists or menus a presentational-component usually will recieve arrays of -preprocessed data as prop. To iterate over such an array the `Neos.Fusion:Collection` +preprocessed data as prop. To iterate over such an array the `Neos.Fusion:Loop` can be used in afx. ``` @@ -368,11 +368,11 @@ prototype(Vendor.Site:IterationExample) < prototype(Neos.Fusion:Component) { renderer = afx`
    - -
  • + +
  • -
    +
` } @@ -389,11 +389,11 @@ prototype(PackageFactory.AtomicFusion.AFX:SliderExample) < prototype(Packagefact images = ${[]} renderer = afx`
- + - +
` } diff --git a/Neos.Fusion/Classes/Core/FusionGlobals.php b/Neos.Fusion/Classes/Core/FusionGlobals.php index d9077a1809b..5e95c9a8cfb 100644 --- a/Neos.Fusion/Classes/Core/FusionGlobals.php +++ b/Neos.Fusion/Classes/Core/FusionGlobals.php @@ -4,8 +4,6 @@ namespace Neos\Fusion\Core; -use Neos\Utility\Arrays; - /** * Fusion allows to add variable to the context either via * \@context.foo = "bar" or by leveraging the php api {@see Runtime::pushContext()}. @@ -57,7 +55,7 @@ public function has(string $name): bool public function merge(FusionGlobals $other): self { return new self( - Arrays::arrayMergeRecursiveOverrule($this->value, $other->value) + [...$this->value, ...$other->value] ); } } diff --git a/Neos.Fusion/Classes/Core/FusionSourceCodeCollection.php b/Neos.Fusion/Classes/Core/FusionSourceCodeCollection.php index dd20062a890..f9774b78705 100644 --- a/Neos.Fusion/Classes/Core/FusionSourceCodeCollection.php +++ b/Neos.Fusion/Classes/Core/FusionSourceCodeCollection.php @@ -59,10 +59,12 @@ public function union(FusionSourceCodeCollection $other): self return new static(...$this->fusionCodeCollection, ...$other->fusionCodeCollection); } - /** @return \ArrayIterator|FusionSourceCode[] */ - public function getIterator(): \ArrayIterator + /** + * @return \Traversable + */ + public function getIterator(): \Traversable { - return new \ArrayIterator($this->fusionCodeCollection); + yield from $this->fusionCodeCollection; } public function count(): int diff --git a/Neos.Fusion/Classes/Core/Runtime.php b/Neos.Fusion/Classes/Core/Runtime.php index 320315f4f12..2db2acbe273 100644 --- a/Neos.Fusion/Classes/Core/Runtime.php +++ b/Neos.Fusion/Classes/Core/Runtime.php @@ -24,6 +24,7 @@ use Neos\Flow\Security\Exception as SecurityException; use Neos\Fusion\Core\Cache\RuntimeContentCache; use Neos\Fusion\Core\ExceptionHandlers\AbstractRenderingExceptionHandler; +use Neos\Fusion\Core\ExceptionHandlers\ThrowingHandler; use Neos\Fusion\Exception; use Neos\Fusion\Exception as Exceptions; use Neos\Fusion\Exception\RuntimeException; @@ -132,6 +133,9 @@ class Runtime */ protected $lastEvaluationStatus; + /** {@see Runtime::overrideExceptionHandler} */ + protected ?AbstractRenderingExceptionHandler $overriddenExceptionHandler = null; + /** * @internal use {@see RuntimeFactory} for instantiating. */ @@ -170,7 +174,7 @@ public function getControllerContext(): ControllerContext } if (!($request = $this->fusionGlobals->get('request')) instanceof ActionRequest) { - throw new \RuntimeException(sprintf('Expected Fusion variable "request" to be of type ActionRequest, got value of type "%s".', get_debug_type($request)), 1693558026485); + throw new Exception(sprintf('Expected Fusion variable "request" to be of type ActionRequest, got value of type "%s".', get_debug_type($request)), 1693558026485); } $uriBuilder = new UriBuilder(); @@ -247,7 +251,7 @@ public function pushContextArray(array $contextArray) public function pushContext($key, $context) { if ($this->fusionGlobals->has($key)) { - throw new RuntimeException(sprintf('Overriding Fusion global variable "%s" via @context is not allowed.', $key), 1694284229044); + throw new Exception(sprintf('Overriding Fusion global variable "%s" via @context is not allowed.', $key), 1694284229044); } $newContext = $this->currentContext; $newContext[$key] = $context; @@ -341,6 +345,11 @@ public function render($fusionPath) */ public function handleRenderingException(string $fusionPath, \Exception $exception, bool $useInnerExceptionHandler = false) { + if ($this->overriddenExceptionHandler) { + $this->overriddenExceptionHandler->setRuntime($this); + return $this->overriddenExceptionHandler->handleRenderingException($fusionPath, $exception); + } + $fusionConfiguration = $this->runtimeConfiguration->forPath($fusionPath); $useLocalExceptionHandler = isset($fusionConfiguration['__meta']['exceptionHandler']); @@ -616,7 +625,7 @@ protected function prepareContextForFusionObject(AbstractFusionObject $fusionObj $newContextArray ??= $this->currentContext; foreach ($fusionConfiguration['__meta']['context'] as $contextKey => $contextValue) { if ($this->fusionGlobals->has($contextKey)) { - throw new RuntimeException(sprintf('Overriding Fusion global variable "%s" via @context is not allowed.', $contextKey), 1694247627130); + throw new Exception(sprintf('Overriding Fusion global variable "%s" via @context is not allowed.', $contextKey), 1694247627130); } $newContextArray[$contextKey] = $this->evaluate($fusionPath . '/__meta/context/' . $contextKey, $fusionObject, self::BEHAVIOR_EXCEPTION); } @@ -918,6 +927,18 @@ protected function throwExceptionForUnrenderablePathIfNeeded($fusionPath, $fusio } } + /** + * Configures this runtime to override the default exception handler configured in the settings + * or via Fusion's \@exceptionHandler {@see AbstractRenderingExceptionHandler}. + * + * In combination with the throwing handler {@see ThrowingHandler} this can be used to rethrow all exceptions. + * This is helpfully for renderings in CLI context or testing. + */ + public function overrideExceptionHandler(AbstractRenderingExceptionHandler $exceptionHandler): void + { + $this->overriddenExceptionHandler = $exceptionHandler; + } + /** * @param boolean $debugMode * @return void diff --git a/Neos.Fusion/Classes/Core/RuntimeConfiguration.php b/Neos.Fusion/Classes/Core/RuntimeConfiguration.php index 0c0a9b3bfef..39bfcaaaeb5 100644 --- a/Neos.Fusion/Classes/Core/RuntimeConfiguration.php +++ b/Neos.Fusion/Classes/Core/RuntimeConfiguration.php @@ -64,6 +64,10 @@ public function forPath(string $fusionPath): array return $this->pathCache[$fusionPath]['c']; } + if ($fusionPath === '') { + throw new Exception('Fusion path cannot be empty.', 1695308681); + } + // Find longest prefix of path that already is in path cache $pathUntilNow = ''; $fusionPathLength = strlen($fusionPath); diff --git a/Neos.Fusion/Classes/Exception/RuntimeException.php b/Neos.Fusion/Classes/Exception/RuntimeException.php index cca947a8082..bb40a1589c8 100644 --- a/Neos.Fusion/Classes/Exception/RuntimeException.php +++ b/Neos.Fusion/Classes/Exception/RuntimeException.php @@ -17,21 +17,11 @@ */ class RuntimeException extends Exception { - /** - * @var string - */ - protected $fusionPath; + private string $fusionPath; - /** - * @param string $message - * @param int $code - * @param \Exception $previous - * @param null $fusionPath - */ - public function __construct($message = '', $code = 0, \Exception $previous = null, $fusionPath = null) + public function __construct(string $message, int $code, \Exception $previous, string $fusionPath) { parent::__construct($message, $code, $previous); - $this->fusionPath = $fusionPath; } diff --git a/Neos.Fusion/Classes/FusionObjects/AbstractCollectionImplementation.php b/Neos.Fusion/Classes/FusionObjects/AbstractCollectionImplementation.php deleted file mode 100644 index a8b46e46d30..00000000000 --- a/Neos.Fusion/Classes/FusionObjects/AbstractCollectionImplementation.php +++ /dev/null @@ -1,61 +0,0 @@ -fusionValue('collection'); - } - - /** - * @return array - */ - public function getItems() - { - return $this->getCollection(); - } - - /** - * Evaluate the collection nodes as concatenated string - * - * @return string - * @throws FusionException - */ - public function evaluate() - { - return implode('', parent::evaluate()); - } - - /** - * Evaluate the collection nodes as array - * - * @return array - * @throws FusionException - */ - public function evaluateAsArray() - { - return parent::evaluate(); - } -} diff --git a/Neos.Fusion/Classes/FusionObjects/ArrayImplementation.php b/Neos.Fusion/Classes/FusionObjects/ArrayImplementation.php deleted file mode 100644 index d69590469b2..00000000000 --- a/Neos.Fusion/Classes/FusionObjects/ArrayImplementation.php +++ /dev/null @@ -1,30 +0,0 @@ -getAllowEmpty(); - $attributes = []; - foreach (array_keys($this->properties) as $attributeName) { - if ($attributeName === '__meta' || in_array($attributeName, $this->ignoreProperties)) { - continue; - } - $attributes[$attributeName] = $this->fusionValue($attributeName); - } - return $this->renderAttributes($attributes, $allowEmpty); - } - - /** - * Whether empty attributes (HTML5 syntax) should be allowed - * - * @return boolean - */ - protected function getAllowEmpty() - { - $allowEmpty = $this->fusionValue('__meta/allowEmpty'); - if ($allowEmpty === null) { - return true; - } else { - return (boolean)$allowEmpty; - } - } -} diff --git a/Neos.Fusion/Classes/FusionObjects/CollectionImplementation.php b/Neos.Fusion/Classes/FusionObjects/CollectionImplementation.php deleted file mode 100644 index 7d932fb0b29..00000000000 --- a/Neos.Fusion/Classes/FusionObjects/CollectionImplementation.php +++ /dev/null @@ -1,43 +0,0 @@ -__toString(); + } elseif ($attributeValuePart instanceof \BackedEnum) { + $attributeValuePart = $attributeValuePart->value; } $joinedAttributeValue .= match (gettype($attributeValuePart)) { 'boolean', 'NULL' => '', @@ -50,6 +52,10 @@ protected function renderAttributes(iterable $attributes, bool $allowEmpty = tru }; } $attributeValue = trim($joinedAttributeValue); + } elseif ($attributeValue instanceof \Stringable) { + $attributeValue = $attributeValue->__toString(); + } elseif ($attributeValue instanceof \BackedEnum) { + $attributeValue = $attributeValue->value; } $encodedAttributeName = htmlspecialchars((string)$attributeName, ENT_COMPAT, 'UTF-8', false); if ($attributeValue === true || $attributeValue === '') { diff --git a/Neos.Fusion/Classes/ViewHelpers/FusionContextTrait.php b/Neos.Fusion/Classes/ViewHelpers/FusionContextTrait.php index 511868cc4af..29133108fb5 100644 --- a/Neos.Fusion/Classes/ViewHelpers/FusionContextTrait.php +++ b/Neos.Fusion/Classes/ViewHelpers/FusionContextTrait.php @@ -33,18 +33,19 @@ trait FusionContextTrait */ protected function getContextVariable($variableName) { - $value = null; - $view = $this->viewHelperVariableContainer->getView(); if ($view instanceof FusionAwareViewInterface) { $fusionObject = $view->getFusionObject(); $currentContext = $fusionObject->getRuntime()->getCurrentContext(); if (isset($currentContext[$variableName])) { - $value = $currentContext[$variableName]; + return $currentContext[$variableName]; + } + $fusionGlobals = $fusionObject->getRuntime()->fusionGlobals; + if ($fusionGlobals->has($variableName)) { + return $fusionGlobals->get($variableName); } } - - return $value; + return null; } /** diff --git a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Array.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/Array.fusion deleted file mode 100644 index 33dc0d6cefe..00000000000 --- a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Array.fusion +++ /dev/null @@ -1,5 +0,0 @@ -# deprecated since Neos 4.2 in favor of Neos.Fusion:Join -prototype(Neos.Fusion:Array) { - @class = 'Neos\\Fusion\\FusionObjects\\ArrayImplementation' - @sortProperties = true -} diff --git a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Attributes.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/Attributes.fusion deleted file mode 100644 index 93019acbaf0..00000000000 --- a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Attributes.fusion +++ /dev/null @@ -1,15 +0,0 @@ -# Renders attributes of a HTML tag -# -# Usage: -# attributes = Neos.Fusion:Attributes { -# foo = 'bar' -# class = Neos.Fusion:DataStructure { -# class1 = 'class1' -# class2 = 'class2' -# } -# } -# -# @deprecated since Neos 5.0 in favor of Neos.Fusion:Tag internal attributes handling when a datastructure is passed -prototype(Neos.Fusion:Attributes) { - @class = 'Neos\\Fusion\\FusionObjects\\AttributesImplementation' -} diff --git a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Collection.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/Collection.fusion deleted file mode 100644 index bc2d5d554b4..00000000000 --- a/Neos.Fusion/Resources/Private/Fusion/Deprecated/Collection.fusion +++ /dev/null @@ -1,7 +0,0 @@ -# @deprecated since Neos 4.2 in favor of Neos.Fusion:Loop -prototype(Neos.Fusion:Collection) { - @class = 'Neos\\Fusion\\FusionObjects\\CollectionImplementation' - itemName = 'item' - itemKey = 'itemKey' - iterationName = 'iterator' -} diff --git a/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawArray.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawArray.fusion deleted file mode 100644 index 568736ddcea..00000000000 --- a/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawArray.fusion +++ /dev/null @@ -1,5 +0,0 @@ -# @deprecated since Neos 4.2 in favor of Neos.Fusion:DataStructure -prototype(Neos.Fusion:RawArray) { - @class = 'Neos\\Fusion\\FusionObjects\\RawArrayImplementation' - @sortProperties = true -} diff --git a/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawCollection.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawCollection.fusion deleted file mode 100644 index d87b279bb6c..00000000000 --- a/Neos.Fusion/Resources/Private/Fusion/Deprecated/RawCollection.fusion +++ /dev/null @@ -1,7 +0,0 @@ -# @deprecated since Neos 4.2 in favor of Neos.Fusion:Map -prototype(Neos.Fusion:RawCollection) { - @class = 'Neos\\Fusion\\FusionObjects\\RawCollectionImplementation' - itemName = 'item' - itemKey = 'itemKey' - iterationName = 'iterator' -} diff --git a/Neos.Fusion/Resources/Private/Fusion/Prototypes/UriBuilder.fusion b/Neos.Fusion/Resources/Private/Fusion/Deprecated/UriBuilder.fusion similarity index 100% rename from Neos.Fusion/Resources/Private/Fusion/Prototypes/UriBuilder.fusion rename to Neos.Fusion/Resources/Private/Fusion/Deprecated/UriBuilder.fusion diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/CollectionTest.php b/Neos.Fusion/Tests/Functional/FusionObjects/CollectionTest.php deleted file mode 100644 index 946b37c8a7b..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/CollectionTest.php +++ /dev/null @@ -1,64 +0,0 @@ -buildView(); - $view->assign('collection', ['element1', 'element2']); - $view->setFusionPath('collection/basicLoop'); - self::assertEquals('Xelement1Xelement2', $view->render()); - } - - /** - * @test - */ - public function basicCollectionWorksAndStillContainsOtherContextVariables() - { - $view = $this->buildView(); - $view->assign('collection', ['element1', 'element2']); - $view->assign('other', 'var'); - $view->setFusionPath('collection/basicLoopOtherContextVariables'); - self::assertEquals('Xelement1varXelement2var', $view->render()); - } - - /** - * @test - */ - public function emptyCollectionReturnsEmptyString() - { - $view = $this->buildView(); - $view->assign('collection', null); - $view->setFusionPath('collection/basicLoop'); - self::assertEquals('', $view->render()); - } - - /** - * @test - */ - public function iterationInformationIsAddedToCollection() - { - $view = $this->buildView(); - $view->assign('collection', ['element1', 'element2', 'element3', 'element4']); - $view->setFusionPath('collection/iteration'); - self::assertEquals('Xelement1-0-1-1--1-Xelement2-1-2----1Xelement3-2-3---1-Xelement4-3-4--1--1', $view->render()); - } -} diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/ConditionsTest.php b/Neos.Fusion/Tests/Functional/FusionObjects/ConditionsTest.php index c596b3a463d..64082cb3fe1 100644 --- a/Neos.Fusion/Tests/Functional/FusionObjects/ConditionsTest.php +++ b/Neos.Fusion/Tests/Functional/FusionObjects/ConditionsTest.php @@ -30,7 +30,6 @@ public function conditionExamples() ['conditions/objectAtLeastOneFalse', null], ['conditions/objectThis', null], ['conditions/dataStructure', ['key' => 'foo', 'nullValue' => null]], - ['conditions/attributes', ' key="foo"'], ['conditions/supportForConditionInProcess', 'wrappedValue'], ['conditions/supportForConditionInProcessFalse', 'originalValue'], ['conditions/supportForConditionInProcessWithAdvancedProcess', 'wrappedValue'], diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Collection.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Collection.fusion deleted file mode 100644 index 1b60c4b562f..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Collection.fusion +++ /dev/null @@ -1,27 +0,0 @@ -prototype(Neos.Fusion:Collection).@class = 'Neos\\Fusion\\FusionObjects\\CollectionImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - -collection.basicLoop = Neos.Fusion:Collection { - collection = ${collection} - itemName = 'element' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element} - } -} - -collection.basicLoopOtherContextVariables = Neos.Fusion:Collection { - collection = ${collection} - itemName = 'element' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element + other} - } -} - -collection.iteration = Neos.Fusion:Collection { - collection = ${collection} - itemName = 'element' - iterationName = 'iteration' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element + '-' + iteration.index + '-' + iteration.cycle + '-' + iteration.isFirst + '-' + iteration.isLast + '-' + iteration.isOdd + '-' + iteration.isEven} - } -} diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Conditions.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Conditions.fusion index 97b4d0c2051..1eca7ee64bf 100644 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Conditions.fusion +++ b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Conditions.fusion @@ -49,12 +49,6 @@ conditions.dataStructure = Neos.Fusion:DataStructure { keyNotSet.@if.cond = false } -conditions.attributes = Neos.Fusion:Attributes { - key = 'foo' - keyNotSet = 'bar' - keyNotSet.@if.cond = false -} - conditions.supportForConditionInProcess = Neos.Fusion:Value { value = 'originalValue' @process.wrap { @@ -92,7 +86,7 @@ conditions.supportForConditionInProcessWithAdvancedProcessFalse = Neos.Fusion:Va conditions.supportForFusionObjectWithSubEvaluationUsedInProcessor = Neos.Fusion:Value { value = 'basic' - theArray = Neos.Fusion:Array { + theArray = Neos.Fusion:Join { something = ' appended' another = Neos.Fusion:Value { value = ' more' diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/FusionArray.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/FusionArray.fusion deleted file mode 100644 index f21a801b933..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/FusionArray.fusion +++ /dev/null @@ -1,88 +0,0 @@ -prototype(Neos.Fusion:Array).@class = 'Neos\\Fusion\\FusionObjects\\ArrayImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - -array.basicOrdering = Neos.Fusion:Array { - 100 = Neos.Fusion:TestRenderer - 100.test = 'test100' - - 10 = Neos.Fusion:TestRenderer - 10.test = 'test10' -} - -array.positionalOrdering = Neos.Fusion:Array { - c = Neos.Fusion:TestRenderer - c.test = 'before' - c.@position = '10' - - a = Neos.Fusion:TestRenderer - a.test = 'after' - a.@position = '100' - - f = Neos.Fusion:TestRenderer - f.test = 'middle' - f.@position = '50' -} - -array.startEndOrdering = Neos.Fusion:Array { - a = Neos.Fusion:TestRenderer - a.test = 'after' - a.@position = 'end' - - c = Neos.Fusion:TestRenderer - c.test = 'before' - c.@position = 'start' - - f = Neos.Fusion:TestRenderer - f.test = 'middle' - f.@position = '50' -} - -# expected ordering: -# - e -# - d -# - foobar -# - f -# - g -# - 100 -# - b -# - a -# - c -array.advancedStartEndOrdering = Neos.Fusion:Array { - a = Neos.Fusion:TestRenderer - a.test = 'a' - a.@position = 'end 10' - - b = Neos.Fusion:TestRenderer - b.test = 'b' - b.@position = 'end' - - c = Neos.Fusion:TestRenderer - c.test = 'c' - c.@position = 'end 20' - - d = Neos.Fusion:TestRenderer - d.test = 'd' - d.@position = 'start' - - e = Neos.Fusion:TestRenderer - e.test = 'e' - e.@position = 'start 10' - - f = Neos.Fusion:TestRenderer - f.test = 'f' - f.@position = '50' - - 100 = Neos.Fusion:TestRenderer - 100.test = '100' - - foobar = Neos.Fusion:TestRenderer - foobar.test = 'foobar' - - g = Neos.Fusion:TestRenderer - g.test = 'g' - g.@position = '90' -} - -array.ignoreProperties < array.positionalOrdering { - @ignoreProperties = ${['f']} -} diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/NestedOverwritesAndProcessors.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/NestedOverwritesAndProcessors.fusion index 3374ef78a2a..4af508a7190 100644 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/NestedOverwritesAndProcessors.fusion +++ b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/NestedOverwritesAndProcessors.fusion @@ -1,7 +1,6 @@ prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' prototype(Neos.Fusion:Value).@class = 'Neos\\Fusion\\FusionObjects\\ValueImplementation' prototype(Neos.Fusion:DataStructure).@class = 'Neos\\Fusion\\FusionObjects\\DataStructureImplementation' -prototype(Neos.Fusion:Attributes).@class = 'Neos\\Fusion\\FusionObjects\\AttributesImplementation' prototype(Neos.Fusion:Tag) { # dummy declaration, will be overriden someplace - due to merged import of fixtures. @class = 'Neos\\Fusion\\FusionObjects\\TagImplementation' diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/RawCollection.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/RawCollection.fusion deleted file mode 100644 index 02343fd90b4..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/RawCollection.fusion +++ /dev/null @@ -1,27 +0,0 @@ -prototype(Neos.Fusion:RawCollection).@class = 'Neos\\Fusion\\FusionObjects\\RawCollectionImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - -rawCollection.basicLoop = Neos.Fusion:RawCollection { - collection = ${collection} - itemName = 'element' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element} - } -} - -rawCollection.basicLoopOtherContextVariables = Neos.Fusion:RawCollection { - collection = ${collection} - itemName = 'element' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element + other} - } -} - -rawCollection.iteration = Neos.Fusion:RawCollection { - collection = ${collection} - itemName = 'element' - iterationName = 'iteration' - itemRenderer = Neos.Fusion:TestRenderer { - test = ${element + '-' + iteration.index + '-' + iteration.cycle + '-' + iteration.isFirst + '-' + iteration.isLast + '-' + iteration.isOdd + '-' + iteration.isEven} - } -} diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Tag.fusion b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Tag.fusion index 589c8730216..78021e07fbc 100644 --- a/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Tag.fusion +++ b/Neos.Fusion/Tests/Functional/FusionObjects/Fixtures/Fusion/Tag.fusion @@ -1,5 +1,4 @@ prototype(Neos.Fusion:DataStructure).@class = 'Neos\\Fusion\\FusionObjects\\DataStructureImplementation' -prototype(Neos.Fusion:Attributes).@class = 'Neos\\Fusion\\FusionObjects\\AttributesImplementation' prototype(Neos.Fusion:DataStructure).@class = 'Neos\\Fusion\\FusionObjects\\DataStructureImplementation' prototype(Neos.Fusion:Tag) { @class = 'Neos\\Fusion\\FusionObjects\\TagImplementation' @@ -34,7 +33,7 @@ tag.arrayAttributes = Neos.Fusion:Tag { } tag.fusionAttributes = Neos.Fusion:Tag { - attributes = Neos.Fusion:Attributes { + attributes = Neos.Fusion:DataStructure { key = 'value' list = ${['foo', 'bar']} } diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/FusionArrayTest.php b/Neos.Fusion/Tests/Functional/FusionObjects/FusionArrayTest.php deleted file mode 100644 index e004fee24e4..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/FusionArrayTest.php +++ /dev/null @@ -1,74 +0,0 @@ -buildView(); - - $view->setFusionPath('array/basicOrdering'); - self::assertEquals('Xtest10Xtest100', $view->render()); - } - - /** - * @test - */ - public function positionalOrderingWorks() - { - $view = $this->buildView(); - - $view->setFusionPath('array/positionalOrdering'); - self::assertEquals('XbeforeXmiddleXafter', $view->render()); - } - - /** - * @test - */ - public function startEndOrderingWorks() - { - $view = $this->buildView(); - - $view->setFusionPath('array/startEndOrdering'); - self::assertEquals('XbeforeXmiddleXafter', $view->render()); - } - - /** - * @test - */ - public function advancedStartEndOrderingWorks() - { - $view = $this->buildView(); - - $view->setFusionPath('array/advancedStartEndOrdering'); - self::assertEquals('XeXdXfoobarXfXgX100XbXaXc', $view->render()); - } - - /** - * @test - */ - public function ignoredPropertiesWork() - { - $view = $this->buildView(); - - $view->setFusionPath('array/ignoreProperties'); - self::assertEquals('XbeforeXafter', $view->render()); - } -} diff --git a/Neos.Fusion/Tests/Functional/FusionObjects/RawCollectionTest.php b/Neos.Fusion/Tests/Functional/FusionObjects/RawCollectionTest.php deleted file mode 100644 index c5c1aec93b9..00000000000 --- a/Neos.Fusion/Tests/Functional/FusionObjects/RawCollectionTest.php +++ /dev/null @@ -1,65 +0,0 @@ -buildView(); - $view->assign('collection', ['element1', 'element2']); - $view->setFusionPath('rawCollection/basicLoop'); - self::assertEquals(['Xelement1','Xelement2'], $view->render()); - } - - - /** - * @test - */ - public function basicCollectionWorksAndStillContainsOtherContextVariables() - { - $view = $this->buildView(); - $view->assign('collection', ['element1', 'element2']); - $view->assign('other', 'var'); - $view->setFusionPath('rawCollection/basicLoopOtherContextVariables'); - self::assertEquals(['Xelement1var','Xelement2var'], $view->render()); - } - - /** - * @test - */ - public function emptyCollectionReturnsEmptyArray() - { - $view = $this->buildView(); - $view->assign('collection', null); - $view->setFusionPath('rawCollection/basicLoop'); - self::assertEquals([], $view->render()); - } - - /** - * @test - */ - public function iterationInformationIsAddedToCollection() - { - $view = $this->buildView(); - $view->assign('collection', ['element1', 'element2', 'element3', 'element4']); - $view->setFusionPath('rawCollection/iteration'); - self::assertEquals(['Xelement1-0-1-1--1-','Xelement2-1-2----1','Xelement3-2-3---1-','Xelement4-3-4--1--1'], $view->render()); - } -} diff --git a/Neos.Fusion/Tests/Unit/Core/FusionSourceCodeDtosTest.php b/Neos.Fusion/Tests/Unit/Core/FusionSourceCodeDtosTest.php index eca7003562d..0315f78055b 100644 --- a/Neos.Fusion/Tests/Unit/Core/FusionSourceCodeDtosTest.php +++ b/Neos.Fusion/Tests/Unit/Core/FusionSourceCodeDtosTest.php @@ -22,7 +22,7 @@ private static function getTheOnlyFusionCode(FusionSourceCodeCollection $collect { self::assertCount(1, $collection); /** @var FusionSourceCode[] $asArray */ - $asArray = $collection->getIterator()->getArrayCopy(); + $asArray = iterator_to_array($collection); return $asArray[0]; } @@ -108,7 +108,7 @@ public function deduplication() self::assertCount(2, $collection, "The deduplication didnt work."); - $asArray = $collection->getIterator()->getArrayCopy(); + $asArray = iterator_to_array($collection); self::assertEquals($code2, $asArray[0]); self::assertEquals($code1doubled, $asArray[1]); @@ -141,7 +141,7 @@ public function deduplication2() self::assertCount(4, $collection, "The deduplication didnt work."); - $asArray = $collection->getIterator()->getArrayCopy(); + $asArray = iterator_to_array($collection); self::assertEquals($code2, $asArray[0]); self::assertEquals($code3, $asArray[1]); @@ -174,7 +174,7 @@ public function deduplication4() self::assertCount(3, $collection, "The deduplication didnt work."); - $asArray = $collection->getIterator()->getArrayCopy(); + $asArray = iterator_to_array($collection); self::assertEquals($code2, $asArray[0]); self::assertEquals($code3, $asArray[1]); @@ -196,7 +196,7 @@ public function union() self::assertCount(2, $collection, "The union didnt work."); /** @var FusionSourceCode[] $asArray */ - $asArray = $collection->getIterator()->getArrayCopy(); + $asArray = iterator_to_array($collection); self::assertEquals("a", $asArray[0]->getSourceCode()); self::assertEquals("b", $asArray[1]->getSourceCode()); diff --git a/Neos.Fusion/Tests/Unit/Core/RuntimeTest.php b/Neos.Fusion/Tests/Unit/Core/RuntimeTest.php index e96a1fa8137..bc9920a0140 100644 --- a/Neos.Fusion/Tests/Unit/Core/RuntimeTest.php +++ b/Neos.Fusion/Tests/Unit/Core/RuntimeTest.php @@ -33,7 +33,7 @@ class RuntimeTest extends UnitTestCase */ public function renderHandlesExceptionDuringRendering() { - $runtimeException = new RuntimeException('I am a parent exception', 123, new Exception('I am a previous exception')); + $runtimeException = new RuntimeException('I am a parent exception', 123, new Exception('I am a previous exception'), 'root'); $runtime = $this->getMockBuilder(Runtime::class)->onlyMethods(['evaluate', 'handleRenderingException'])->disableOriginalConstructor()->getMock(); $runtime->expects(self::any())->method('evaluate')->will(self::throwException($runtimeException)); $runtime->expects(self::once())->method('handleRenderingException')->with('/foo/bar', $runtimeException)->will(self::returnValue('Exception Message')); @@ -54,7 +54,7 @@ public function handleRenderingExceptionThrowsException() { $this->expectException(Exception::class); $objectManager = $this->getMockBuilder(ObjectManager::class)->disableOriginalConstructor()->setMethods(['isRegistered', 'get'])->getMock(); - $runtimeException = new RuntimeException('I am a parent exception', 123, new Exception('I am a previous exception')); + $runtimeException = new RuntimeException('I am a parent exception', 123, new Exception('I am a previous exception'), 'root'); $runtime = new Runtime(FusionConfiguration::fromArray([]), FusionGlobals::empty()); $this->inject($runtime, 'objectManager', $objectManager); $exceptionHandlerSetting = 'settings'; @@ -177,7 +177,7 @@ public function runtimeCurrentContextStack3PushesAndPops() */ public function fusionContextIsNotAllowedToOverrideFusionGlobals() { - $this->expectException(\Neos\Fusion\Exception\RuntimeException::class); + $this->expectException(\Neos\Fusion\Exception::class); $this->expectExceptionMessage('Overriding Fusion global variable "request" via @context is not allowed.'); $runtime = new Runtime(FusionConfiguration::fromArray([ 'foo' => [ @@ -190,6 +190,7 @@ public function fusionContextIsNotAllowedToOverrideFusionGlobals() ] ] ]), FusionGlobals::fromArray(['request' => 'fixed'])); + $runtime->overrideExceptionHandler(new ThrowingHandler()); $runtime->evaluate('foo'); } @@ -199,7 +200,7 @@ public function fusionContextIsNotAllowedToOverrideFusionGlobals() */ public function pushContextIsNotAllowedToOverrideFusionGlobals() { - $this->expectException(\Neos\Fusion\Exception\RuntimeException::class); + $this->expectException(\Neos\Fusion\Exception::class); $this->expectExceptionMessage('Overriding Fusion global variable "request" via @context is not allowed.'); $runtime = new Runtime(FusionConfiguration::fromArray([]), FusionGlobals::fromArray(['request' => 'fixed'])); diff --git a/Neos.Fusion/Tests/Unit/FusionObjects/AttributesImplementationTest.php b/Neos.Fusion/Tests/Unit/FusionObjects/AttributesImplementationTest.php deleted file mode 100644 index 59a374b90a0..00000000000 --- a/Neos.Fusion/Tests/Unit/FusionObjects/AttributesImplementationTest.php +++ /dev/null @@ -1,73 +0,0 @@ -mockRuntime = $this->getMockBuilder(Runtime::class)->disableOriginalConstructor()->getMock(); - } - - public function attributeExamples() - { - return [ - 'null' => [null, ''], - 'empty array' => [[], ''], - 'boolean values' => [['booleanTrueAttribute' => true, 'booleanFalseAttribute' => false], ' booleanTrueAttribute'], - 'empty string value' => [['emptyStringAttribute' => ''], ' emptyStringAttribute'], - 'null value' => [['nullAttribute' => null], ''], - 'simple array' => [['attributeName1' => 'attributeValue1'], ' attributeName1="attributeValue1"'], - 'encoding' => [['spec 'chara>cters'], ' spec<ial="chara>cters"'], - 'array attributes' => [['class' => ['icon', null, 'icon-neos', '']], ' class="icon icon-neos"'], - 'empty attribute value without allowEmpty' => [['emptyStringAttribute' => '', '__meta' => ['allowEmpty' => false]], ' emptyStringAttribute=""'], - ]; - } - - /** - * @test - * @dataProvider attributeExamples - */ - public function evaluateTests($properties, $expectedOutput) - { - $path = 'attributes/test'; - $this->mockRuntime->expects(self::any())->method('evaluate')->will(self::returnCallback(function ($evaluatePath, $that) use ($path, $properties) { - $relativePath = str_replace($path . '/', '', $evaluatePath); - return ObjectAccess::getPropertyPath($properties, str_replace('/', '.', $relativePath)); - })); - - $fusionObjectName = 'Neos.Fusion:Attributes'; - $renderer = new AttributesImplementation($this->mockRuntime, $path, $fusionObjectName); - if ($properties !== null) { - foreach ($properties as $name => $value) { - ObjectAccess::setProperty($renderer, $name, $value); - } - } - - $result = $renderer->evaluate(); - self::assertEquals($expectedOutput, $result); - } -} diff --git a/Neos.Fusion/Tests/Unit/Service/HtmlAugmenterTest.php b/Neos.Fusion/Tests/Unit/Service/HtmlAugmenterTest.php index 820b2d7afe5..c2befa76c02 100644 --- a/Neos.Fusion/Tests/Unit/Service/HtmlAugmenterTest.php +++ b/Neos.Fusion/Tests/Unit/Service/HtmlAugmenterTest.php @@ -47,9 +47,14 @@ public function __toString() { return "casted value"; } } + enum BackedStringEnum: string { + case Example = "enum value"; + } '); + /** @noinspection PhpUndefinedClassInspection */ $mockObject = new \ClassWithToStringMethod(); + $mockEnum = \BackedStringEnum::Example; return [ // object values with __toString method @@ -61,7 +66,15 @@ public function __toString() { 'allowEmpty' => true, 'expectedResult' => '
' ], - + // object values with BackendEnum value + [ + 'html' => '', + 'attributes' => ['enum' => $mockEnum], + 'fallbackTagName' => null, + 'exclusiveAttributes' => null, + 'allowEmpty' => true, + 'expectedResult' => '
' + ], // empty source [ 'html' => '', @@ -344,6 +357,23 @@ public function __toString() { 'allowEmpty' => false, 'expectedResult' => '

Stringable attribute

', ], + // Adding of Enum attributes + [ + 'html' => '

Enum attribute

', + 'attributes' => ['data-enum' => $mockEnum], + 'fallbackTagName' => null, + 'exclusiveAttributes' => null, + 'allowEmpty' => true, + 'expectedResult' => '

Enum attribute

', + ], + [ + 'html' => '

Enum attribute

', + 'attributes' => ['data-enum' => $mockEnum], + 'fallbackTagName' => null, + 'exclusiveAttributes' => null, + 'allowEmpty' => false, + 'expectedResult' => '

Enum attribute

', + ], // Adding of array attributes [ 'html' => '

Array attribute

', diff --git a/Neos.Media.Browser/Classes/Controller/UsageController.php b/Neos.Media.Browser/Classes/Controller/UsageController.php index eb3dab88e26..6a1c6b924fe 100644 --- a/Neos.Media.Browser/Classes/Controller/UsageController.php +++ b/Neos.Media.Browser/Classes/Controller/UsageController.php @@ -12,20 +12,21 @@ * source code. */ +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\Eel\FlowQuery\FlowQuery; use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\Controller\ActionController; use Neos\Media\Domain\Model\AssetInterface; use Neos\Media\Domain\Service\AssetService; use Neos\Neos\Domain\Repository\SiteRepository; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; use Neos\Neos\Service\UserService; use Neos\Neos\Domain\Service\UserService as DomainUserService; use Neos\Neos\AssetUsage\Dto\AssetUsageReference; -use Neos\Neos\Domain\Service\SiteNodeUtility; use Neos\Neos\Domain\Model\Site; /** @@ -65,12 +66,6 @@ class UsageController extends ActionController */ protected $domainUserService; - /** - * @Flow\Inject - * @var SiteNodeUtility - */ - protected $siteNodeUtility; - /** * Get Related Nodes for an asset * @@ -126,28 +121,32 @@ public function relatedNodesAction(AssetInterface $asset) continue; } - $node = $contentRepository->getContentGraph()->findNodeByIdAndOriginDimensionSpacePoint( + $subgraph = $contentRepository->getContentGraph()->getSubgraph( $usage->getContentStreamId(), - $usage->getNodeAggregateId(), - $usage->getOriginDimensionSpacePoint() + $usage->getOriginDimensionSpacePoint()->toDimensionSpacePoint(), + VisibilityConstraints::withoutRestrictions() ); + $node = $subgraph->findNodeById($usage->getNodeAggregateId()); // this should actually never happen. if (!$node) { $inaccessibleRelations[] = $inaccessibleRelation; continue; } - $flowQuery = new FlowQuery([$node]); - $documentNode = $flowQuery->closest('[instanceof Neos.Neos:Document]')->get(0); + $documentNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); // this should actually never happen, too. if (!$documentNode) { $inaccessibleRelations[] = $inaccessibleRelation; continue; } - - $siteNode = $this->siteNodeUtility->findSiteNode($node); + $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE)); + // this should actually never happen, too. :D + if (!$siteNode) { + $inaccessibleRelations[] = $inaccessibleRelation; + continue; + } foreach ($existingSites as $existingSite) { /** @var Site $existingSite * */ if ($siteNode->nodeName->equals($existingSite->getNodeName()->toNodeName())) { diff --git a/Neos.Media.Browser/Configuration/Settings.yaml b/Neos.Media.Browser/Configuration/Settings.yaml index 1cac708bd5c..ec7c29899eb 100644 --- a/Neos.Media.Browser/Configuration/Settings.yaml +++ b/Neos.Media.Browser/Configuration/Settings.yaml @@ -16,7 +16,7 @@ Neos: - 'resource://Neos.Media.Browser/Public/Libraries/bootstrap/bootstrap-components.js' - 'resource://Neos.Media.Browser/Public/JavaScript/media-browser.js' styles: - - 'resource://Neos.Neos/Public/Styles/Neos.css' + - 'resource://Neos.Neos/Public/Styles/Main.css' - 'resource://Neos.Media.Browser/Public/Styles/MediaBrowser.css' - 'resource://Neos.Media.Browser/Public/Styles/Main.css' diff --git a/Neos.Media/Classes/Domain/Model/Thumbnail.php b/Neos.Media/Classes/Domain/Model/Thumbnail.php index bbc5ed5552c..56d3cf87c82 100644 --- a/Neos.Media/Classes/Domain/Model/Thumbnail.php +++ b/Neos.Media/Classes/Domain/Model/Thumbnail.php @@ -224,4 +224,9 @@ public function refresh() { $this->generatorStrategy->refresh($this); } + + public function getConfigurationHash(): string + { + return $this->configurationHash; + } } diff --git a/Neos.Media/Classes/Domain/Service/AssetSourceService.php b/Neos.Media/Classes/Domain/Service/AssetSourceService.php index 156b63d3e19..43766fe9e7a 100644 --- a/Neos.Media/Classes/Domain/Service/AssetSourceService.php +++ b/Neos.Media/Classes/Domain/Service/AssetSourceService.php @@ -175,7 +175,7 @@ private function initialize(): void if ($this->assetSources === []) { foreach ($this->assetSourcesConfiguration as $assetSourceIdentifier => $assetSourceConfiguration) { if (is_array($assetSourceConfiguration)) { - $this->assetSources[$assetSourceIdentifier] = new $assetSourceConfiguration['assetSource']($assetSourceIdentifier, $assetSourceConfiguration['assetSourceOptions'] ?? []); + $this->assetSources[$assetSourceIdentifier] = $assetSourceConfiguration['assetSource']::createFromConfiguration($assetSourceIdentifier, $assetSourceConfiguration['assetSourceOptions'] ?? []); } } } diff --git a/Neos.Media/Classes/Domain/Service/ThumbnailGenerator.php b/Neos.Media/Classes/Domain/Service/ThumbnailGenerator.php index bb817fa8a3e..b9ded1f0f43 100644 --- a/Neos.Media/Classes/Domain/Service/ThumbnailGenerator.php +++ b/Neos.Media/Classes/Domain/Service/ThumbnailGenerator.php @@ -48,8 +48,10 @@ public function createThumbnails(AssetInterface $image) { if ($this->autoCreateThumbnailPresets) { foreach ($this->thumbnailService->getPresets() as $preset => $presetConfiguration) { - $thumbnailConfiguration = $this->thumbnailService->getThumbnailConfigurationForPreset($preset, $this->asyncThumbnails); - $this->thumbnailService->getThumbnail($image, $thumbnailConfiguration); + if ($presetConfiguration) { + $thumbnailConfiguration = $this->thumbnailService->getThumbnailConfigurationForPreset($preset, $this->asyncThumbnails); + $this->thumbnailService->getThumbnail($image, $thumbnailConfiguration); + } } } } diff --git a/Neos.Media/Classes/Domain/Service/ThumbnailService.php b/Neos.Media/Classes/Domain/Service/ThumbnailService.php index 4efc5544fd4..32843c971c3 100644 --- a/Neos.Media/Classes/Domain/Service/ThumbnailService.php +++ b/Neos.Media/Classes/Domain/Service/ThumbnailService.php @@ -132,8 +132,16 @@ public function getThumbnail(AssetInterface $asset, ThumbnailConfiguration $conf if (isset($this->thumbnailCache[$assetIdentifier][$configurationHash])) { $thumbnail = $this->thumbnailCache[$assetIdentifier][$configurationHash]; } else { - $thumbnail = $this->thumbnailRepository->findOneByAssetAndThumbnailConfiguration($asset, $configuration); - $this->thumbnailCache[$assetIdentifier][$configurationHash] = $thumbnail; + $thumbnail = null; + // Load all thumbnails for the asset and cache them to prevent further db requests for the same asset + $thumbnailsForAsset = $this->thumbnailRepository->findByOriginalAsset($asset); + /** @var Thumbnail $thumbnailVariant */ + foreach ($thumbnailsForAsset as $thumbnailVariant) { + $this->thumbnailCache[$assetIdentifier][$thumbnailVariant->getConfigurationHash()] = $thumbnailVariant; + if ($thumbnailVariant->getConfigurationHash() === $configurationHash) { + $thumbnail = $thumbnailVariant; + } + } } $async = $configuration->isAsync(); if ($thumbnail === null) { diff --git a/Neos.Media/Documentation/.readthedocs.yaml b/Neos.Media/Documentation/.readthedocs.yaml new file mode 100644 index 00000000000..9bc45a5f025 --- /dev/null +++ b/Neos.Media/Documentation/.readthedocs.yaml @@ -0,0 +1,26 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-20.04 + tools: + python: "3.9" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: Neos.Media/Documentation/conf.py + +# If using Sphinx, optionally build your docs in additional formats such as PDF +formats: + - pdf + - epub + +# Optionally declare the Python requirements required to build your docs +python: + install: + - requirements: Neos.Media/Documentation/requirements.txt diff --git a/Neos.Media/Documentation/requirements.in b/Neos.Media/Documentation/requirements.in new file mode 100644 index 00000000000..52096927cfe --- /dev/null +++ b/Neos.Media/Documentation/requirements.in @@ -0,0 +1,2 @@ +sphinx==7.2.6 +sphinx_rtd_theme==1.3.0 diff --git a/Neos.Media/Documentation/requirements.txt b/Neos.Media/Documentation/requirements.txt index 6b3439d4217..12e992402fd 100644 --- a/Neos.Media/Documentation/requirements.txt +++ b/Neos.Media/Documentation/requirements.txt @@ -1,2 +1,62 @@ -sphinx==3.2.1 -sphinx_rtd_theme==1.0.0 +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile requirements.in +# +alabaster==0.7.13 + # via sphinx +babel==2.13.0 + # via sphinx +certifi==2023.7.22 + # via requests +charset-normalizer==3.3.0 + # via requests +docutils==0.18.1 + # via + # sphinx + # sphinx-rtd-theme +idna==3.4 + # via requests +imagesize==1.4.1 + # via sphinx +jinja2==3.1.2 + # via sphinx +markupsafe==2.1.3 + # via jinja2 +packaging==23.2 + # via sphinx +pygments==2.16.1 + # via sphinx +requests==2.31.0 + # via sphinx +snowballstemmer==2.2.0 + # via sphinx +sphinx==7.2.6 + # via + # -r requirements.in + # sphinx-rtd-theme + # sphinxcontrib-applehelp + # sphinxcontrib-devhelp + # sphinxcontrib-htmlhelp + # sphinxcontrib-jquery + # sphinxcontrib-qthelp + # sphinxcontrib-serializinghtml +sphinx-rtd-theme==1.3.0 + # via -r requirements.in +sphinxcontrib-applehelp==1.0.7 + # via sphinx +sphinxcontrib-devhelp==1.0.5 + # via sphinx +sphinxcontrib-htmlhelp==2.0.4 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.6 + # via sphinx +sphinxcontrib-serializinghtml==1.1.9 + # via sphinx +urllib3==2.0.6 + # via requests diff --git a/Neos.Neos/.gitignore b/Neos.Neos/.gitignore index c9d479ed176..49154ea5679 100644 --- a/Neos.Neos/.gitignore +++ b/Neos.Neos/.gitignore @@ -3,7 +3,6 @@ /Tests/Behavior/behat.yml /Resources/Public/Styles/Error.css /Resources/Public/Styles/Login.css -/Resources/Public/Styles/Neos.css /Resources/Public/Styles/RawContentMode.css # diff --git a/Neos.Neos/Classes/AssetUsage/Dto/AssetIdsByProperty.php b/Neos.Neos/Classes/AssetUsage/Dto/AssetIdsByProperty.php index 54e5c517200..7b3673b3715 100644 --- a/Neos.Neos/Classes/AssetUsage/Dto/AssetIdsByProperty.php +++ b/Neos.Neos/Classes/AssetUsage/Dto/AssetIdsByProperty.php @@ -12,13 +12,13 @@ * @internal */ #[Flow\Proxy(false)] -final class AssetIdsByProperty implements \IteratorAggregate +final readonly class AssetIdsByProperty implements \IteratorAggregate { /** * @param array> $assetIds */ public function __construct( - private readonly array $assetIds, + private array $assetIds, ) { } @@ -30,8 +30,8 @@ public function propertyNames(): array return array_keys($this->assetIds); } - public function getIterator(): Traversable + public function getIterator(): \Traversable { - return new \ArrayIterator($this->assetIds); + yield from $this->assetIds; } } diff --git a/Neos.Neos/Classes/AssetUsage/Dto/NodeAddress.php b/Neos.Neos/Classes/AssetUsage/Dto/AssetUsageNodeAddress.php similarity index 54% rename from Neos.Neos/Classes/AssetUsage/Dto/NodeAddress.php rename to Neos.Neos/Classes/AssetUsage/Dto/AssetUsageNodeAddress.php index 84d8c88d634..05326982575 100644 --- a/Neos.Neos/Classes/AssetUsage/Dto/NodeAddress.php +++ b/Neos.Neos/Classes/AssetUsage/Dto/AssetUsageNodeAddress.php @@ -10,30 +10,20 @@ use Neos\Flow\Annotations as Flow; /** - * Is used to address a node within the AssetUsage package + * Addresses a node within the AssetUsage package + * + * We don't use the official NodeAddress here {@see \Neos\Neos\FrontendRouting\NodeAddress}, + * As we don't need the workspaceName information, and just a simple pointer to a node. * * @internal */ #[Flow\Proxy(false)] -final class NodeAddress +final class AssetUsageNodeAddress { - /** - * @internal use NodeAddressFactory, if you want to create a NodeAddress - */ public function __construct( public readonly ContentStreamId $contentStreamId, public readonly DimensionSpacePoint $dimensionSpacePoint, public readonly NodeAggregateId $nodeAggregateId, ) { } - - public function __toString(): string - { - return sprintf( - 'NodeAddress[contentStream=%s, dimensionSpacePoint=%s, nodeAggregateId=%s]', - $this->contentStreamId->value, - $this->dimensionSpacePoint->toJson(), - $this->nodeAggregateId->value - ); - } } diff --git a/Neos.Neos/Classes/AssetUsage/Dto/AssetUsagesByContentRepository.php b/Neos.Neos/Classes/AssetUsage/Dto/AssetUsagesByContentRepository.php index 73b3b9036b0..6dd214783eb 100644 --- a/Neos.Neos/Classes/AssetUsage/Dto/AssetUsagesByContentRepository.php +++ b/Neos.Neos/Classes/AssetUsage/Dto/AssetUsagesByContentRepository.php @@ -11,19 +11,19 @@ * @api */ #[Flow\Proxy(false)] -final class AssetUsagesByContentRepository implements \IteratorAggregate, \Countable +final readonly class AssetUsagesByContentRepository implements \IteratorAggregate, \Countable { /** * @param array $assetUsages */ public function __construct( - private readonly array $assetUsages, + private array $assetUsages, ) { } public function getIterator(): \Traversable { - return new \ArrayIterator($this->assetUsages); + yield from $this->assetUsages; } /** diff --git a/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageProjection.php b/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageProjection.php index 23cd1633e55..d3b25a3e10f 100644 --- a/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageProjection.php +++ b/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageProjection.php @@ -31,7 +31,7 @@ use Neos\Media\Domain\Repository\AssetRepository; use Neos\Neos\AssetUsage\Dto\AssetIdAndOriginalAssetId; use Neos\Neos\AssetUsage\Dto\AssetIdsByProperty; -use Neos\Neos\AssetUsage\Dto\NodeAddress; +use Neos\Neos\AssetUsage\Dto\AssetUsageNodeAddress; use Neos\Utility\Exception\InvalidTypeException; use Neos\Utility\TypeHandling; @@ -83,7 +83,7 @@ public function whenNodeAggregateWithNodeWasCreated(NodeAggregateWithNodeWasCrea $e ); } - $nodeAddress = new NodeAddress( + $nodeAddress = new AssetUsageNodeAddress( $event->getContentStreamId(), $event->getOriginDimensionSpacePoint()->toDimensionSpacePoint(), $event->getNodeAggregateId() @@ -106,7 +106,7 @@ public function whenNodePropertiesWereSet(NodePropertiesWereSet $event, EventEnv $e ); } - $nodeAddress = new NodeAddress( + $nodeAddress = new AssetUsageNodeAddress( $event->getContentStreamId(), $event->getOriginDimensionSpacePoint()->toDimensionSpacePoint(), $event->getNodeAggregateId() diff --git a/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageRepository.php b/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageRepository.php index 82dfa20a222..7e5bf890b43 100644 --- a/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageRepository.php +++ b/Neos.Neos/Classes/AssetUsage/Projection/AssetUsageRepository.php @@ -12,7 +12,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\Neos\AssetUsage\Dto\NodeAddress; +use Neos\Neos\AssetUsage\Dto\AssetUsageNodeAddress; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\Neos\AssetUsage\Dto\AssetIdsByProperty; use Neos\Neos\AssetUsage\Dto\AssetUsage; @@ -152,7 +152,7 @@ public function findUsages(AssetUsageFilter $filter): AssetUsages }); } - public function addUsagesForNode(NodeAddress $nodeAddress, AssetIdsByProperty $assetIdsByProperty): void + public function addUsagesForNode(AssetUsageNodeAddress $nodeAddress, AssetIdsByProperty $assetIdsByProperty): void { // Delete all asset usage entries for newly set properties to ensure that removed or replaced assets are reflected $this->dbal->executeStatement('DELETE FROM ' . $this->tableNamePrefix diff --git a/Neos.Neos/Classes/Command/SiteCommandController.php b/Neos.Neos/Classes/Command/SiteCommandController.php index 733078f6d88..14354cd743b 100644 --- a/Neos.Neos/Classes/Command/SiteCommandController.php +++ b/Neos.Neos/Classes/Command/SiteCommandController.php @@ -95,7 +95,7 @@ public function createCommand($name, $packageKey, $nodeType, $nodeName = null, $ } catch (SiteNodeTypeIsInvalid $exception) { $this->outputLine( 'The given node type "%s" is not based on the superType "%s"', - [$nodeType, NodeTypeNameFactory::forSite()] + [$nodeType, NodeTypeNameFactory::NAME_SITE] ); $this->quit(1); } catch (SiteNodeNameIsAlreadyInUseByAnotherSite | NodeNameIsAlreadyOccupied $exception) { @@ -105,7 +105,7 @@ public function createCommand($name, $packageKey, $nodeType, $nodeName = null, $ $this->outputLine( 'Successfully created site "%s" with siteNode "%s", type "%s", packageKey "%s" and state "%s"', - [$name, $nodeName, $nodeType, $packageKey, $inactive ? 'offline' : 'online'] + [$name, $nodeName ?: $name, $nodeType, $packageKey, $inactive ? 'offline' : 'online'] ); } diff --git a/Neos.Neos/Classes/Command/WorkspaceCommandController.php b/Neos.Neos/Classes/Command/WorkspaceCommandController.php index d4756a51bd0..ea2685a2fdc 100644 --- a/Neos.Neos/Classes/Command/WorkspaceCommandController.php +++ b/Neos.Neos/Classes/Command/WorkspaceCommandController.php @@ -321,7 +321,7 @@ public function listCommand(string $contentRepositoryIdentifier = 'default'): vo $tableRows[] = [ $workspace->workspaceName->value, $workspace->baseWorkspaceName?->value ?: '', - $workspace->workspaceTitle?->value, + $workspace->workspaceTitle->value, $workspace->workspaceOwner ?: '', $workspace->workspaceDescription->value, $workspace->status->value, diff --git a/Neos.Neos/Classes/Controller/Backend/ContentController.php b/Neos.Neos/Classes/Controller/Backend/ContentController.php index 431ebe35270..9b89d665ac8 100644 --- a/Neos.Neos/Classes/Controller/Backend/ContentController.php +++ b/Neos.Neos/Classes/Controller/Backend/ContentController.php @@ -14,15 +14,12 @@ namespace Neos\Neos\Controller\Backend; -use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; -use Neos\Flow\I18n\EelHelper\TranslationHelper; use Neos\Flow\Mvc\Controller\ActionController; use Neos\Flow\Mvc\Exception\NoSuchArgumentException; use Neos\Flow\Persistence\Exception\IllegalObjectTypeException; @@ -45,6 +42,7 @@ use Neos\Neos\Controller\BackendUserTranslationTrait; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; use Neos\Neos\TypeConverter\EntityToIdentityConverter; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * The Neos ContentModule controller; providing backend functionality for the Content Module. @@ -54,6 +52,10 @@ class ContentController extends ActionController { use BackendUserTranslationTrait; + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; /** * @Flow\Inject @@ -103,9 +105,6 @@ class ContentController extends ActionController */ protected $propertyMapper; - #[Flow\Inject] - protected ContentRepositoryRegistry $contentRepositoryRegistry; - /** * Initialize property mapping as the upload usually comes from the Inspector JavaScript * @throws NoSuchArgumentException @@ -411,19 +410,6 @@ public function masterPluginsAction(string $workspaceName = 'live', array $dimen return json_encode((object)$masterPlugins, JSON_THROW_ON_ERROR); } - final protected function findClosestDocumentNode(Node $node): ?Node - { - while ($node instanceof Node) { - if ($node->nodeType->isOfType('Neos.Neos:Document')) { - return $node; - } - $node = $this->contentRepositoryRegistry->subgraphForNode($node) - ->findParentNode($node->nodeAggregateId); - } - - return null; - } - /** * Signals that a new asset has been uploaded through the Neos Backend * diff --git a/Neos.Neos/Classes/Controller/Backend/MenuHelper.php b/Neos.Neos/Classes/Controller/Backend/MenuHelper.php index 75ad026b9e1..5f9b0415c9c 100644 --- a/Neos.Neos/Classes/Controller/Backend/MenuHelper.php +++ b/Neos.Neos/Classes/Controller/Backend/MenuHelper.php @@ -12,23 +12,17 @@ * source code. */ -use Neos\ContentRepository\Security\Authorization\Privilege\Node\NodePrivilegeSubject; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Http\Exception; use Neos\Flow\Mvc\Controller\ControllerContext; use Neos\Flow\Mvc\Routing\Exception\MissingActionNameException; use Neos\Flow\Security\Authorization\PrivilegeManagerInterface; -use Neos\Neos\Domain\Service\ContentContextFactory; -use Neos\Neos\Domain\Service\SiteService; -use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; +use Neos\Neos\Domain\Model\Site; +use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Security\Authorization\Privilege\ModulePrivilege; use Neos\Neos\Security\Authorization\Privilege\ModulePrivilegeSubject; -use Neos\Neos\Security\Authorization\Privilege\NodeTreePrivilege; use Neos\Neos\Service\IconNameMappingService; use Neos\Utility\Arrays; -use Neos\Neos\Domain\Model\Site; -use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Utility\PositionalArraySorter; /** diff --git a/Neos.Neos/Classes/Controller/Frontend/NodeController.php b/Neos.Neos/Classes/Controller/Frontend/NodeController.php index d7ef5446465..8f8c450cef2 100644 --- a/Neos.Neos/Classes/Controller/Frontend/NodeController.php +++ b/Neos.Neos/Classes/Controller/Frontend/NodeController.php @@ -15,13 +15,11 @@ namespace Neos\Neos\Controller\Frontend; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\Projection\ContentGraph\AbsoluteNodePath; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphWithRuntimeCaches\ContentSubgraphWithRuntimeCaches; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphWithRuntimeCaches\InMemoryCache; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSubtreeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; @@ -37,6 +35,7 @@ use Neos\Flow\Utility\Now; use Neos\Neos\Domain\Model\RenderingMode; use Neos\Neos\Domain\Service\NodeSiteResolvingService; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\FrontendRouting\Exception\InvalidShortcutException; use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException; @@ -45,6 +44,7 @@ use Neos\Neos\FrontendRouting\NodeShortcutResolver; use Neos\Neos\FrontendRouting\NodeUriBuilder; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; use Neos\Neos\View\FusionView; /** @@ -52,11 +52,10 @@ */ class NodeController extends ActionController { - /** - * @Flow\Inject - * @var ContentRepositoryRegistry - */ - protected $contentRepositoryRegistry; + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; /** * @Flow\Inject @@ -165,7 +164,7 @@ public function previewAction(string $node): void ); } - if ($nodeInstance->nodeType->isOfType('Neos.Neos:Shortcut') && $nodeAddress->isInLiveWorkspace()) { + if ($this->getNodeType($nodeInstance)->isOfType(NodeTypeNameFactory::NAME_SHORTCUT) && $nodeAddress->isInLiveWorkspace()) { $this->handleShortcutNode($nodeAddress, $contentRepository); } @@ -182,10 +181,6 @@ public function previewAction(string $node): void if (!$this->view->canRenderWithNodeAndPath()) { $this->view->setFusionPath('rawContent'); } - - if ($this->session->isStarted()) { - $this->session->putData('lastVisitedNode', $nodeAddress); - } } } @@ -240,7 +235,7 @@ public function showAction(string $node, bool $showInvisible = false): void throw new NodeNotFoundException('The requested node does not exist', 1596191460); } - if ($nodeInstance->nodeType->isOfType('Neos.Neos:Shortcut')) { + if ($this->getNodeType($nodeInstance)->isOfType(NodeTypeNameFactory::NAME_SHORTCUT)) { $this->handleShortcutNode($nodeAddress, $contentRepository); } @@ -336,7 +331,7 @@ private function fillCacheWithContentNodes( $subtree = $subgraph->findSubtree( $nodeAggregateId, - FindSubtreeFilter::create(nodeTypeConstraints: '!Neos.Neos:Document', maximumLevels: 20) + FindSubtreeFilter::create(nodeTypeConstraints: '!' . NodeTypeNameFactory::NAME_DOCUMENT, maximumLevels: 20) ); if ($subtree === null) { return; diff --git a/Neos.Neos/Classes/Controller/LoginController.php b/Neos.Neos/Classes/Controller/LoginController.php index 7493b1b4510..c7601c8b540 100644 --- a/Neos.Neos/Classes/Controller/LoginController.php +++ b/Neos.Neos/Classes/Controller/LoginController.php @@ -31,7 +31,7 @@ use Neos\Flow\Session\SessionInterface; use Neos\Flow\Session\SessionManagerInterface; use Neos\Fusion\View\FusionView; -use Neos\Neos\Controller\Module\ModuleTranslationTrait; +use Neos\Neos\Controller\TranslationTrait; use Neos\Neos\Domain\Repository\DomainRepository; use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Service\BackendRedirectionService; @@ -41,42 +41,30 @@ */ class LoginController extends AbstractAuthenticationController { - use ModuleTranslationTrait; + use TranslationTrait; /** * @var string */ protected $defaultViewObjectName = FusionView::class; - /** - * @Flow\Inject - * @var SessionInterface - */ - protected $session; + #[Flow\Inject] + protected SessionInterface $session; - /** - * @Flow\Inject - * @var SessionManagerInterface - */ - protected $sessionManager; + #[Flow\Inject] + protected SessionManagerInterface $sessionManager; - /** - * @Flow\Inject - * @var BackendRedirectionService - */ - protected $backendRedirectionService; + #[Flow\Inject] + protected BackendRedirectionService $backendRedirectionService; - /** - * @Flow\Inject - * @var DomainRepository - */ - protected $domainRepository; + #[Flow\Inject] + protected DomainRepository $domainRepository; - /** - * @Flow\Inject - * @var SiteRepository - */ - protected $siteRepository; + #[Flow\Inject] + protected SiteRepository $siteRepository; + + #[Flow\Inject] + protected FlashMessageService $flashMessageService; /** * @Flow\Inject @@ -90,12 +78,6 @@ class LoginController extends AbstractAuthenticationController */ protected $sessionName; - /** - * @Flow\Inject - * @var FlashMessageService - */ - protected $flashMessageService; - /** * @var array */ @@ -127,7 +109,7 @@ public function initializeIndexAction(): void $this->request->setArgument( 'username', $authenticationArgument['Neos']['Flow']['Security']['Authentication'] - ['Token']['UsernamePassword']['username'] + ['Token']['UsernamePassword']['username'] ); } } @@ -191,9 +173,7 @@ public function tokenLoginAction(string $token): void if ($newSession->canBeResumed()) { $newSession->resume(); } - if ($newSession->isStarted()) { - $newSession->putData('lastVisitedNode', null); - } else { + if (!$newSession->isStarted()) { $this->logger->error(sprintf( 'Failed resuming or starting session %s which was referred to in the login token %s.', $newSessionId, @@ -211,14 +191,14 @@ public function tokenLoginAction(string $token): void * @param AuthenticationRequiredException $exception The exception thrown while the authentication process * @return void */ - protected function onAuthenticationFailure(AuthenticationRequiredException $exception = null) + protected function onAuthenticationFailure(AuthenticationRequiredException $exception = null): void { if ($this->view instanceof JsonView) { $this->view->assign('value', ['success' => false]); } else { $this->addFlashMessage( - $this->getModuleLabel('login.wrongCredentials.body'), - $this->getModuleLabel('login.wrongCredentials.title'), + $this->getLabel('login.wrongCredentials.body'), + $this->getLabel('login.wrongCredentials.title'), Message::SEVERITY_ERROR, [], $exception === null ? 1347016771 : $exception->getCode() @@ -237,7 +217,7 @@ protected function onAuthenticationFailure(AuthenticationRequiredException $exce * @throws StopActionException * @throws \Neos\Flow\Mvc\Exception\NoSuchArgumentException */ - protected function onAuthenticationSuccess(ActionRequest $originalRequest = null) + protected function onAuthenticationSuccess(ActionRequest $originalRequest = null): void { if ($this->view instanceof JsonView) { $this->view->assign( @@ -248,12 +228,6 @@ protected function onAuthenticationSuccess(ActionRequest $originalRequest = null ] ); } else { - if ( - $this->request->hasArgument('lastVisitedNode') - && $this->request->getArgument('lastVisitedNode') !== '' - ) { - $this->session->putData('lastVisitedNode', $this->request->getArgument('lastVisitedNode')); - } if ($originalRequest !== null) { // Redirect to the location that redirected to the login form because the user was nog logged in $this->redirectToRequest($originalRequest); @@ -272,21 +246,17 @@ protected function onAuthenticationSuccess(ActionRequest $originalRequest = null * * @return void */ - public function logoutAction() + public function logoutAction(): void { - $possibleRedirectionUri = $this->backendRedirectionService->getAfterLogoutRedirectionUri($this->request); parent::logoutAction(); switch ($this->request->getFormat()) { case 'json': $this->view->assign('value', ['success' => true]); break; default: - if ($possibleRedirectionUri !== null) { - $this->redirectToUri($possibleRedirectionUri); - } $this->addFlashMessage( - $this->getModuleLabel('login.loggedOut.body'), - $this->getModuleLabel('login.loggedOut.title'), + $this->getLabel('login.loggedOut.body'), + $this->getLabel('login.loggedOut.title'), Message::SEVERITY_NOTICE, [], 1318421560 @@ -302,7 +272,7 @@ public function logoutAction() * @phpstan-ignore-next-line Flow does not properly declare its types here * @return false */ - protected function getErrorFlashMessage() + protected function getErrorFlashMessage(): bool { return false; } diff --git a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php index 5cc1a00fb17..04fecdde89d 100755 --- a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php +++ b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php @@ -15,7 +15,6 @@ namespace Neos\Neos\Controller\Module\Administration; use Neos\ContentRepository\Core\Feature\NodeRenaming\Command\ChangeNodeAggregateName; -use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Exception\NodeNameIsAlreadyOccupied; @@ -186,7 +185,7 @@ public function updateSiteAction(Site $site, $newSiteNodeName) try { $sitesNode = $contentRepository->getContentGraph()->findRootNodeAggregateByType( $liveWorkspace->currentContentStreamId, - NodeTypeName::fromString('Neos.Neos:Sites') + NodeTypeNameFactory::forSites() ); } catch (\Exception $exception) { throw new \InvalidArgumentException( @@ -234,7 +233,7 @@ public function updateSiteAction(Site $site, $newSiteNodeName) [], 1412371798 ); - $this->unsetLastVisitedNodeAndRedirect('index'); + $this->redirect('index'); } /** @@ -253,7 +252,7 @@ public function newSiteAction(Site $site = null) $sitePackages = $this->packageManager->getFilteredPackages('available', 'neos-site'); - $documentNodeTypes = $contentRepository->getNodeTypeManager()->getSubNodeTypes('Neos.Neos:Document', false); + $documentNodeTypes = $contentRepository->getNodeTypeManager()->getSubNodeTypes(NodeTypeNameFactory::forDocument(), false); $generatorServiceIsAvailable = $this->packageManager->isPackageAvailable('Neos.SiteKickstarter'); $generatorServices = []; @@ -399,7 +398,7 @@ public function createSiteNodeAction($packageKey, $siteName, $nodeType) $this->addFlashMessage( $this->getModuleLabel( 'sites.siteCreationError.givenNodeTypeNotBasedOnSuperType.body', - [$nodeType, NodeTypeNameFactory::forSite()] + [$nodeType, NodeTypeNameFactory::NAME_SITE] ), $this->getModuleLabel('sites.siteCreationError.givenNodeTypeNotBasedOnSuperType.title'), Message::SEVERITY_ERROR, @@ -430,7 +429,7 @@ public function createSiteNodeAction($packageKey, $siteName, $nodeType) [], 1412372266 ); - $this->unsetLastVisitedNodeAndRedirect('index'); + $this->redirect('index'); } /** @@ -450,7 +449,7 @@ public function deleteSiteAction(Site $site) [], 1412372689 ); - $this->unsetLastVisitedNodeAndRedirect('index'); + $this->redirect('index'); } /** @@ -470,7 +469,7 @@ public function activateSiteAction(Site $site) [], 1412372881 ); - $this->unsetLastVisitedNodeAndRedirect('index'); + $this->redirect('index'); } /** @@ -490,7 +489,7 @@ public function deactivateSiteAction(Site $site) [], 1412372975 ); - $this->unsetLastVisitedNodeAndRedirect('index'); + $this->redirect('index'); } /** @@ -525,7 +524,7 @@ public function updateDomainAction(Domain $domain) [], 1412373069 ); - $this->unsetLastVisitedNodeAndRedirect('edit', null, null, ['site' => $domain->getSite()]); + $this->redirect('edit', null, null, ['site' => $domain->getSite()]); } /** @@ -562,7 +561,7 @@ public function createDomainAction(Domain $domain) [], 1412373192 ); - $this->unsetLastVisitedNodeAndRedirect('edit', null, null, ['site' => $domain->getSite()]); + $this->redirect('edit', null, null, ['site' => $domain->getSite()]); } /** @@ -587,7 +586,7 @@ public function deleteDomainAction(Domain $domain) [], 1412373310 ); - $this->unsetLastVisitedNodeAndRedirect('edit', null, null, ['site' => $site]); + $this->redirect('edit', null, null, ['site' => $site]); } /** @@ -608,7 +607,7 @@ public function activateDomainAction(Domain $domain) [], 1412373539 ); - $this->unsetLastVisitedNodeAndRedirect('edit', null, null, ['site' => $domain->getSite()]); + $this->redirect('edit', null, null, ['site' => $domain->getSite()]); } /** @@ -629,31 +628,6 @@ public function deactivateDomainAction(Domain $domain) [], 1412373425 ); - $this->unsetLastVisitedNodeAndRedirect('edit', null, null, ['site' => $domain->getSite()]); - } - - /** - * @param string $actionName Name of the action to forward to - * @param string $controllerName Unqualified object name of the controller to forward to. - * If not specified, the current controller is used. - * @param string $packageKey Key of the package containing the controller to forward to. - * If not specified, the current package is assumed. - * @param array $arguments Array of arguments for the target action - * @param integer $delay (optional) The delay in seconds. Default is no delay. - * @param integer $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other" - * @param string $format The format to use for the redirect URI - * @return void - */ - protected function unsetLastVisitedNodeAndRedirect( - $actionName, - $controllerName = null, - $packageKey = null, - array $arguments = [], - $delay = 0, - $statusCode = 303, - $format = null - ) { - $this->session->putData('lastVisitedNode', null); - parent::redirect($actionName, $controllerName, $packageKey, $arguments, $delay, $statusCode, $format); + $this->redirect('edit', null, null, ['site' => $domain->getSite()]); } } diff --git a/Neos.Neos/Classes/Controller/Module/Management/HistoryController.php b/Neos.Neos/Classes/Controller/Module/Management/HistoryController.php deleted file mode 100644 index b6fdedf6ec9..00000000000 --- a/Neos.Neos/Classes/Controller/Module/Management/HistoryController.php +++ /dev/null @@ -1,93 +0,0 @@ -eventRepository->findRelevantEventsByWorkspace($offset, $limit + 1, 'live')->toArray(); - - $nextPage = null; - if (count($events) > $limit) { - $events = array_slice($events, 0, $limit); - - $nextPage = $this - ->controllerContext - ->getUriBuilder() - ->setCreateAbsoluteUri(true) - ->uriFor('Index', ['offset' => $offset + $limit], 'History', 'Neos.Neos'); - } - - $eventsByDate = []; - foreach ($events as $event) { - /* @var $event Event */ - $day = $event->getTimestamp()->format('Y-m-d'); - if (!isset($eventsByDate[$day])) { - $eventsByDate[$day] = new EventsOnDate($event->getTimestamp()); - } - - /* @var $eventsOnThisDay EventsOnDate */ - $eventsOnThisDay = $eventsByDate[$day]; - $eventsOnThisDay->add($event); - } - - $this->view->assignMultiple([ - 'eventsByDate' => $eventsByDate, - 'nextPage' => $nextPage - ]); - } - - /** - * Simply sets the Fusion path pattern on the view. - * - * @param ViewInterface $view - * @return void - */ - protected function initializeView(ViewInterface $view) - { - parent::initializeView($view); - /** @var FusionView $view */ - $view->setFusionPathPattern('resource://Neos.Neos/Private/Fusion/Backend/History'); - } -} diff --git a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php index bf782bfc86f..26d7046e851 100644 --- a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php +++ b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php @@ -14,17 +14,20 @@ namespace Neos\Neos\Controller\Module\Management; +use Doctrine\DBAL\DBALException; +use JsonException; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\WorkspaceAlreadyExists; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; -use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTypeConstraints; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\I18n\Exception\IndexOutOfBoundsException; use Neos\Flow\I18n\Exception\InvalidFormatPlaceholderException; use Neos\Flow\Mvc\Exception\StopActionException; use Neos\Neos\Domain\Model\SiteNodeName; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\PendingChangesProjection\ChangeFinder; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; @@ -44,11 +47,9 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceTitle; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Diff\Diff; use Neos\Diff\Renderer\Html\HtmlArrayRenderer; use Neos\Neos\Controller\Module\ModuleTranslationTrait; -use Neos\Neos\Domain\Model\WorkspaceName as NeosWorkspaceName; use Neos\Flow\Annotations as Flow; use Neos\Error\Messages\Message; use Neos\Flow\Mvc\ActionRequest; @@ -62,6 +63,9 @@ use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\UserService; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; +use Neos\Neos\Domain\Service\WorkspaceNameBuilder; +use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; /** * The Neos Workspaces module controller @@ -71,42 +75,25 @@ class WorkspacesController extends AbstractModuleController { use ModuleTranslationTrait; + use NodeTypeWithFallbackProvider; - /** - * @Flow\Inject - * @var SiteRepository - */ - protected $siteRepository; + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; - /** - * @Flow\Inject - * @var PropertyMapper - */ - protected $propertyMapper; + #[Flow\Inject] + protected SiteRepository $siteRepository; - /** - * @Flow\Inject - * @var Context - */ - protected $securityContext; + #[Flow\Inject] + protected PropertyMapper $propertyMapper; - /** - * @Flow\Inject - * @var UserService - */ - protected $domainUserService; + #[Flow\Inject] + protected Context $securityContext; - /** - * @var PackageManager - * @Flow\Inject - */ - protected $packageManager; + #[Flow\Inject] + protected UserService $domainUserService; - /** - * @var ContentRepositoryRegistry - * @Flow\Inject - */ - protected $contentRepositoryRegistry; + #[Flow\Inject] + protected PackageManager $packageManager; /** * Display a list of unpublished content @@ -121,8 +108,7 @@ public function indexAction() $currentAccount = $this->securityContext->getAccount(); $userWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName( - NeosWorkspaceName::fromAccountIdentifier($currentAccount->getAccountIdentifier()) - ->toContentRepositoryWorkspaceName() + WorkspaceNameBuilder::fromAccountIdentifier($currentAccount->getAccountIdentifier()) ); if (is_null($userWorkspace)) { throw new \RuntimeException('Current user has no workspace', 1645485990); @@ -181,7 +167,7 @@ public function showAction(WorkspaceName $workspace): void } $this->view->assignMultiple([ 'selectedWorkspace' => $workspaceObj, - 'selectedWorkspaceLabel' => $workspaceObj->workspaceTitle ?: $workspaceObj->workspaceName, + 'selectedWorkspaceLabel' => $workspaceObj->workspaceTitle, 'baseWorkspaceName' => $workspaceObj->baseWorkspaceName, 'baseWorkspaceLabel' => $workspaceObj->baseWorkspaceName, // TODO fallback to title // TODO $this->domainUserService->currentUserCanPublishToWorkspace($workspace->getBaseWorkspace()), @@ -191,10 +177,7 @@ public function showAction(WorkspaceName $workspace): void ]); } - /** - * @return void - */ - public function newAction() + public function newAction(): void { $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; @@ -219,7 +202,7 @@ public function createAction( WorkspaceName $baseWorkspace, string $visibility, WorkspaceDescription $description, - ) { + ): void { $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); @@ -265,11 +248,8 @@ public function createAction( /** * Edit a workspace - * - * @param WorkspaceName $workspaceName - * @return void */ - public function editAction(WorkspaceName $workspaceName) + public function editAction(WorkspaceName $workspaceName): void { $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; @@ -302,8 +282,12 @@ public function editAction(WorkspaceName $workspaceName) * @param string $workspaceOwner Id of the owner of the workspace * @return void */ - public function updateAction(WorkspaceName $workspaceName, WorkspaceTitle $title, WorkspaceDescription $description, ?string $workspaceOwner) - { + public function updateAction( + WorkspaceName $workspaceName, + WorkspaceTitle $title, + WorkspaceDescription $description, + ?string $workspaceOwner + ): void { $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); @@ -323,7 +307,7 @@ public function updateAction(WorkspaceName $workspaceName, WorkspaceTitle $title return; } - if (!$workspace->workspaceTitle?->equals($title) || !$workspace->workspaceDescription->equals($description)) { + if (!$workspace->workspaceTitle->equals($title) || !$workspace->workspaceDescription->equals($description)) { $contentRepository->handle( RenameWorkspace::create( $workspaceName, @@ -357,9 +341,12 @@ public function updateAction(WorkspaceName $workspaceName, WorkspaceTitle $title * Delete a workspace * * @param WorkspaceName $workspaceName A workspace to delete - * @return void + * @throws IndexOutOfBoundsException + * @throws InvalidFormatPlaceholderException + * @throws StopActionException + * @throws DBALException */ - public function deleteAction(WorkspaceName $workspaceName) + public function deleteAction(WorkspaceName $workspaceName): void { $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; @@ -387,12 +374,12 @@ public function deleteAction(WorkspaceName $workspaceName) $dependentWorkspaceTitles = []; /** @var Workspace $dependentWorkspace */ foreach ($dependentWorkspaces as $dependentWorkspace) { - $dependentWorkspaceTitles[] = $dependentWorkspace->workspaceTitle?->value; + $dependentWorkspaceTitles[] = $dependentWorkspace->workspaceTitle->value; } $message = $this->translator->translateById( 'workspaces.workspaceCannotBeDeletedBecauseOfDependencies', - [$workspace->workspaceTitle?->value, implode(', ', $dependentWorkspaceTitles)], + [$workspace->workspaceTitle->value, implode(', ', $dependentWorkspaceTitles)], null, null, 'Modules', @@ -412,7 +399,7 @@ public function deleteAction(WorkspaceName $workspaceName) } catch (\Exception $exception) { $message = $this->translator->translateById( 'workspaces.notDeletedErrorWhileFetchingUnpublishedNodes', - [$workspace->workspaceTitle?->value], + [$workspace->workspaceTitle->value], null, null, 'Modules', @@ -424,7 +411,7 @@ public function deleteAction(WorkspaceName $workspaceName) if ($nodesCount > 0) { $message = $this->translator->translateById( 'workspaces.workspaceCannotBeDeletedBecauseOfUnpublishedNodes', - [$workspace->workspaceTitle?->value, $nodesCount], + [$workspace->workspaceTitle->value, $nodesCount], $nodesCount, null, 'Modules', @@ -442,7 +429,7 @@ public function deleteAction(WorkspaceName $workspaceName) $this->addFlashMessage($this->translator->translateById( 'workspaces.workspaceHasBeenRemoved', - [$workspace->workspaceTitle?->value], + [$workspace->workspaceTitle->value], null, null, 'Modules', @@ -462,8 +449,7 @@ public function rebaseAndRedirectAction(Node $targetNode, Workspace $targetWorks $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); $currentAccount = $this->securityContext->getAccount(); - $personalWorkspaceName = NeosWorkspaceName::fromAccountIdentifier($currentAccount->getAccountIdentifier()) - ->toContentRepositoryWorkspaceName(); + $personalWorkspaceName = WorkspaceNameBuilder::fromAccountIdentifier($currentAccount->getAccountIdentifier()); $personalWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName($personalWorkspaceName); /** @var Workspace $personalWorkspace */ @@ -591,17 +577,7 @@ public function discardNodeAction(string $nodeAddress, WorkspaceName $selectedWo } /** - * Publishes or discards the given nodes - * - * @param array $nodes - * @throws \Exception - * @throws \Neos\Flow\Property\Exception - * @throws \Neos\Flow\Security\Exception - */ - /** @phpstan-ignore-next-line - * @param array $nodes - * @param string $action - * @param string $selectedWorkspace + * @psalm-param list $nodes * @throws IndexOutOfBoundsException * @throws InvalidFormatPlaceholderException * @throws StopActionException @@ -726,6 +702,7 @@ public function discardWorkspaceAction(WorkspaceName $workspace): void * Computes the number of added, changed and removed nodes for the given workspace * * @return array + * @throws JsonException */ protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepository $contentRepository): array { @@ -751,11 +728,10 @@ protected function computeChangesCount(Workspace $selectedWorkspace, ContentRepo /** * Builds an array of changes for sites in the given workspace * @return array + * @throws JsonException */ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepository $contentRepository): array { - $nodeAddressFactory = NodeAddressFactory::create($contentRepository); - $siteChanges = []; $changes = $contentRepository->projectionState(ChangeFinder::class) ->findByContentStreamId( @@ -788,18 +764,25 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos $node->nodeAggregateId, FindAncestorNodesFilter::create() ); + $ancestors = Nodes::fromArray([$node])->merge($ancestors); + $nodePathSegments = []; $documentPathSegments = []; foreach ($ancestors as $ancestor) { $pathSegment = $ancestor->nodeName ?: NodeName::fromString($ancestor->nodeAggregateId->value); - $nodePathSegments[] = $pathSegment; - if ($ancestor->nodeType->isOfType('Neos.Neos:Document')) { + // Don't include `sites` path as they are not needed + // by the HTML/JS magic and won't be included as `$documentPathSegments` + if (!$this->getNodeType($ancestor)->isOfType(NodeTypeNameFactory::NAME_SITES)) { + $nodePathSegments[] = $pathSegment; + } + if ($this->getNodeType($ancestor)->isOfType(NodeTypeNameFactory::NAME_DOCUMENT)) { $documentPathSegments[] = $pathSegment; if (is_null($documentNode)) { $documentNode = $ancestor; } - // the site node is the last ancestor of type Document - $siteNode = $documentNode; + } + if ($this->getNodeType($ancestor)->isOfType(NodeTypeNameFactory::NAME_SITE)) { + $siteNode = $ancestor; } } @@ -807,37 +790,55 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos // We should probably throw an exception though if ($documentNode !== null && $siteNode !== null && $siteNode->nodeName) { $siteNodeName = $siteNode->nodeName->value; - $documentPath = implode('/', array_slice(array_map( + // Reverse `$documentPathSegments` to start with the site node. + // The paths are used for grouping the nodes and for selecting a tree of nodes. + $documentPath = implode('/', array_reverse(array_map( fn (NodeName $nodeName): string => $nodeName->value, $documentPathSegments - ), 2)); - $relativePath = str_replace( - sprintf('//%s/%s', $siteNodeName, $documentPath), - '', - implode('/', array_map( - fn (NodeName $nodeName): string => $nodeName->value, - $nodePathSegments - )) - ); + ))); + // Reverse `$nodePathSegments` to start with the site node. + // The paths are used for grouping the nodes and for selecting a tree of nodes. + $relativePath = implode('/', array_reverse(array_map( + fn (NodeName $nodeName): string => $nodeName->value, + $nodePathSegments + ))); if (!isset($siteChanges[$siteNodeName]['siteNode'])) { $siteChanges[$siteNodeName]['siteNode'] = $this->siteRepository->findOneByNodeName(SiteNodeName::fromString($siteNodeName)); } + $siteChanges[$siteNodeName]['documents'][$documentPath]['documentNode'] = $documentNode; + // We need to set `isNew` and `isMoved` on document level to make our JS behave as before. + if ($documentNode->equals($node)) { + $siteChanges[$siteNodeName]['documents'][$documentPath]['isNew'] = $change->created; + $siteChanges[$siteNodeName]['documents'][$documentPath]['isMoved'] = $change->moved; + } + + // As for changes of type `delete` we are using nodes from the live content stream + // we can't create `serializedNodeAddress` from the node. + // Instead, we use the original stored values. + $nodeAddress = new NodeAddress( + $change->contentStreamId, + $change->originDimensionSpacePoint->toDimensionSpacePoint(), + $change->nodeAggregateId, + $selectedWorkspace->workspaceName + ); $change = [ 'node' => $node, - 'serializedNodeAddress' => $nodeAddressFactory->createFromNode($node)->serializeForUri(), + 'serializedNodeAddress' => $nodeAddress->serializeForUri(), 'isRemoved' => $change->deleted, - 'isNew' => false, + 'isNew' => $change->created, + 'isMoved' => $change->moved, 'contentChanges' => $this->renderContentChanges( $node, $change->contentStreamId, $contentRepository ) ]; - if ($node->nodeType->isOfType('Neos.Neos:Node')) { - $change['configuration'] = $node->nodeType->getFullConfiguration(); + $nodeType = $this->getNodeType($node); + if ($nodeType->isOfType('Neos.Neos:Node')) { + $change['configuration'] = $nodeType->getFullConfiguration(); } $siteChanges[$siteNodeName]['documents'][$documentPath]['changes'][$relativePath] = $change; } @@ -846,19 +847,9 @@ protected function computeSiteChanges(Workspace $selectedWorkspace, ContentRepos ksort($siteChanges); foreach ($siteChanges as $siteKey => $site) { - /*foreach ($site['documents'] as $documentKey => $document) { - $liveDocumentNode = $liveContext->getNodeByIdentifier($document['documentNode']->getIdentifier()); - $siteChanges[$siteKey]['documents'][$documentKey]['isMoved'] - = $liveDocumentNode && $document['documentNode']->getPath() !== $liveDocumentNode->getPath(); - $siteChanges[$siteKey]['documents'][$documentKey]['isNew'] = $liveDocumentNode === null; - foreach ($document['changes'] as $changeKey => $change) { - $liveNode = $liveContext->getNodeByIdentifier($change['node']->getIdentifier()); - $siteChanges[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isNew'] - = is_null($liveNode); - $siteChanges[$siteKey]['documents'][$documentKey]['changes'][$changeKey]['isMoved'] - = $liveNode && $change['node']->getPath() !== $liveNode->getPath(); - } - }*/ + foreach ($site['documents'] as $documentKey => $document) { + ksort($siteChanges[$siteKey]['documents'][$documentKey]['changes']); + } ksort($siteChanges[$siteKey]['documents']); } return $siteChanges; @@ -907,7 +898,7 @@ protected function renderContentChanges( $contentChanges = []; - $changeNodePropertiesDefaults = $changedNode->nodeType->getDefaultValuesForProperties(); + $changeNodePropertiesDefaults = $this->getNodeType($changedNode)->getDefaultValuesForProperties(); $renderer = new HtmlArrayRenderer(); foreach ($changedNode->properties as $propertyName => $changedPropertyValue) { @@ -1024,7 +1015,7 @@ protected function renderSlimmedDownContent($propertyValue) */ protected function getPropertyLabel($propertyName, Node $changedNode) { - $properties = $changedNode->nodeType->getProperties(); + $properties = $this->getNodeType($changedNode)->getProperties(); if ( !isset($properties[$propertyName]) || !isset($properties[$propertyName]['ui']['label']) @@ -1090,7 +1081,7 @@ protected function prepareBaseWorkspaceOptions( || $this->domainUserService->currentUserCanManageWorkspace($workspace)) && (!$excludedWorkspace || $workspaces->getBaseWorkspaces($workspace->workspaceName)->get($excludedWorkspace->workspaceName) === null) ) { - $baseWorkspaceOptions[$workspace->workspaceName->value] = $workspace->workspaceTitle?->value; + $baseWorkspaceOptions[$workspace->workspaceName->value] = $workspace->workspaceTitle->value; } } diff --git a/Neos.Neos/Classes/Controller/Service/NodesController.php b/Neos.Neos/Classes/Controller/Service/NodesController.php index f9bfdf3f638..e649ffc87f3 100644 --- a/Neos.Neos/Classes/Controller/Service/NodesController.php +++ b/Neos.Neos/Classes/Controller/Service/NodesController.php @@ -29,6 +29,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\NodeType\NodeTypeConstraintParser; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTypeConstraints; @@ -114,7 +115,7 @@ public function indexAction( array|string $nodeIds = [], string $workspaceName = 'live', array $dimensions = [], - array $nodeTypes = ['Neos.Neos:Document'], + array $nodeTypes = [NodeTypeNameFactory::NAME_DOCUMENT], string $contextNode = null, array|string $nodeIdentifiers = [] ): void { @@ -435,7 +436,7 @@ protected function adoptNodeAndParents( )->block(); if ($copyContent === true) { - $contentNodeConstraint = NodeTypeConstraints::fromFilterString('!Neos.Neos:Document'); + $contentNodeConstraint = NodeTypeConstraints::fromFilterString('!' . NodeTypeNameFactory::NAME_DOCUMENT); $this->createNodeVariantsForChildNodes( $contentStreamId, $identifier, diff --git a/Neos.Neos/Classes/Controller/TranslationTrait.php b/Neos.Neos/Classes/Controller/TranslationTrait.php new file mode 100644 index 00000000000..d0b048ace0d --- /dev/null +++ b/Neos.Neos/Classes/Controller/TranslationTrait.php @@ -0,0 +1,42 @@ + $arguments + */ + public function getLabel(string $id, array $arguments = []): string + { + return $this->translator->translateById( + $id, + $arguments, + null, + null, + 'Main', + 'Neos.Neos' + ) ?: $id; + } +} diff --git a/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php b/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php deleted file mode 100644 index 17ee064d9c3..00000000000 --- a/Neos.Neos/Classes/Domain/Exception/CurrentUserIsMissing.php +++ /dev/null @@ -1,29 +0,0 @@ -value - . '" is not of required type "' . NodeTypeNameFactory::forSite()->value . '"', + . '" is not of required type "' . NodeTypeNameFactory::NAME_SITE . '"', 1412372375 ); } diff --git a/Neos.Neos/Classes/Domain/Exception/SitesNodeIsMissing.php b/Neos.Neos/Classes/Domain/Exception/SitesNodeIsMissing.php deleted file mode 100644 index ee2cea42256..00000000000 --- a/Neos.Neos/Classes/Domain/Exception/SitesNodeIsMissing.php +++ /dev/null @@ -1,30 +0,0 @@ -value . '" root node is missing.', - 1651956364 - ); - } -} diff --git a/Neos.Neos/Classes/Domain/Model/WorkspaceName.php b/Neos.Neos/Classes/Domain/Model/WorkspaceName.php deleted file mode 100644 index c59ba79951d..00000000000 --- a/Neos.Neos/Classes/Domain/Model/WorkspaceName.php +++ /dev/null @@ -1,81 +0,0 @@ -name = $name; - } - - public static function fromAccountIdentifier(string $accountIdentifier): self - { - $name = preg_replace('/[^A-Za-z0-9\-]/', '-', self::PREFIX . $accountIdentifier); - if (is_null($name)) { - throw new \InvalidArgumentException( - 'Cannot convert account identifier ' . $accountIdentifier . ' to workspace name.', - 1645656253 - ); - } - - return new self($name); - } - - /** - * @param array $takenWorkspaceNames - */ - public function increment(array $takenWorkspaceNames): self - { - $name = $this->name; - $i = 1; - while (array_key_exists($name, $takenWorkspaceNames)) { - $name = $this->name . self::SUFFIX_DELIMITER . $i; - $i++; - } - - if ($i > 1) { - return new WorkspaceName($name); - } else { - return $this; - } - } - - public function toContentRepositoryWorkspaceName(): ContentRepositoryWorkspaceName - { - return ContentRepositoryWorkspaceName::fromString($this->name); - } - - public function jsonSerialize(): string - { - return $this->name; - } - - public function __toString(): string - { - return $this->name; - } -} diff --git a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php index 815d9057028..d097041e88d 100644 --- a/Neos.Neos/Classes/Domain/Repository/SiteRepository.php +++ b/Neos.Neos/Classes/Domain/Repository/SiteRepository.php @@ -15,13 +15,17 @@ namespace Neos\Neos\Domain\Repository; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\QueryInterface; use Neos\Flow\Persistence\QueryResultInterface; use Neos\Flow\Persistence\Repository; -use Neos\Neos\Domain\Model\Site; use Neos\Neos\Domain\Exception as NeosException; +use Neos\Neos\Domain\Model\Site; use Neos\Neos\Domain\Model\SiteNodeName; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; +use Neos\Neos\Domain\Service\SiteNodeUtility; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * The Site Repository @@ -33,6 +37,11 @@ */ class SiteRepository extends Repository { + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** * @var array */ @@ -95,8 +104,26 @@ public function findOneByNodeName(string|SiteNodeName $nodeName): ?Site return $site; } + /** + * Finds a given site by site node. + * + * To find the correct site node by its descended child node leverage `findClosestNode`: + * ```php + * $siteNode = $subgraph->findClosestNode( + * $node->nodeAggregateId, + * FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE) + * ); + * ``` + * + * To resolve the SiteNode by a Site use {@see SiteNodeUtility::findSiteNodeBySite()} + * + * @throws \Neos\Neos\Domain\Exception in case the passed $siteNode is not a real site node or no site matches this site node. + */ public function findSiteBySiteNode(Node $siteNode): Site { + if (!$this->getNodeType($siteNode)->isOfType(NodeTypeNameFactory::NAME_SITE)) { + throw new \Neos\Neos\Domain\Exception(sprintf('Node %s is not a site node. Site nodes must be of type "%s".', $siteNode->nodeAggregateId->value, NodeTypeNameFactory::NAME_SITE), 1697108987); + } if ($siteNode->nodeName === null) { throw new \Neos\Neos\Domain\Exception(sprintf('Site node "%s" is unnamed', $siteNode->nodeAggregateId->value), 1681286146); } diff --git a/Neos.Neos/Classes/Domain/Service/FusionService.php b/Neos.Neos/Classes/Domain/Service/FusionService.php index 05db82195f5..86ca7bfdd52 100644 --- a/Neos.Neos/Classes/Domain/Service/FusionService.php +++ b/Neos.Neos/Classes/Domain/Service/FusionService.php @@ -14,84 +14,24 @@ * source code. */ -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\Flow\Mvc\Controller\ControllerContext; -use Neos\Fusion\Core\FusionConfiguration; use Neos\Flow\Annotations as Flow; -use Neos\Fusion\Core\FusionGlobals; -use Neos\Fusion\Core\FusionSourceCode; +use Neos\Fusion\Core\FusionConfiguration; use Neos\Fusion\Core\FusionSourceCodeCollection; use Neos\Fusion\Core\Parser; -use Neos\Fusion\Core\Runtime; -use Neos\Fusion\Core\RuntimeFactory; use Neos\Neos\Domain\Model\Site; -use Neos\Neos\Domain\Model\SiteNodeName; -use Neos\Neos\Domain\Repository\SiteRepository; /** - * @todo currently scope prototype will change with the removal of the internal state to singleton in Neos 9.0 - * - * @Flow\Scope("prototype") * @api */ +#[Flow\Scope('singleton')] class FusionService { - /** - * Pattern used for determining the Fusion root file for a site - * - * @deprecated with Neos 8.3, will be immutable with 9.0 - * @var string - */ - protected $siteRootFusionPattern = 'resource://%s/Private/Fusion/Root.fusion'; - - /** - * Array of Fusion files to include before the site Fusion - * - * Example: - * - * array( - * 'resources://MyVendor.MyPackageKey/Private/Fusion/Root.fusion', - * 'resources://SomeVendor.OtherPackage/Private/Fusion/Root.fusion' - * ) - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * @var array - */ - protected $prependFusionIncludes = []; - - /** - * Array of Fusion files to include after the site Fusion - * - * Example: - * - * array( - * 'resources://MyVendor.MyPackageKey/Private/Fusion/Root.fusion', - * 'resources://SomeVendor.OtherPackage/Private/Fusion/Root.fusion' - * ) - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * @var array - */ - protected $appendFusionIncludes = []; - - /** - * @Flow\Inject - * @var SiteRepository - */ - protected $siteRepository; - /** * @Flow\Inject * @var Parser */ protected $fusionParser; - /** - * @Flow\Inject - * @var RuntimeFactory - */ - protected $runtimeFactory; - /** * @Flow\Inject * @var FusionSourceCodeFactory @@ -109,156 +49,21 @@ public function createFusionConfigurationFromSite(Site $site): FusionConfigurati return $this->fusionConfigurationCache->cacheFusionConfigurationBySite($site, function () use ($site) { $siteResourcesPackageKey = $site->getSiteResourcesPackageKey(); - $siteRootFusionPathAndFilename = sprintf($this->siteRootFusionPattern, $siteResourcesPackageKey); - return $this->fusionParser->parseFromSource( $this->fusionSourceCodeFactory->createFromNodeTypeDefinitions($site->getConfiguration()->contentRepositoryId) ->union( $this->fusionSourceCodeFactory->createFromAutoIncludes() ) ->union( - $this->createSourceCodeFromLegacyFusionIncludes($this->prependFusionIncludes, $siteRootFusionPathAndFilename) - ) - ->union( - FusionSourceCodeCollection::tryFromFilePath($siteRootFusionPathAndFilename) - ) - ->union( - $this->createSourceCodeFromLegacyFusionIncludes($this->appendFusionIncludes, $siteRootFusionPathAndFilename) + FusionSourceCodeCollection::tryFromPackageRootFusion($siteResourcesPackageKey) ) ); }); } - /** - * Returns a merged Fusion object tree in the context of the given nodes - * - * @deprecated with Neos 8.3, will be removed with 9.0 {@link createFusionConfigurationFromSite} - * - * @param Node $startNode Node marking the starting point (i.e. the "Site" node) - * @return array The merged object tree as of the given node - */ - public function getMergedFusionObjectTree(Node $startNode) - { - return $this->createFusionConfigurationFromSite($this->findSiteBySiteNode($startNode))->toArray(); - } - - /** - * Create a runtime for the given site node - * - * @deprecated with Neos 8.3, will be removed with 9.0 use {@link createFusionConfigurationFromSite} and {@link RuntimeFactory::createFromConfiguration} instead - * - * @return Runtime - */ - public function createRuntime( - Node $currentSiteNode, - ControllerContext $controllerContext - ) { - $fusionGlobals = FusionGlobals::fromArray( - ['request' => $controllerContext->getRequest()] - ); - $runtime = $this->runtimeFactory->createFromConfiguration( - $this->createFusionConfigurationFromSite($this->findSiteBySiteNode($currentSiteNode)), - $fusionGlobals - ); - $runtime->setControllerContext($controllerContext); - return $runtime; - } - - /** - * Set the pattern for including the site root Fusion - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * use {@link FusionSourceCodeFactory} in combination with {@link RuntimeFactory::createRuntimeFromSourceCode()} instead - * - * @param string $siteRootFusionPattern A string for the sprintf format that takes the site package key as a single placeholder - * @return void - */ - public function setSiteRootFusionPattern($siteRootFusionPattern) - { - $this->siteRootFusionPattern = $siteRootFusionPattern; - } - - /** - * Get the Fusion resources that are included before the site Fusion. - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * use {@link FusionSourceCodeFactory} in combination with {@link RuntimeFactory::createRuntimeFromSourceCode()} instead - * - * @return array - */ - public function getPrependFusionIncludes() - { - return $this->prependFusionIncludes; - } - - /** - * Set Fusion resources that should be prepended before the site Fusion, - * it defaults to the Neos Root.fusion Fusion. - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * use {@link FusionSourceCodeFactory} in combination with {@link RuntimeFactory::createRuntimeFromSourceCode()} instead - * - * @param array $prependFusionIncludes - * @return void - */ - public function setPrependFusionIncludes(array $prependFusionIncludes) - { - $this->prependFusionIncludes = $prependFusionIncludes; - } - - - /** - * Get Fusion resources that will be appended after the site Fusion. - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * use {@link FusionSourceCodeFactory} in combination with {@link RuntimeFactory::createRuntimeFromSourceCode()} instead - * - * @return array - */ - public function getAppendFusionIncludes() - { - return $this->appendFusionIncludes; - } - - /** - * Set Fusion resources that should be appended after the site Fusion, - * this defaults to an empty array. - * - * @deprecated with Neos 8.3, will be removed with 9.0 - * use {@link FusionSourceCodeFactory} in combination with {@link RuntimeFactory::createRuntimeFromSourceCode()} instead - * - * @param array $appendFusionIncludes An array of Fusion resource URIs - * @return void - */ - public function setAppendFusionIncludes(array $appendFusionIncludes) - { - $this->appendFusionIncludes = $appendFusionIncludes; - } - - /** - * @param array $fusionIncludes - * @deprecated with Neos 8.3, will be removed with 9.0 - */ - private function createSourceCodeFromLegacyFusionIncludes(array $fusionIncludes, string $filePathForRelativeResolves): FusionSourceCodeCollection - { - return new FusionSourceCodeCollection(...array_map( - function (string $fusionFile) use ($filePathForRelativeResolves) { - if (str_starts_with($fusionFile, "resource://") === false) { - // legacy relative includes - $fusionFile = dirname($filePathForRelativeResolves) . '/' . $fusionFile; - } - return FusionSourceCode::fromFilePath($fusionFile); - }, - $fusionIncludes - )); - } - - private function findSiteBySiteNode(Node $siteNode): Site - { - if ($siteNode->nodeName === null) { - throw new \Neos\Neos\Domain\Exception(sprintf('Site node "%s" is unnamed', $siteNode->nodeAggregateId->value), 1681286146); - } - return $this->siteRepository->findOneByNodeName(SiteNodeName::fromNodeName($siteNode->nodeName)) - ?? throw new \Neos\Neos\Domain\Exception(sprintf('No site found for nodeNodeName "%s"', $siteNode->nodeName->value), 1677245517); - } + // @todo reintroduce with edit preview mode support + // /** + // * Create a runtime for the given site + // */ + // public function createRuntime(Site $site): Runtime; } diff --git a/Neos.Neos/Classes/Domain/Service/NodeSearchService.php b/Neos.Neos/Classes/Domain/Service/NodeSearchService.php deleted file mode 100644 index bd3ed2bb289..00000000000 --- a/Neos.Neos/Classes/Domain/Service/NodeSearchService.php +++ /dev/null @@ -1,42 +0,0 @@ - $searchNodeTypes - */ - public function findByProperties( - string $term, - array $searchNodeTypes, - ?Node $startingPoint = null - ): never { - throw new \InvalidArgumentException('Cannot find nodes with the current set of arguments', 1651923867); - } -} diff --git a/Neos.Neos/Classes/Domain/Service/NodeSearchServiceInterface.php b/Neos.Neos/Classes/Domain/Service/NodeSearchServiceInterface.php deleted file mode 100644 index abd58aa5681..00000000000 --- a/Neos.Neos/Classes/Domain/Service/NodeSearchServiceInterface.php +++ /dev/null @@ -1,28 +0,0 @@ - $searchNodeTypes - */ - public function findByProperties(string $term, array $searchNodeTypes): Nodes; -} diff --git a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php index 0807b96ccd3..5fd9c00d611 100644 --- a/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php +++ b/Neos.Neos/Classes/Domain/Service/NodeSiteResolvingService.php @@ -15,22 +15,20 @@ namespace Neos\Neos\Domain\Service; use Neos\ContentRepository\Core\Factory\ContentRepositoryId; -use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphIdentity; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\Neos\FrontendRouting\NodeAddress; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; +use Neos\Neos\FrontendRouting\NodeAddress; #[Flow\Scope('singleton')] class NodeSiteResolvingService { - /** - * @Flow\Inject - * @var ContentRepositoryRegistry - */ - protected $contentRepositoryRegistry; + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** @internal */ public function findSiteNodeForNodeAddress( NodeAddress $nodeAddress, ContentRepositoryId $contentRepositoryId @@ -45,20 +43,13 @@ public function findSiteNodeForNodeAddress( ? VisibilityConstraints::frontend() : VisibilityConstraints::withoutRestrictions() ); + $node = $subgraph->findNodeById($nodeAddress->nodeAggregateId); - if (is_null($node)) { + if (!$node) { return null; } - $previousNode = null; - do { - if ($node->nodeType->isOfType('Neos.Neos:Sites')) { - // the Site node is the one one level underneath the "Sites" node. - return $previousNode; - } - $previousNode = $node; - } while ($node = $subgraph->findParentNode($node->nodeAggregateId)); + $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE)); - // no Site node found at rootline - return null; + return $siteNode; } } diff --git a/Neos.Neos/Classes/Domain/Service/NodeTypeNameFactory.php b/Neos.Neos/Classes/Domain/Service/NodeTypeNameFactory.php index 67542aa2327..6af5e3827b1 100644 --- a/Neos.Neos/Classes/Domain/Service/NodeTypeNameFactory.php +++ b/Neos.Neos/Classes/Domain/Service/NodeTypeNameFactory.php @@ -20,16 +20,39 @@ #[Flow\Proxy(false)] final class NodeTypeNameFactory { + public const NAME_CONTENT = 'Neos.Neos:Content'; + public const NAME_CONTENT_COLLECTION = 'Neos.Neos:ContentCollection'; public const NAME_DOCUMENT = 'Neos.Neos:Document'; + public const NAME_FALLBACK = 'Neos.Neos:FallbackNode'; + public const NAME_SHORTCUT = 'Neos.Neos:Shortcut'; public const NAME_SITE = 'Neos.Neos:Site'; public const NAME_SITES = 'Neos.Neos:Sites'; - public const NAME_FALLBACK = 'Neos.Neos:FallbackNode'; + + public static function forContent(): NodeTypeName + { + return NodeTypeName::fromString(self::NAME_CONTENT); + } + + public static function forContentCollection(): NodeTypeName + { + return NodeTypeName::fromString(self::NAME_CONTENT_COLLECTION); + } public static function forDocument(): NodeTypeName { return NodeTypeName::fromString(self::NAME_DOCUMENT); } + public static function forFallback(): NodeTypeName + { + return NodeTypeName::fromString(self::NAME_FALLBACK); + } + + public static function forShortcut(): NodeTypeName + { + return NodeTypeName::fromString(self::NAME_SHORTCUT); + } + public static function forSite(): NodeTypeName { return NodeTypeName::fromString(self::NAME_SITE); @@ -39,9 +62,4 @@ public static function forSites(): NodeTypeName { return NodeTypeName::fromString(self::NAME_SITES); } - - public static function forFallback(): NodeTypeName - { - return NodeTypeName::fromString(self::NAME_FALLBACK); - } } diff --git a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php index e676f4579c0..a93df26f963 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php +++ b/Neos.Neos/Classes/Domain/Service/SiteNodeUtility.php @@ -16,82 +16,83 @@ namespace Neos\Neos\Domain\Service; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; -use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Neos\Domain\Model\Site; -use Neos\Neos\Domain\Repository\DomainRepository; use Neos\Neos\Domain\Repository\SiteRepository; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; #[Flow\Scope('singleton')] final class SiteNodeUtility { + use NodeTypeWithFallbackProvider; + public function __construct( - private readonly ContentRepositoryRegistry $contentRepositoryRegistry, - private readonly DomainRepository $domainRepository, - private readonly SiteRepository $siteRepository + private readonly ContentRepositoryRegistry $contentRepositoryRegistry ) { } - public function findSiteNode(Node $node): Node - { - $previousNode = null; - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); - do { - if ($node->nodeType->isOfType('Neos.Neos:Sites')) { - // the Site node is the one one level underneath the "Sites" node. - if (is_null($previousNode)) { - break; - } - return $previousNode; - } - $previousNode = $node; - } while ($node = $subgraph->findParentNode($node->nodeAggregateId)); - - // no Site node found at rootline - throw new \RuntimeException('No site node found!'); - } - - public function findCurrentSiteNode( - ContentRepositoryId $contentRepositoryId, + /** + * Find the site node by the neos site entity. + * + * To find the site node for the live workspace in a 0 dimensional content repository use: + * + * ```php + * $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId); + * $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()) + * ?? throw new \RuntimeException('Expected live workspace to exist.'); + * + * $siteNode = $this->siteNodeUtility->findSiteNodeBySite( + * $site, + * $liveWorkspace->currentContentStreamId, + * DimensionSpacePoint::createWithoutDimensions(), + * VisibilityConstraints::frontend() + * ); + * ``` + * + * To resolve the Site by a node use {@see SiteRepository::findSiteBySiteNode()} + */ + public function findSiteNodeBySite( + Site $site, ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, VisibilityConstraints $visibilityConstraints ): Node { - $domain = $this->domainRepository->findOneByActiveRequest(); - $site = $domain - ? $domain->getSite() - : $this->siteRepository->findDefault(); + $contentRepository = $this->contentRepositoryRegistry->get($site->getConfiguration()->contentRepositoryId); - if ($site instanceof Site) { - $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $subgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, - $dimensionSpacePoint, - $visibilityConstraints, - ); + $subgraph = $contentRepository->getContentGraph()->getSubgraph( + $contentStreamId, + $dimensionSpacePoint, + $visibilityConstraints, + ); + + $rootNodeAggregate = $contentRepository->getContentGraph()->findRootNodeAggregateByType( + $contentStreamId, + NodeTypeNameFactory::forSites() + ); + $rootNode = $rootNodeAggregate->getNodeByCoveredDimensionSpacePoint($dimensionSpacePoint); + + $siteNode = $subgraph->findChildNodeConnectedThroughEdgeName( + $rootNode->nodeAggregateId, + $site->getNodeName()->toNodeName() + ); + + if (!$siteNode) { + throw new \RuntimeException(sprintf('No site node found for site "%s"', $site->getNodeName()), 1697140379); + } - $rootNodeAggregate = $contentRepository->getContentGraph() - ->findRootNodeAggregateByType( - $contentStreamId, - NodeTypeName::fromString('Neos.Neos:Sites') - ); - $sitesNode = $subgraph->findNodeById($rootNodeAggregate->nodeAggregateId); - if ($sitesNode) { - $siteNode = $subgraph->findChildNodeConnectedThroughEdgeName( - $sitesNode->nodeAggregateId, - $site->getNodeName()->toNodeName() - ); - if ($siteNode instanceof Node) { - return $siteNode; - } - } + if (!$this->getNodeType($siteNode)->isOfType(NodeTypeNameFactory::NAME_SITE)) { + throw new \RuntimeException(sprintf( + 'The site node "%s" (type: "%s") must be of type "%s"', + $siteNode->nodeAggregateId->value, + $siteNode->nodeTypeName->value, + NodeTypeNameFactory::NAME_SITE + ), 1697140367); } - throw new \RuntimeException('No site node found for domain "' . $domain?->getHostname() . '" and site "' . $site?->getNodeName() . '"'); + return $siteNode; } } diff --git a/Neos.Neos/Classes/Domain/Service/SiteService.php b/Neos.Neos/Classes/Domain/Service/SiteService.php index 0331b8be881..c1fafe378bf 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteService.php +++ b/Neos.Neos/Classes/Domain/Service/SiteService.php @@ -14,11 +14,10 @@ namespace Neos\Neos\Domain\Service; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\PersistenceManagerInterface; use Neos\Media\Domain\Model\Asset; @@ -65,12 +64,6 @@ class SiteService */ protected $assetCollectionRepository; - #[Flow\Inject] - protected SiteNodeUtility $siteNodeUtility; - - #[Flow\Inject] - protected UserService $domainUserService; - /** * Remove given site all nodes for that site and all domains associated. */ @@ -121,12 +114,12 @@ public function pruneAll() */ public function assignUploadedAssetToSiteAssetCollection(Asset $asset, Node $node, string $propertyName) { - try { - $siteNode = $this->siteNodeUtility->findSiteNode($node); - } catch (\InvalidArgumentException $exception) { + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); + $siteNode = $subgraph->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE)); + if (!$siteNode) { + // should not happen return; } - if ($siteNode->nodeName === null) { return; } diff --git a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php index 5e9ce9ce471..77c66be3809 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php +++ b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php @@ -15,32 +15,22 @@ namespace Neos\Neos\Domain\Service; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\DimensionSpace\ContentDimensionZookeeper; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\InterDimensionalVariationGraph; +use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; -use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; -use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant; -use Neos\ContentRepository\Core\Feature\RootNodeCreation\Command\CreateRootNodeAggregateWithNode; -use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace; +use Neos\ContentRepository\Core\NodeType\NodeTypeManager; +use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; -use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\Service\ContentRepositoryBootstrapper; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFoundException; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; -use Neos\ContentRepository\Core\NodeType\NodeTypeManager; -use Neos\ContentRepository\Core\NodeType\NodeTypeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; -use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceTitle; -use Neos\Neos\Domain\Exception\LiveWorkspaceIsMissing; -use Neos\Neos\Domain\Exception\SitesNodeIsMissing; +use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; +use Neos\Neos\Domain\Exception\SiteNodeTypeIsInvalid; use Neos\Neos\Domain\Model\Site; use Neos\Neos\Domain\Model\SiteNodeName; @@ -69,7 +59,7 @@ public function removeSiteNode(SiteNodeName $siteNodeName): void foreach ($this->contentRepository->getContentStreamFinder()->findAllIds() as $contentStreamId) { $sitesNodeAggregate = $contentGraph->findRootNodeAggregateByType( $contentStreamId, - NodeTypeName::fromString('Neos.Neos:Sites') + NodeTypeNameFactory::forSites() ); $siteNodeAggregates = $contentGraph->findChildNodeAggregatesByName( $contentStreamId, @@ -97,14 +87,20 @@ public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): voi $liveContentStreamId, NodeTypeNameFactory::forSites() ); - $siteNodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); - - if ($siteNodeType->getName() === 'Neos.Neos:FallbackNode') { + try { + $siteNodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); + } catch (NodeTypeNotFoundException $exception) { throw new NodeTypeNotFoundException( 'Cannot create a site using a non-existing node type.', - 1412372375 + 1412372375, + $exception ); } + + if (!$siteNodeType->isOfType(NodeTypeNameFactory::NAME_SITE)) { + throw SiteNodeTypeIsInvalid::becauseItIsNotOfTypeSite(NodeTypeName::fromString($nodeTypeName)); + } + $siteNodeAggregate = $this->contentRepository->getContentGraph()->findChildNodeAggregatesByName( $liveContentStreamId, $sitesNodeIdentifier, diff --git a/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php b/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php new file mode 100644 index 00000000000..44d75e72086 --- /dev/null +++ b/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php @@ -0,0 +1,35 @@ + - */ - protected $data = []; - - /** - * The parent event, if exists. E.g. if a "move node" operation triggered a bunch of other events, or a "publish" - * - * @var Event - * @phpstan-var ?self - * @ORM\ManyToOne(inversedBy="childEvents") - */ - protected $parentEvent; - - /** - * Child events, of this event - * - * @var ArrayCollection<\Neos\Neos\EventLog\Domain\Model\Event> - * @phpstan-var ArrayCollection - * @codingStandardsIgnoreStart - * @ORM\OneToMany(targetEntity="\Neos\Neos\EventLog\Domain\Model\Event", mappedBy="parentEvent", cascade={"persist"}) - * @codingStandardsIgnoreEnd - */ - protected $childEvents; - - /** - * Create a new event - * - * @param string $eventType - * @param array $data - * @param string $user - * @param Event $parentEvent - */ - public function __construct($eventType, $data, $user = null, Event $parentEvent = null) - { - $this->timestamp = new \DateTime(); - $this->eventType = $eventType; - $this->data = $data; - $this->accountIdentifier = $user; - $this->parentEvent = $parentEvent; - - $this->childEvents = new ArrayCollection(); - - $this->parentEvent?->addChildEvent($this); - } - - /** - * Return the type of this event - * - * @return string - */ - public function getEventType() - { - return $this->eventType; - } - - /** - * Return the timestamp of this event - * - * @return \DateTime - */ - public function getTimestamp() - { - return $this->timestamp; - } - - /** - * Return the payload of this event - * - * @return array - */ - public function getData(): array - { - return $this->data; - } - - /** - * Return the identifier of the account (if any) which triggered this event - * - * @return ?string - */ - public function getAccountIdentifier() - { - return $this->accountIdentifier; - } - - /** - * Return the parent event (if any) - */ - public function getParentEvent(): ?Event - { - return $this->parentEvent; - } - - /** - * Return the child events (if any) - * - * @return ArrayCollection - */ - public function getChildEvents(): ArrayCollection - { - return $this->childEvents; - } - - /** - * Add a new child event. Is called from the child event's constructor. - * - * @param Event $childEvent - * @return void - */ - public function addChildEvent(Event $childEvent) - { - $this->childEvents->add($childEvent); - } -} diff --git a/Neos.Neos/Classes/EventLog/Domain/Model/EventsOnDate.php b/Neos.Neos/Classes/EventLog/Domain/Model/EventsOnDate.php deleted file mode 100644 index 4e7c33190e2..00000000000 --- a/Neos.Neos/Classes/EventLog/Domain/Model/EventsOnDate.php +++ /dev/null @@ -1,63 +0,0 @@ - - */ - protected $events = []; - - /** - * @param \DateTime $day - */ - public function __construct(\DateTime $day) - { - $this->day = $day; - } - - /** - * add another event to this group - */ - public function add(Event $event): void - { - $this->events[] = $event; - } - - /** - * @return array - */ - public function getEvents() - { - return $this->events; - } - - /** - * @return \DateTime - */ - public function getDay() - { - return $this->day; - } -} diff --git a/Neos.Neos/Classes/EventLog/Domain/Model/NodeEvent.php b/Neos.Neos/Classes/EventLog/Domain/Model/NodeEvent.php deleted file mode 100644 index 02d1e3ada4d..00000000000 --- a/Neos.Neos/Classes/EventLog/Domain/Model/NodeEvent.php +++ /dev/null @@ -1,283 +0,0 @@ - - */ - protected $dimension; - - /** - * MD5 hash of the content dimensions - * - * @var string - * @ORM\Column(length=32) - */ - protected $dimensionsHash; - - /** - * @Flow\Inject - * @var UserService - */ - protected $userService; - - /** - * @Flow\Inject - * @var PersistenceManagerInterface - */ - protected $persistenceManager; - - /** - * @Flow\Inject - * @var SiteRepository - */ - protected $siteRepository; - - /** - * Return name of the workspace where the node event happened - * - * @return string - */ - public function getWorkspaceName() - { - return $this->workspaceName; - } - - /** - * @return bool - */ - public function isDocumentEvent() - { - return $this->documentNodeIdentifier === $this->nodeIdentifier; - } - - /** - * Return the node identifier of the closest parent document node related to this event - * - * @return string - */ - public function getDocumentNodeIdentifier() - { - return $this->documentNodeIdentifier; - } - - /** - * Return the node identifier of the node this event relates to - * - * @return string - */ - public function getNodeIdentifier() - { - return $this->nodeIdentifier; - } - - /** - * Set the "context node" this operation was working on. - * - * @param Node $node - * @return void - */ - /*public function setNode(Node $node) - { - $dimensionsArray = $node->getContext()->getDimensions(); - - $this->nodeIdentifier = $node->getIdentifier(); - $this->workspaceName = $node->getContext()->getWorkspaceName(); - $this->dimension = $dimensionsArray; - $this->dimensionsHash = Utility::sortDimensionValueArrayAndReturnDimensionsHash($dimensionsArray); - - $context = $node->getContext(); - if ($context instanceof ContentContext && $context->getCurrentSite() !== null) { - $siteIdentifier = $this->persistenceManager->getIdentifierByObject($context->getCurrentSite()); - } else { - $siteIdentifier = null; - } - $this->data = Arrays::arrayMergeRecursiveOverrule($this->data, [ - 'nodeContextPath' => $node->get(), - 'nodeLabel' => $node->getLabel(), - 'nodeType' => $node->nodeType->getName(), - 'site' => $siteIdentifier - ]); - - $node = self::getClosestAggregateNode($node); - - if ($node !== null) { - $this->documentNodeIdentifier = $node->getIdentifier(); - $this->data = Arrays::arrayMergeRecursiveOverrule($this->data, [ - 'documentNodeContextPath' => $node->getContextPath(), - 'documentNodeLabel' => $node->getLabel(), - 'documentNodeType' => $node->nodeType->getName() - ]); - } - }*/ - - /** - * Override the workspace name. *MUST* be called after setNode(), else it won't have an effect. - * - * @param string $workspaceName - * @return void - */ - public function setWorkspaceName($workspaceName) - { - $this->workspaceName = $workspaceName; - } - - /** - * Returns the closest aggregate node of the given node - * - * @param Node $node - * @return Node - */ - /*public static function getClosestAggregateNode(Node $node) - { - while ($node !== null && !$node->nodeType->isAggregate()) { - $node = $node->getParent(); - } - return $node; - }*/ - - /** - * Returns the closest document node, if it can be resolved. - * - * It might happen that, if this event refers to a node contained in a site which is not available anymore, - * Doctrine's proxy class of the Site domain model will fail with an EntityNotFoundException. We catch this - * case and return NULL. - * - * @return Node - */ - /*public function getDocumentNode() - { - try { - $context = $this->contextFactory->create([ - 'workspaceName' => $this->userService->getPersonalWorkspaceName(), - 'dimensions' => $this->dimension, - 'currentSite' => $this->getCurrentSite(), - 'invisibleContentShown' => true - ]); - return $context->getNodeByIdentifier($this->documentNodeIdentifier); - } catch (EntityNotFoundException $e) { - return null; - } - }*/ - - /** - * Returns the node this even refers to, if it can be resolved. - * - * It might happen that, if this event refers to a node contained in a site which is not available anymore, - * Doctrine's proxy class of the Site domain model will fail with an EntityNotFoundException. We catch this - * case and return NULL. - * - * @return Node - */ - /*public function getNode() - { - try { - $context = $this->contextFactory->create([ - 'workspaceName' => $this->userService->getPersonalWorkspaceName(), - 'dimensions' => $this->dimension, - 'currentSite' => $this->getCurrentSite(), - 'invisibleContentShown' => true - ]); - return $context->getNodeByIdentifier($this->nodeIdentifier); - } catch (EntityNotFoundException $e) { - return null; - } - }*/ - - /** - * Prevents invalid calls to the site repository in case the site data property is not available. - * - * @return null|object - */ - protected function getCurrentSite() - { - if (!isset($this->data['site'])) { - return null; - } - - return $this->siteRepository->findByIdentifier($this->data['site']); - } - - /** - * @return string - */ - public function __toString() - { - return sprintf('NodeEvent[%s, %s]', $this->eventType, $this->nodeIdentifier); - } - - /** - * @return string - */ - public function getDimensionsHash(): string - { - return $this->dimensionsHash; - } -} diff --git a/Neos.Neos/Classes/EventLog/Domain/Repository/EventRepository.php b/Neos.Neos/Classes/EventLog/Domain/Repository/EventRepository.php deleted file mode 100644 index 6aa769ea8c4..00000000000 --- a/Neos.Neos/Classes/EventLog/Domain/Repository/EventRepository.php +++ /dev/null @@ -1,110 +0,0 @@ - - */ - protected $defaultOrderings = [ - 'uid' => QueryInterface::ORDER_ASCENDING - ]; - - /** - * Find all events which are "top-level" and in a given workspace (or are not NodeEvents) - * - * @param integer $offset - * @param integer $limit - * @param string $workspaceName - * @return QueryResultInterface - * @throws PropertyNotAccessibleException - */ - public function findRelevantEventsByWorkspace($offset, $limit, $workspaceName) - { - $query = $this->prepareRelevantEventsQuery(); - $query->getQueryBuilder()->select('DISTINCT e'); - $query->getQueryBuilder() - ->andWhere('e NOT INSTANCE OF ' . NodeEvent::class . ' OR e IN (SELECT nodeevent.uid FROM ' - . NodeEvent::class - . ' nodeevent WHERE nodeevent.workspaceName = :workspaceName AND nodeevent.parentEvent IS NULL)') - ->setParameter('workspaceName', $workspaceName); - $query->getQueryBuilder()->setFirstResult($offset); - $query->getQueryBuilder()->setMaxResults($limit); - - return $query->execute(); - } - - /** - * Find all events which are "top-level", i.e. do not have a parent event. - * - * @param integer $offset - * @param integer $limit - * @return QueryResultInterface - * @throws PropertyNotAccessibleException - */ - public function findRelevantEvents($offset, $limit) - { - $query = $this->prepareRelevantEventsQuery(); - - $query->getQueryBuilder()->setFirstResult($offset); - $query->getQueryBuilder()->setMaxResults($limit); - - return $query->execute(); - } - - /** - * @return \Neos\Flow\Persistence\Doctrine\Query - */ - protected function prepareRelevantEventsQuery() - { - $query = $this->createQuery(); - $queryBuilder = $query->getQueryBuilder(); - - $queryBuilder->andWhere( - $queryBuilder->expr()->isNull('e.parentEvent') - ); - - $queryBuilder->orderBy('e.uid', 'DESC'); - - return $query; - } - - /** - * Remove all events without checking foreign keys. Needed for clearing the table during tests. - * - * @return void - */ - public function removeAll(): void - { - $classMetaData = $this->entityManager->getClassMetadata($this->getEntityClassName()); - $connection = $this->entityManager->getConnection(); - $databasePlatform = $connection->getDatabasePlatform(); - $truncateTableQuery = $databasePlatform->getTruncateTableSql($classMetaData->getTableName()); - $connection->executeStatement($truncateTableQuery); - } -} diff --git a/Neos.Neos/Classes/EventLog/Domain/Service/EventEmittingService.php b/Neos.Neos/Classes/EventLog/Domain/Service/EventEmittingService.php deleted file mode 100644 index 8b4dfce5515..00000000000 --- a/Neos.Neos/Classes/EventLog/Domain/Service/EventEmittingService.php +++ /dev/null @@ -1,208 +0,0 @@ - - */ - protected $eventContext = []; - - protected ?string $currentUsername = null; - - /** - * @Flow\Inject - * @var EventRepository - */ - protected $eventRepository; - - /** - * @Flow\Inject - * @var UserService - */ - protected $userDomainService; - - /** - * @Flow\InjectConfiguration("eventLog.enabled") - * @var bool - */ - protected $enabled; - - /** - * @return boolean true if the event log is enabled and events should be captured - */ - public function isEnabled() - { - return (bool)$this->enabled; - } - - /** - * Convenience method for generating an event and directly adding it afterwards to persistence. - * - * @param string $eventType - * @param array $data - * @param string $eventClassName - * @throws Exception - * @return Event - */ - public function emit($eventType, array $data, $eventClassName = Event::class) - { - if (!$this->isEnabled()) { - throw new Exception('Event log not enabled', 1418464933); - } - - $event = $this->generate($eventType, $data, $eventClassName); - $this->add($event); - - return $event; - } - - /** - * Generates a new event, without persisting it yet. - * - * Note: Make sure to call add($event) afterwards. - * - * @param string $eventType - * @param array $data - * @param string $eventClassName - * @return Event - * @see emit() - */ - public function generate($eventType, array $data, $eventClassName = Event::class) - { - $this->initializeCurrentUsername(); - /** @var Event $event */ - $event = new $eventClassName($eventType, $data, $this->currentUsername, $this->getCurrentContext()); - $this->lastGeneratedEvent = $event; - - return $event; - } - - /** - * Add the passed event (which has been generated by generate()) to persistence. - * - * This only happens for top-level-events. All events which are attached to some parent event are persisted - * together with the parent. - * - * @param Event $nodeEvent - * @throws Exception - * @return void - * @see emit() - */ - public function add(Event $nodeEvent) - { - if (!$this->isEnabled()) { - throw new Exception('Event log not enabled', 1418464935); - } - - if ($nodeEvent->getParentEvent() === null) { - $this->eventRepository->add($nodeEvent); - } - } - - /** - * Push the last-generated event onto the context, - * nesting all further generated events underneath the top-level one. - * - * @return void - */ - public function pushContext() - { - if ($this->lastGeneratedEvent === null) { - throw new \InvalidArgumentException( - 'pushContext() can only be called directly after an invocation of emit().', - 1415353980 - ); - } - - $this->eventContext[] = $this->lastGeneratedEvent; - } - - /** - * Remove an element from the context stack. Is the reverse operation to pushContext(). - * - * @return void - */ - public function popContext() - { - if (count($this->eventContext) > 0) { - array_pop($this->eventContext); - } else { - throw new \InvalidArgumentException( - 'popContext() can only be called if the context has been pushed beforehand.', - 1415354224 - ); - } - } - - /** - * The current context-event or NULL if none exists currently. - * - * @return Event|NULL - */ - protected function getCurrentContext() - { - if (count($this->eventContext) > 0) { - return end($this->eventContext); - } else { - return null; - } - } - - /** - * Try to set the current username emitting the events, if possible - * - * @return void - */ - protected function initializeCurrentUsername() - { - if (!is_null($this->currentUsername)) { - return; - } - - $currentUser = $this->userDomainService->getCurrentUser(); - if (!$currentUser instanceof User) { - return; - } - - $this->currentUsername = $this->userDomainService->getUsername($currentUser); - } -} diff --git a/Neos.Neos/Classes/EventLog/Integrations/AbstractIntegrationService.php b/Neos.Neos/Classes/EventLog/Integrations/AbstractIntegrationService.php deleted file mode 100644 index be96f2310f2..00000000000 --- a/Neos.Neos/Classes/EventLog/Integrations/AbstractIntegrationService.php +++ /dev/null @@ -1,27 +0,0 @@ - - */ - protected $changedNodes = []; - - /** - * @var array - */ - protected $currentNodeAddEvents = []; - - /** - * @var boolean - */ - protected $currentlyCopying = false; - - /** - * @var integer - */ - protected $currentlyMoving = 0; - - /** - * @var integer - */ - protected $currentlyAdopting = 0; - - /** - * @var array - */ - protected $scheduledNodeEventUpdates = []; - - /** - * React on the Doctrine preFlush event and trigger the respective internal node events - * - * @return void - */ - /*public function preFlush() - { - $this->generateNodeEvents(); - }*/ - - /** - * Emit a "Node Added" event - * - * @return void - */ - /*public function beforeNodeCreate() - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $nodeEvent = $this->eventEmittingService->generate(self::NODE_ADDED, [], NodeEvent::class); - $this->currentNodeAddEvents[] = $nodeEvent; - $this->eventEmittingService->pushContext($nodeEvent); - }*/ - - /** - * Add the created node to the previously created "Added Node" event - * - * @param Node $node - * @return void - */ - /*public function afterNodeCreate(Node $node) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $nodeEvent = array_pop($this->currentNodeAddEvents); - $nodeEvent->setNode($node); - $this->eventEmittingService->popContext(); - $this->eventEmittingService->add($nodeEvent); - }*/ - - /** - * Emit a "Node Updated" event - * - * @param Node $node - * @return void - */ - /*public function nodeUpdated(Node $node) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if (!isset($this->changedNodes[$node->getContextPath()])) { - $this->changedNodes[$node->getContextPath()] = ['node' => $node]; - } - }*/ - - /** - * Emit an event when node properties have been changed - * - * @param Node $node - * @param $propertyName - * @param $oldValue - * @param $value - * @return void - */ - /*public function beforeNodePropertyChange(Node $node, $propertyName, $oldValue, $value) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if (count($this->currentNodeAddEvents) > 0) { - // add is currently running, during that; we do not want any update events - return; - } - if ($oldValue === $value) { - return; - } - if (!isset($this->changedNodes[$node->getContextPath()])) { - $this->changedNodes[$node->getContextPath()] = ['node' => $node]; - } - if (!isset($this->changedNodes[$node->getContextPath()]['oldLabel'])) { - $this->changedNodes[$node->getContextPath()]['oldLabel'] = $node->getLabel(); - } - - $this->changedNodes[$node->getContextPath()]['old'][$propertyName] = $oldValue; - $this->changedNodes[$node->getContextPath()]['new'][$propertyName] = $value; - }*/ - - /** - * Add the new label to a previously created node property changed event - * - * @param Node $node - * @param $propertyName - * @param $oldValue - * @param $value - * @return void - */ - /*public function nodePropertyChanged(Node $node, $propertyName, $oldValue, $value) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if ($oldValue === $value) { - return; - } - - $this->changedNodes[$node->getContextPath()]['newLabel'] = $node->getLabel(); - $this->changedNodes[$node->getContextPath()]['node'] = $node; - }*/ - - /** - * Emits a "Node Removed" event - * - * @param Node $node - * @return void - */ - /*public function nodeRemoved(Node $node) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $nodeEvent = $this->eventEmittingService->emit(self::NODE_REMOVED, [], NodeEvent::class); - $nodeEvent->setNode($node); - }*/ - - /** - * @param Node $node - * @param Workspace $targetWorkspace - * @return void - */ - /*public function beforeNodePublishing(Node $node, Workspace $targetWorkspace) - { - }*/ - - /** - * Emits a "Node Copy" event - * - * @param Node $sourceNode - * @param Node $targetParentNode - * @return void - * @throws \Exception - */ - /*public function beforeNodeCopy(Node $sourceNode, Node $targetParentNode) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if ($this->currentlyCopying) { - throw new \Exception('TODO: already copying...'); - } - - $this->currentlyCopying = true; - - $nodeEvent = $this->eventEmittingService->emit(self::NODE_COPY, [ - 'copiedInto' => $targetParentNode->getContextPath() - ], NodeEvent::class); - $nodeEvent->setNode($sourceNode); - $this->eventEmittingService->pushContext(); - }*/ - - /** - * @param Node $copiedNode - * @param Node $targetParentNode - * @return void - * @throws \Exception - */ - /*public function afterNodeCopy(Node $copiedNode, Node $targetParentNode) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if ($this->currentlyCopying === false) { - throw new \Exception('TODO: copying not started'); - } - $this->currentlyCopying = false; - $this->eventEmittingService->popContext(); - }*/ - - /** - * Emits a "Node Move" event - * - * @param Node $movedNode - * @param Node $referenceNode - * @param integer $moveOperation - */ - /*public function beforeNodeMove(Node $movedNode, Node $referenceNode, $moveOperation) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $this->currentlyMoving += 1; - - $nodeEvent = $this->eventEmittingService->emit(self::NODE_MOVE, [ - 'referenceNode' => $referenceNode->getContextPath(), - 'moveOperation' => $moveOperation - ], NodeEvent::class); - $nodeEvent->setNode($movedNode); - $this->eventEmittingService->pushContext(); - }*/ - - /** - * @param Node $movedNode - * @param Node $referenceNode - * @param integer $moveOperation - * @return void - * @throws \Exception - */ - /*public function afterNodeMove(Node $movedNode, Node $referenceNode, $moveOperation) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if ($this->currentlyMoving === 0) { - throw new \Exception('TODO: moving not started'); - } - - $this->currentlyMoving -= 1; - $this->eventEmittingService->popContext(); - }*/ - - /** - * Emits a "Node Adopt" event - * - * @param Node $node - * @param Context $context - * @param $recursive - * @return void - */ - /*public function beforeAdoptNode(Node $node, Context $context, $recursive) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if ($this->currentlyAdopting === 0) { - $nodeEvent = $this->eventEmittingService->emit(self::NODE_ADOPT, [ - 'targetWorkspace' => $context->getWorkspaceName(), - 'targetDimensions' => $context->getTargetDimensions(), - 'recursive' => $recursive - ], NodeEvent::class); - $nodeEvent->setNode($node); - $this->eventEmittingService->pushContext(); - } - - $this->currentlyAdopting++; - }*/ - - /** - * @param Node $node - * @param Context $context - * @param $recursive - * @return void - */ - /*public function afterAdoptNode(Node $node, Context $context, $recursive) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $this->currentlyAdopting--; - if ($this->currentlyAdopting === 0) { - $this->eventEmittingService->popContext(); - } - }*/ - - /** - * @return void - */ - /*public function generateNodeEvents() - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - if (count($this->currentNodeAddEvents) > 0) { - return; - } - - foreach ($this->changedNodes as $nodePath => $data) { - $node = $data['node']; - unset($data['node']); - if (isset($data['oldLabel']) && isset($data['newLabel'])) { - if ($data['oldLabel'] !== $data['newLabel']) { - $nodeEvent = $this->eventEmittingService->emit( - self::NODE_LABEL_CHANGED, - ['oldLabel' => $data['oldLabel'], 'newLabel' => $data['newLabel']], - NodeEvent::class - ); - $nodeEvent->setNode($node); - } - unset($data['oldLabel']); - unset($data['newLabel']); - } - - if (!empty($data)) { - $nodeEvent = $this->eventEmittingService->emit(self::NODE_UPDATED, $data, NodeEvent::class); - $nodeEvent->setNode($node); - } - } - - $this->changedNodes = []; - }*/ - - /** - * @param Node $node - * @param Workspace $targetWorkspace - * @return void - */ - public function afterNodePublishing(Node $node, Workspace $targetWorkspace) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); - $documentNode = $node; - while ($documentNode !== null && !$documentNode->nodeType->isAggregate()) { - $documentNode = $subgraph->findParentNode($documentNode->nodeAggregateId); - } - - if ($documentNode === null) { - return; - } - $contentRepository = $this->contentRepositoryRegistry->get( - $node->subgraphIdentity->contentRepositoryId - ); - $nodeAddressFactory = NodeAddressFactory::create($contentRepository); - $nodeAddress = $nodeAddressFactory->createFromNode($node); - $documentNodeAddress = $nodeAddressFactory->createFromNode($documentNode); - - $this->scheduledNodeEventUpdates[$documentNodeAddress->serializeForUri()] = [ - 'workspaceName' => $nodeAddress->workspaceName, - 'nestedNodeIdentifiersWhichArePublished' => [], - 'targetWorkspace' => $targetWorkspace->workspaceName, - 'documentNode' => $documentNode - ]; - - $this->scheduledNodeEventUpdates[$documentNodeAddress->serializeForUri()] - ['nestedNodeIdentifiersWhichArePublished'][] = $node->nodeAggregateId; - } - - /** - * Binds events to a Node.Published event for each document node published - * - * @return void - */ - /*public function updateEventsAfterPublish() - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $entityManager = $this->entityManager; - - foreach ($this->scheduledNodeEventUpdates as $documentPublish) { - $nodeEvent = $this->eventEmittingService->emit(self::DOCUMENT_PUBLISHED, [], NodeEvent::class); - $nodeEvent->setNode($documentPublish['documentNode']); - $nodeEvent->setWorkspaceName($documentPublish['targetWorkspace']); - $this->persistenceManager->allowObject($nodeEvent); - $this->persistenceManager->persistAll(true); - - $parentEventIdentifier = $this->persistenceManager->getIdentifierByObject($nodeEvent); - - $qb = $entityManager->createQueryBuilder(); - $qb->update(NodeEvent::class, 'e') - ->set('e.parentEvent', ':parentEventIdentifier') - ->setParameter('parentEventIdentifier', $parentEventIdentifier) - ->where('e.parentEvent IS NULL') - ->andWhere('e.workspaceName = :workspaceName') - ->setParameter('workspaceName', $documentPublish['workspaceName']) - ->andWhere('e.documentNodeIdentifier = :documentNodeIdentifier') - ->setParameter('documentNodeIdentifier', $documentPublish['documentNode']->getIdentifier()) - ->andWhere('e.eventType != :publishedEventType') - ->setParameter('publishedEventType', self::DOCUMENT_PUBLISHED) - ->getQuery()->execute(); - } - - $this->scheduledNodeEventUpdates = []; - - }*/ - - /** - * @return void - */ - public function reset() - { - $this->changedNodes = []; - $this->scheduledNodeEventUpdates = []; - $this->currentlyAdopting = 0; - $this->currentlyCopying = false; - $this->currentNodeAddEvents = []; - } -} diff --git a/Neos.Neos/Classes/EventLog/Integrations/EntityIntegrationService.php b/Neos.Neos/Classes/EventLog/Integrations/EntityIntegrationService.php deleted file mode 100644 index 857a2c9fac6..00000000000 --- a/Neos.Neos/Classes/EventLog/Integrations/EntityIntegrationService.php +++ /dev/null @@ -1,141 +0,0 @@ - - */ - protected $monitorEntitiesSetting; - - /** - * Dummy method which is called in a prePersist signal. - * If we remove that, this object is never instantiated and thus cannot hook into the Doctrine EntityManager. - * - * @return void - */ - public function dummyMethodToEnsureInstanceExists() - { - // intentionally empty - } - - /** - * Record events for entity changes. - * - * Note: this method is registered as an Doctrine event listener in the settings of this package. - * - * TODO: Update/Delete of Entities - * - * @param OnFlushEventArgs $eventArgs - * @return void - * @throws Exception - */ - public function onFlush(OnFlushEventArgs $eventArgs) - { - if (!$this->eventEmittingService->isEnabled()) { - return; - } - - $entityManager = $eventArgs->getEntityManager(); - $unitOfWork = $entityManager->getUnitOfWork(); - - foreach ($unitOfWork->getScheduledEntityInsertions() as $entity) { - $className = get_class($entity); - if (isset($this->monitorEntitiesSetting[$className])) { - $entityMonitoringConfiguration = $this->monitorEntitiesSetting[$className]; - - if (isset($entityMonitoringConfiguration['events']['created'])) { - $data = []; - foreach ($entityMonitoringConfiguration['data'] as $key => $eelExpression) { - $data[$key] = Utility::evaluateEelExpression( - $eelExpression, - $this->eelEvaluator, - ['entity' => $entity] - ); - } - - $event = $this->eventEmittingService->emit( - $entityMonitoringConfiguration['events']['created'], - $data - ); - $unitOfWork->computeChangeSet($entityManager->getClassMetadata(Event::class), $event); - } - } - } - - foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) { - $className = get_class($entity); - if (isset($this->monitorEntitiesSetting[$className])) { - $entityMonitoringConfiguration = $this->monitorEntitiesSetting[$className]; - - if (isset($entityMonitoringConfiguration['events']['deleted'])) { - $data = []; - foreach ($entityMonitoringConfiguration['data'] as $key => $eelExpression) { - $data[$key] = Utility::evaluateEelExpression( - $eelExpression, - $this->eelEvaluator, - ['entity' => $entity] - ); - } - - $event = $this->eventEmittingService->emit( - $entityMonitoringConfiguration['events']['deleted'], - $data - ); - $unitOfWork->computeChangeSet($entityManager->getClassMetadata(Event::class), $event); - } - } - } - } - - /** - * @param array $monitorEntitiesSetting - * @return void - */ - public function setMonitorEntitiesSetting($monitorEntitiesSetting) - { - $this->monitorEntitiesSetting = $monitorEntitiesSetting; - } -} diff --git a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/RequestToDimensionSpacePointContext.php b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/RequestToDimensionSpacePointContext.php index f615f766c44..abec0874482 100644 --- a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/RequestToDimensionSpacePointContext.php +++ b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/RequestToDimensionSpacePointContext.php @@ -32,7 +32,7 @@ public static function fromUriPathAndRouteParametersAndResolvedSite(string $init $initialUriPath, $routeParameters, $initialUriPath, - DimensionSpacePoint::fromArray([]), + DimensionSpacePoint::createWithoutDimensions(), $resolvedSite, ); } diff --git a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver.php b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver.php index 300586962a8..d84976d2f43 100644 --- a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver.php +++ b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver.php @@ -83,7 +83,7 @@ public static function createForNoDimensions(): self [], [], Segments::create(), - DimensionSpacePoint::fromArray([]) + DimensionSpacePoint::createWithoutDimensions() ); } diff --git a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver/SegmentMapping.php b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver/SegmentMapping.php index b28ecbce923..9e930a401b9 100644 --- a/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver/SegmentMapping.php +++ b/Neos.Neos/Classes/FrontendRouting/DimensionResolution/Resolver/UriPathResolver/SegmentMapping.php @@ -45,7 +45,7 @@ public static function fromArray(array $dimensionValueMapping): self public function getIterator(): \Traversable { - return new \ArrayIterator($this->elements); + yield from $this->elements; } public function count(): int diff --git a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentNodeInfos.php b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentNodeInfos.php index e7b54c5ee21..a53401de5b3 100644 --- a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentNodeInfos.php +++ b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentNodeInfos.php @@ -14,18 +14,16 @@ namespace Neos\Neos\FrontendRouting\Projection; -use Traversable; - /** * @implements \IteratorAggregate */ -final class DocumentNodeInfos implements \IteratorAggregate +final readonly class DocumentNodeInfos implements \IteratorAggregate { /** * @param array $documentNodeInfos */ private function __construct( - private readonly array $documentNodeInfos + private array $documentNodeInfos ) { } @@ -38,8 +36,8 @@ public static function create(array $documentNodeInfos): static return new static($documentNodeInfos); } - public function getIterator(): Traversable + public function getIterator(): \Traversable { - return new \ArrayIterator($this->documentNodeInfos); + yield from $this->documentNodeInfos; } } diff --git a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php index f2150759fde..cb4a3d2cf40 100644 --- a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php +++ b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php @@ -41,6 +41,7 @@ use Neos\EventStore\Model\EventEnvelope; use Neos\EventStore\Model\EventStore\SetupResult; use Neos\Neos\Domain\Model\SiteNodeName; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException; /** @@ -208,9 +209,15 @@ private function whenRootNodeAggregateDimensionsWereUpdated(RootNodeAggregateDim } // Just to figure out current NodeTypeName. This is the same for the aggregate in all dimensionSpacePoints. + $pointHashes = $event->coveredDimensionSpacePoints->getPointHashes(); + $anyPointHash = reset($pointHashes); + // There is always at least one dimension space point covered, even in a zero-dimensional cr. + // Zero-dimensional means DimensionSpacePoint::fromArray([])->hash + assert(is_string($anyPointHash)); + $nodeInSomeDimension = $this->tryGetNode(fn () => $this->getState()->getByIdAndDimensionSpacePointHash( $event->nodeAggregateId, - $event->coveredDimensionSpacePoints->getIterator()->current()->hash + $anyPointHash )); if ($nodeInSomeDimension === null) { @@ -322,6 +329,7 @@ private function whenNodeAggregateWithNodeWasCreated(NodeAggregateWithNodeWasCre 'succeedingNodeAggregateId' => $event->succeedingNodeAggregateId?->value, 'shortcutTarget' => $shortcutTarget, 'nodeTypeName' => $event->nodeTypeName->value, + 'disabled' => $parentNode->getDisableLevel(), ]); } } @@ -527,7 +535,11 @@ private function whenNodePropertiesWereSet(NodePropertiesWereSet $event, EventEn $affectedDimensionSpacePoint->hash )); - if ($node === null) { + if ( + $node === null + || $this->nodeTypeManager->getNodeType($node->getNodeTypeName()) + ->isOfType(NodeTypeNameFactory::forSite()) + ) { // probably not a document node continue; } @@ -548,11 +560,6 @@ private function whenNodePropertiesWereSet(NodePropertiesWereSet $event, EventEn continue; } $oldUriPath = $node->getUriPath(); - // homepage -> TODO hacky? - if ($oldUriPath === '') { - continue; - } - /** @var string[] $uriPathSegments */ $uriPathSegments = explode('/', $oldUriPath); $uriPathSegments[array_key_last($uriPathSegments)] = $newPropertyValues['uriPathSegment']; $newUriPath = implode('/', $uriPathSegments); @@ -704,7 +711,7 @@ private function isDocumentNodeType(NodeTypeName $nodeTypeName): bool // HACK: We consider the currently configured node type of the given node. // This is a deliberate side effect of this projector! $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); - return $nodeType->isOfType('Neos.Neos:Document'); + return $nodeType->isOfType(NodeTypeNameFactory::NAME_DOCUMENT); } private function isShortcutNodeType(NodeTypeName $nodeTypeName): bool @@ -712,7 +719,7 @@ private function isShortcutNodeType(NodeTypeName $nodeTypeName): bool // HACK: We consider the currently configured node type of the given node. // This is a deliberate side effect of this projector! $nodeType = $this->nodeTypeManager->getNodeType($nodeTypeName); - return $nodeType->isOfType('Neos.Neos:Shortcut'); + return $nodeType->isOfType(NodeTypeNameFactory::NAME_SHORTCUT); } private function tryGetNode(\Closure $closure): ?DocumentNodeInfo diff --git a/Neos.Neos/Classes/Fusion/AbstractMenuItemsImplementation.php b/Neos.Neos/Classes/Fusion/AbstractMenuItemsImplementation.php index a732ddf97d3..d37385261f4 100644 --- a/Neos.Neos/Classes/Fusion/AbstractMenuItemsImplementation.php +++ b/Neos.Neos/Classes/Fusion/AbstractMenuItemsImplementation.php @@ -60,6 +60,13 @@ abstract class AbstractMenuItemsImplementation extends AbstractFusionObject */ protected $renderHiddenInIndex; + /** + * Internal cache for the calculateItemStates property. + * + * @var boolean + */ + protected $calculateItemStates; + /** * Rootline of all nodes from the current node to the site root node, keys are depth of nodes. * @@ -70,6 +77,19 @@ abstract class AbstractMenuItemsImplementation extends AbstractFusionObject #[Flow\Inject] protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** + * Whether the active/current state of menu items is calculated on the server side. + * This has an effect on performance and caching + */ + public function isCalculateItemStatesEnabled(): bool + { + if ($this->calculateItemStates === null) { + $this->calculateItemStates = (bool)$this->fusionValue('calculateItemStates'); + } + + return $this->calculateItemStates; + } + /** * Should nodes that have "hiddenInIndex" set still be visible in this menu. * @@ -169,4 +189,15 @@ protected function getCurrentNodeRootline(): array return $this->currentNodeRootline; } + + protected function buildUri(Node $node): string + { + $this->runtime->pushContextArray([ + 'itemNode' => $node, + 'documentNode' => $node, + ]); + $uri = $this->runtime->render($this->path . '/itemUriRenderer'); + $this->runtime->popContext(); + return $uri; + } } diff --git a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php index 71a64e4a356..e66d617b834 100644 --- a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php +++ b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php @@ -255,7 +255,7 @@ protected function getAllImplementedNodeTypeNames(NodeType $nodeType) function (array $types, NodeType $superType) use ($self) { return array_merge($types, $self->getAllImplementedNodeTypeNames($superType)); }, - [$nodeType->getName()] + [$nodeType->name->value] ); $types = array_unique($types); diff --git a/Neos.Neos/Classes/Fusion/DimensionMenuItem.php b/Neos.Neos/Classes/Fusion/DimensionMenuItem.php new file mode 100644 index 00000000000..cb7ff321d1c --- /dev/null +++ b/Neos.Neos/Classes/Fusion/DimensionMenuItem.php @@ -0,0 +1,26 @@ +|null $targetDimensions + */ + public function __construct( + public ?Node $node, + public ?MenuItemState $state = null, + public ?string $label = null, + public ?array $targetDimensions = null, + public ?string $uri = null + ) { + } +} diff --git a/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php b/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php index 50871a64ebd..6877fe98c6d 100644 --- a/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php +++ b/Neos.Neos/Classes/Fusion/DimensionsMenuItemsImplementation.php @@ -39,7 +39,7 @@ public function getDimension(): array /** * Builds the array of Menu items for this variant menu - * @return array> + * @return array */ protected function buildItems(): array { @@ -86,12 +86,13 @@ protected function buildItems(): array $metadata = $this->determineMetadata($dimensionSpacePoint, $dimensionMenuItemsImplementationInternals); if ($variant === null || !$this->isNodeHidden($variant)) { - $menuItems[] = [ - 'node' => $variant, - 'state' => $this->calculateItemState($variant), - 'label' => $this->determineLabel($variant, $metadata), - 'targetDimensions' => $metadata - ]; + $menuItems[] = new DimensionMenuItem( + $variant, + $this->isCalculateItemStatesEnabled() ? $this->calculateItemState($variant) : null, + $this->determineLabel($variant, $metadata), + $metadata, + $variant ? $this->buildUri($variant) : null + ); } } } @@ -100,15 +101,15 @@ protected function buildItems(): array if ($contentDimensionIdentifierToLimitTo && $valuesToRestrictTo) { $order = array_flip($valuesToRestrictTo); usort($menuItems, function ( - array $menuItemA, - array $menuItemB + DimensionMenuItem $menuItemA, + DimensionMenuItem $menuItemB ) use ( $order, $contentDimensionIdentifierToLimitTo ) { - return (int)$order[$menuItemA['node']?->subgraphIdentity->dimensionSpacePoint->getCoordinate( + return (int)$order[$menuItemA->node?->subgraphIdentity->dimensionSpacePoint->getCoordinate( $contentDimensionIdentifierToLimitTo - )] <=> (int)$order[$menuItemB['node']?->subgraphIdentity->dimensionSpacePoint->getCoordinate( + )] <=> (int)$order[$menuItemB->node?->subgraphIdentity->dimensionSpacePoint->getCoordinate( $contentDimensionIdentifierToLimitTo )]; }); @@ -218,19 +219,19 @@ protected function determineLabel(?Node $variant = null, array $metadata = []): } } - protected function calculateItemState(?Node $variant = null): string + protected function calculateItemState(?Node $variant = null): MenuItemState { if (is_null($variant)) { - return self::STATE_ABSENT; + return MenuItemState::ABSENT; } if ($variant === $this->currentNode) { - return self::STATE_CURRENT; + return MenuItemState::CURRENT; } - - return self::STATE_NORMAL; + return MenuItemState::NORMAL; } + /** * In some cases generalization of the other dimension values is feasible * to find a dimension space point in which a variant can be resolved diff --git a/Neos.Neos/Classes/Fusion/Helper/BackendHelper.php b/Neos.Neos/Classes/Fusion/Helper/BackendHelper.php index 53c5bd94779..b3dcf1aa0a2 100644 --- a/Neos.Neos/Classes/Fusion/Helper/BackendHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/BackendHelper.php @@ -35,8 +35,6 @@ class BackendHelper implements ProtectedContextAwareInterface */ public function interfaceLanguage(): string { - $currentUser = $this->userService->getBackendUser(); - assert($currentUser !== null, "No backend user"); return $this->userService->getInterfaceLanguage(); } diff --git a/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php b/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php index 0b3826d337f..906d9c2ebb7 100644 --- a/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/NodeHelper.php @@ -14,23 +14,31 @@ namespace Neos\Neos\Fusion\Helper; +use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\Projection\ContentGraph\AbsoluteNodePath; +use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\CountAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\Flow\Annotations as Flow; use Neos\Eel\ProtectedContextAwareInterface; use Neos\Neos\Domain\Exception; use Neos\Neos\Presentation\VisualNodePath; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; +use Neos\Flow\Annotations as Flow; /** * Eel helper for ContentRepository Nodes */ class NodeHelper implements ProtectedContextAwareInterface { + use NodeTypeWithFallbackProvider { + getNodeType as getNodeTypeInternal; + } + #[Flow\Inject] protected ContentRepositoryRegistry $contentRepositoryRegistry; @@ -42,8 +50,8 @@ class NodeHelper implements ProtectedContextAwareInterface */ public function nearestContentCollection(Node $node, string $nodePath): Node { - $contentCollectionType = 'Neos.Neos:ContentCollection'; - if ($node->nodeType->isOfType($contentCollectionType)) { + $contentCollectionType = NodeTypeNameFactory::NAME_CONTENT_COLLECTION; + if ($this->isOfType($node, $contentCollectionType)) { return $node; } else { if ($nodePath === '') { @@ -63,7 +71,7 @@ public function nearestContentCollection(Node $node, string $nodePath): Node ? $subgraph->findNodeByAbsolutePath($nodePath) : $subgraph->findNodeByPath($nodePath, $node->nodeAggregateId); - if ($subNode !== null && $subNode->nodeType->isOfType($contentCollectionType)) { + if ($subNode !== null && $this->isOfType($subNode, $contentCollectionType)) { return $subNode; } else { $nodePathOfNode = VisualNodePath::fromAncestors( @@ -81,7 +89,7 @@ public function nearestContentCollection(Node $node, string $nodePath): Node $contentCollectionType, $nodePathOfNode->value, $nodePath->serializeToString(), - $node->nodeType->name->value + $node->nodeTypeName->value ), 1389352984); } } @@ -95,18 +103,6 @@ public function labelForNode(Node $node): NodeLabelToken return new NodeLabelToken($node); } - /** - * @param Node $node - * @return bool - * @deprecated Remove before Neos 9.0 !!! Use ${userInterfaceMode.isEdit || userInterfaceMode.isPreview} instead - */ - public function inBackend(Node $node): bool - { - $contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId); - $nodeAddressFactory = NodeAddressFactory::create($contentRepository); - return !$nodeAddressFactory->createFromNode($node)->isInLiveWorkspace(); - } - /** * @param Node $node * @return int @@ -132,24 +128,18 @@ public function path(Node $node): string return AbsoluteNodePath::fromLeafNodeAndAncestors($node, $ancestors)->serializeToString(); } - public function isLive(Node $node): bool - { - $contentRepository = $this->contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId); - $nodeAddressFactory = NodeAddressFactory::create($contentRepository); - return $nodeAddressFactory->createFromNode($node)->isInLiveWorkspace(); - } - /** * If this node type or any of the direct or indirect super types * has the given name. - * - * @param Node $node - * @param string $nodeType - * @return bool */ public function isOfType(Node $node, string $nodeType): bool { - return $node->nodeType->isOfType($nodeType); + return $this->getNodeTypeInternal($node)->isOfType($nodeType); + } + + public function getNodeType(Node $node): NodeType + { + return $this->getNodeTypeInternal($node); } public function serializedNodeAddress(Node $node): string @@ -161,6 +151,11 @@ public function serializedNodeAddress(Node $node): string return $nodeAddressFactory->createFromNode($node)->serializeForUri(); } + public function subgraphForNode(Node $node): ContentSubgraphInterface + { + return $this->contentRepositoryRegistry->subgraphForNode($node); + } + /** * @param string $methodName * @return boolean diff --git a/Neos.Neos/Classes/Fusion/Helper/NodeLabelToken.php b/Neos.Neos/Classes/Fusion/Helper/NodeLabelToken.php index b68638890f4..cf63385c03c 100644 --- a/Neos.Neos/Classes/Fusion/Helper/NodeLabelToken.php +++ b/Neos.Neos/Classes/Fusion/Helper/NodeLabelToken.php @@ -15,10 +15,12 @@ namespace Neos\Neos\Fusion\Helper; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Eel\Helper\StringHelper; use Neos\Eel\ProtectedContextAwareInterface; use Neos\Flow\Annotations as Flow; use Neos\Flow\I18n\EelHelper\TranslationHelper; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * Provides a chainable interface to build a label for a nodetype @@ -26,6 +28,11 @@ */ class NodeLabelToken implements ProtectedContextAwareInterface { + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** * @Flow\Inject * @var TranslationHelper @@ -140,9 +147,9 @@ public function evaluate(): string */ protected function resolveLabelFromNodeType(): void { - $this->label = $this->translationHelper->translate($this->node->nodeType->getLabel()) ?: ''; + $this->label = $this->translationHelper->translate($this->getNodeType($this->node)->getLabel()) ?: ''; if (empty($this->label)) { - $this->label = $this->node->nodeType->getName(); + $this->label = $this->node->nodeTypeName->value; } if (empty($this->postfix) && $this->node->nodeName !== null && $this->node->classification->isTethered()) { diff --git a/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php b/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php index 05e8a283d5f..c00989affe8 100644 --- a/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/SiteHelper.php @@ -14,16 +14,11 @@ namespace Neos\Neos\Fusion\Helper; -use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; -use Neos\Neos\Domain\Model\Site; -use Neos\Neos\Domain\Model\SiteNodeName; -use Neos\Neos\Domain\Repository\SiteRepository; -use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\Flow\Annotations as Flow; use Neos\Eel\ProtectedContextAwareInterface; -use Neos\Neos\Domain\Exception; +use Neos\Flow\Annotations as Flow; +use Neos\Neos\Domain\Model\Site; +use Neos\Neos\Domain\Repository\SiteRepository; /** * Eel helper for accessing the Site object @@ -36,17 +31,13 @@ class SiteHelper implements ProtectedContextAwareInterface */ protected $siteRepository; - /** - * - * @throws Exception - */ public function findBySiteNode(Node $siteNode): ?Site { - if ($siteNode->nodeName === null) { + try { + return $this->siteRepository->findSiteBySiteNode($siteNode); + } catch (\Neos\Neos\Domain\Exception) { return null; } - $siteNodeName = SiteNodeName::fromNodeName($siteNode->nodeName); - return $this->siteRepository->findOneByNodeName($siteNodeName); } /** diff --git a/Neos.Neos/Classes/Fusion/MenuItem.php b/Neos.Neos/Classes/Fusion/MenuItem.php index 86c23f1947d..59de848a70c 100644 --- a/Neos.Neos/Classes/Fusion/MenuItem.php +++ b/Neos.Neos/Classes/Fusion/MenuItem.php @@ -9,60 +9,19 @@ /** * A menu item */ -final class MenuItem +final readonly class MenuItem { - protected Node $node; - - protected ?MenuItemState $state; - - protected ?string $label; - - protected int $menuLevel; - - /** - * @var array - */ - protected array $children; - - protected ?string $uri; - /** * @param array $children */ public function __construct( - Node $node, - ?MenuItemState $state = null, - ?string $label = null, - int $menuLevel = 1, - array $children = [], - string $uri = null + public Node $node, + public ?MenuItemState $state = null, + public ?string $label = null, + public int $menuLevel = 1, + public array $children = [], + public ?string $uri = null ) { - $this->node = $node; - $this->state = $state; - $this->label = $label; - $this->menuLevel = $menuLevel; - $this->children = $children; - $this->uri = $uri; - } - - public function getNode(): Node - { - return $this->node; - } - - public function getState(): ?MenuItemState - { - return $this->state; - } - - public function getLabel(): ?string - { - return $this->label; - } - - public function getMenuLevel(): int - { - return $this->menuLevel; } /** @@ -75,7 +34,7 @@ public function getChildren(): array /** * @return array - * @deprecated Use getChildren instead + * @deprecated Use children instead */ public function getSubItems(): array { diff --git a/Neos.Neos/Classes/Fusion/MenuItemState.php b/Neos.Neos/Classes/Fusion/MenuItemState.php index 5bae271d731..2430cc3a75f 100644 --- a/Neos.Neos/Classes/Fusion/MenuItemState.php +++ b/Neos.Neos/Classes/Fusion/MenuItemState.php @@ -7,53 +7,10 @@ /** * The menu item state value object */ -final class MenuItemState +enum MenuItemState: string { - public const STATE_NORMAL = 'normal'; - public const STATE_CURRENT = 'current'; - public const STATE_ACTIVE = 'active'; - public const STATE_ABSENT = 'absent'; - - /** - * @var string - */ - protected $state; - - /** - * @param string $state - * @throws Exception\InvalidMenuItemStateException - */ - public function __construct(string $state) - { - if ( - $state !== self::STATE_NORMAL - && $state !== self::STATE_CURRENT - && $state !== self::STATE_ACTIVE - && $state !== self::STATE_ABSENT - ) { - throw new Exception\InvalidMenuItemStateException( - '"' . $state . '" is no valid menu item state', - 1519668881 - ); - } - - $this->state = $state; - } - - - /** - * @return MenuItemState - */ - public static function normal(): MenuItemState - { - return new MenuItemState(self::STATE_NORMAL); - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->state; - } + case NORMAL = 'normal'; + case CURRENT = 'current'; + case ACTIVE = 'active'; + case ABSENT = 'absent'; } diff --git a/Neos.Neos/Classes/Fusion/MenuItemsImplementation.php b/Neos.Neos/Classes/Fusion/MenuItemsImplementation.php index 57692489567..f88a11120b7 100644 --- a/Neos.Neos/Classes/Fusion/MenuItemsImplementation.php +++ b/Neos.Neos/Classes/Fusion/MenuItemsImplementation.php @@ -15,13 +15,17 @@ namespace Neos\Neos\Fusion; use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindAncestorNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSubtreeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTypeConstraints; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeTypeConstraintsWithSubNodeTypes; use Neos\ContentRepository\Core\Projection\ContentGraph\Subtree; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; use Neos\Fusion\Exception as FusionException; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; /** * A Fusion Menu object @@ -54,6 +58,11 @@ class MenuItemsImplementation extends AbstractMenuItemsImplementation */ protected $maximumLevels; + /** + * Internal cache for the ancestors aggregate ids of the currentNode. + */ + protected ?NodeAggregateIds $currentNodeAncestorAggregateIds = null; + /** * Runtime cache for the node type constraints to be applied */ @@ -86,7 +95,7 @@ public function getFilter() { $filter = $this->fusionValue('filter'); if ($filter === null) { - $filter = 'Neos.Neos:Document'; + $filter = NodeTypeNameFactory::NAME_DOCUMENT; } return $filter; @@ -199,7 +208,7 @@ protected function traverseChildren(Subtree $subtree): MenuItem return new MenuItem( $node, - MenuItemState::normal(), + $this->isCalculateItemStatesEnabled() ? $this->calculateItemState($node) : null, $node->getLabel(), $subtree->level, $children, @@ -231,6 +240,7 @@ protected function findMenuStartingPoint(): ?Node 1369596980 ); } + if ($this->getEntryLevel() === 0) { $entryParentNode = $traversalStartingPoint; } elseif ($this->getEntryLevel() < 0) { @@ -266,7 +276,7 @@ function (Node $node) use ( $traversedHierarchy = []; $nodeTypeConstraintsWithSubNodeTypes = NodeTypeConstraintsWithSubNodeTypes::create( $this->getNodeTypeConstraints()->withAdditionalDisallowedNodeType( - NodeTypeName::fromString('Neos.Neos:Sites') + NodeTypeNameFactory::forSites() ), $contentRepository->getNodeTypeManager() ); @@ -284,7 +294,6 @@ function (Node $traversedNode) use (&$traversedHierarchy, $nodeTypeConstraintsWi $entryParentNode = $traversedHierarchy[$this->getEntryLevel() - 1] ?? null; } - return $entryParentNode; } @@ -311,14 +320,30 @@ protected function traverseUpUntilCondition(Node $node, \Closure $callback): voi } while ($shouldContinueTraversal !== false && $node !== null); } - protected function buildUri(Node $node): string + public function getCurrentNodeAncestorAggregateIds(): NodeAggregateIds { - $this->runtime->pushContextArray([ - 'itemNode' => $node, - 'documentNode' => $node, - ]); - $uri = $this->runtime->render($this->path . '/itemUriRenderer'); - $this->runtime->popContext(); - return $uri; + if ($this->currentNodeAncestorAggregateIds instanceof NodeAggregateIds) { + return $this->currentNodeAncestorAggregateIds; + } + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($this->currentNode); + $currentNodeAncestors = $subgraph->findAncestorNodes( + $this->currentNode->nodeAggregateId, + FindAncestorNodesFilter::create( + $this->getNodeTypeConstraints() + ) + ); + $this->currentNodeAncestorAggregateIds = NodeAggregateIds::fromNodes($currentNodeAncestors); + return $this->currentNodeAncestorAggregateIds; + } + + protected function calculateItemState(Node $node): MenuItemState + { + if ($node->nodeAggregateId->equals($this->currentNode->nodeAggregateId)) { + return MenuItemState::CURRENT; + } + if ($this->getCurrentNodeAncestorAggregateIds()->contain($node->nodeAggregateId)) { + return MenuItemState::ACTIVE; + } + return MenuItemState::NORMAL; } } diff --git a/Neos.Neos/Classes/Fusion/PluginImplementation.php b/Neos.Neos/Classes/Fusion/PluginImplementation.php index fc9a0da7e74..43db3bcbdf2 100644 --- a/Neos.Neos/Classes/Fusion/PluginImplementation.php +++ b/Neos.Neos/Classes/Fusion/PluginImplementation.php @@ -198,7 +198,7 @@ protected function getPluginNamespace(): string return $nodeArgumentNamespace; } - $nodeArgumentNamespace = $this->node->nodeType->getName(); + $nodeArgumentNamespace = $this->node->nodeTypeName->value; $nodeArgumentNamespace = str_replace(':', '-', $nodeArgumentNamespace); $nodeArgumentNamespace = str_replace('.', '_', $nodeArgumentNamespace); $nodeArgumentNamespace = strtolower($nodeArgumentNamespace); diff --git a/Neos.Neos/Classes/NodeTypePostprocessor/DefaultPropertyEditorPostprocessor.php b/Neos.Neos/Classes/NodeTypePostprocessor/DefaultPropertyEditorPostprocessor.php index 1e1bd397c98..5011dff1227 100644 --- a/Neos.Neos/Classes/NodeTypePostprocessor/DefaultPropertyEditorPostprocessor.php +++ b/Neos.Neos/Classes/NodeTypePostprocessor/DefaultPropertyEditorPostprocessor.php @@ -47,7 +47,7 @@ class DefaultPropertyEditorPostprocessor implements NodeTypePostprocessorInterfa */ public function process(NodeType $nodeType, array &$configuration, array $options): void { - $nodeTypeName = $nodeType->getName(); + $nodeTypeName = $nodeType->name->value; if (isset($configuration['properties']) && is_array($configuration['properties'])) { foreach ($configuration['properties'] as $propertyName => &$propertyConfiguration) { if (!isset($propertyConfiguration['type'])) { diff --git a/Neos.Neos/Classes/Routing/Cache/RouteCacheFlusher.php b/Neos.Neos/Classes/Routing/Cache/RouteCacheFlusher.php index be49d9cf6cf..14507af46af 100644 --- a/Neos.Neos/Classes/Routing/Cache/RouteCacheFlusher.php +++ b/Neos.Neos/Classes/Routing/Cache/RouteCacheFlusher.php @@ -16,8 +16,11 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\Routing\RouterCachingService; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * This service flushes Route caches triggered by node changes. @@ -26,6 +29,11 @@ */ class RouteCacheFlusher { + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** * @Flow\Inject * @var RouterCachingService @@ -50,7 +58,7 @@ public function registerNodeChange(Node $node) if (in_array($identifier, $this->tagsToFlush)) { return; } - if (!$node->nodeType->isOfType('Neos.Neos:Document')) { + if (!$this->getNodeType($node)->isOfType(NodeTypeNameFactory::NAME_DOCUMENT)) { return; } $this->tagsToFlush[] = $identifier; diff --git a/Neos.Neos/Classes/Security/Authorization/Privilege/NodeTreePrivilege.php b/Neos.Neos/Classes/Security/Authorization/Privilege/NodeTreePrivilege.php deleted file mode 100644 index 9ccd5bff3ae..00000000000 --- a/Neos.Neos/Classes/Security/Authorization/Privilege/NodeTreePrivilege.php +++ /dev/null @@ -1,25 +0,0 @@ -authenticate())") @@ -61,8 +60,7 @@ public function logManagerAuthenticate(JoinPointInterface $joinPoint): void return; } - /** @phpstan-ignore-next-line might still be null in strange Flow DI cases */ - if ($this->impersonateService && $this->impersonateService->isActive()) { + if ($this->impersonateService->isActive()) { $impersonation = $this->impersonateService->getImpersonation(); foreach ($proxy->getSecurityContext()->getAuthenticationTokens() as $token) { $token->setAccount($impersonation); diff --git a/Neos.Neos/Classes/Service/BackendRedirectionService.php b/Neos.Neos/Classes/Service/BackendRedirectionService.php index 0b8072ba1c0..dd321794071 100644 --- a/Neos.Neos/Classes/Service/BackendRedirectionService.php +++ b/Neos.Neos/Classes/Service/BackendRedirectionService.php @@ -136,54 +136,4 @@ protected function determineStartModule(array $availableModules): ?array return $firstModule; } - - /** - * Returns a specific URI string to redirect to after the logout; or NULL if there is none. - * In case of NULL, it's the responsibility of the AuthenticationController where to redirect, - * most likely to the LoginController's index action. - * - * @param ActionRequest $actionRequest - * @return string A possible redirection URI, if any - * @throws \Neos\Flow\Http\Exception - * @throws MissingActionNameException - */ - public function getAfterLogoutRedirectionUri(ActionRequest $actionRequest): ?string - { - $lastVisitedNode = $this->getLastVisitedNode('live', $actionRequest); - if ($lastVisitedNode === null) { - return null; - } - $uriBuilder = new UriBuilder(); - $uriBuilder->setRequest($actionRequest); - $uriBuilder->setFormat('html'); - $uriBuilder->setCreateAbsoluteUri(true); - - return $uriBuilder->uriFor('show', ['node' => $lastVisitedNode], 'Frontend\\Node', 'Neos.Neos'); - } - - protected function getLastVisitedNode(string $workspaceName, ActionRequest $actionRequest): ?Node - { - $contentRepositoryId = SiteDetectionResult::fromRequest($actionRequest->getHttpRequest()) - ->contentRepositoryId; - $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::fromString($workspaceName)); - if (!$workspace || !$this->session->isStarted() || !$this->session->hasKey('lastVisitedNode')) { - return null; - } - try { - /** @var Node $lastVisitedNode */ - $lastVisitedNode = $this->propertyMapper->convert( - $this->session->getData('lastVisitedNode'), - Node::class - ); - - return $contentRepository->getContentGraph()->getSubgraph( - $workspace->currentContentStreamId, - $lastVisitedNode->subgraphIdentity->dimensionSpacePoint, - VisibilityConstraints::withoutRestrictions() - )->findNodeById($lastVisitedNode->nodeAggregateId); - } catch (\Exception $exception) { - return null; - } - } } diff --git a/Neos.Neos/Classes/Service/ContentElementEditableService.php b/Neos.Neos/Classes/Service/ContentElementEditableService.php index 07a2bfe2c2b..811dc634a65 100644 --- a/Neos.Neos/Classes/Service/ContentElementEditableService.php +++ b/Neos.Neos/Classes/Service/ContentElementEditableService.php @@ -21,7 +21,6 @@ use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Security\Authorization\PrivilegeManagerInterface; -use Neos\ContentRepository\Security\Service\AuthorizationService; use Neos\Fusion\Service\HtmlAugmenter as FusionHtmlAugmenter; /** @@ -39,12 +38,6 @@ class ContentElementEditableService */ protected $privilegeManager; - /** - * @Flow\Inject - * @var AuthorizationService - */ - protected $nodeAuthorizationService; - /** * @Flow\Inject * @var FusionHtmlAugmenter diff --git a/Neos.Neos/Classes/Service/ContentElementWrappingService.php b/Neos.Neos/Classes/Service/ContentElementWrappingService.php index 6d4efa18127..4851b49da2e 100644 --- a/Neos.Neos/Classes/Service/ContentElementWrappingService.php +++ b/Neos.Neos/Classes/Service/ContentElementWrappingService.php @@ -16,7 +16,6 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; -use Neos\ContentRepository\Security\Service\AuthorizationService; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; @@ -24,7 +23,6 @@ use Neos\Flow\Security\Authorization\PrivilegeManagerInterface; use Neos\Flow\Session\SessionInterface; use Neos\Fusion\Service\HtmlAugmenter as FusionHtmlAugmenter; -use Neos\Neos\Domain\Model\NodeCacheEntryIdentifier; use Neos\Neos\Ui\Domain\Service\UserLocaleService; use Neos\Neos\Ui\Fusion\Helper\NodeInfoHelper; @@ -43,12 +41,6 @@ class ContentElementWrappingService */ protected $privilegeManager; - /** - * @Flow\Inject - * @var AuthorizationService - */ - protected $nodeAuthorizationService; - /** * @Flow\Inject * @var FusionHtmlAugmenter @@ -187,7 +179,7 @@ protected function needsMetadata( $contentRepository ) && ($renderCurrentDocumentMetadata === true - || $this->nodeAuthorizationService->isGrantedToEditNode($node) === true); + /* TODO: permissions || $this->nodeAuthorizationService->isGrantedToEditNode($node) === true */); } private function isContentStreamOfLiveWorkspace( diff --git a/Neos.Neos/Classes/Service/EditorContentStreamZookeeper.php b/Neos.Neos/Classes/Service/EditorContentStreamZookeeper.php index 16054d16bae..0dfcea7ee4d 100644 --- a/Neos.Neos/Classes/Service/EditorContentStreamZookeeper.php +++ b/Neos.Neos/Classes/Service/EditorContentStreamZookeeper.php @@ -17,22 +17,22 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace; use Neos\ContentRepository\Core\Projection\Workspace\Workspace; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\User\UserId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceTitle; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\ContentRepositoryRegistry\Factory\ProjectionCatchUpTrigger\CatchUpTriggerWithSynchronousOption; +use Neos\Flow\Annotations as Flow; use Neos\Flow\Core\Bootstrap; use Neos\Flow\Http\HttpRequestHandlerInterface; -use Neos\Neos\Domain\Model\WorkspaceName as AdjustmentsWorkspaceName; -use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\PersistenceManagerInterface; use Neos\Flow\Security\Authentication; use Neos\Flow\Security\Policy\PolicyService; use Neos\Flow\Security\Policy\Role; use Neos\Neos\Domain\Model\User; +use Neos\Neos\Domain\Service\WorkspaceNameBuilder; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; use Neos\Party\Domain\Service\PartyService; @@ -102,48 +102,38 @@ public function relayEditorAuthentication(Authentication\TokenInterface $token): break; } } - - if ($isEditor) { - $user = $this->partyService->getAssignedPartyOfAccount($token->getAccount()); - if ($user instanceof User) { - $workspaceName = AdjustmentsWorkspaceName::fromAccountIdentifier( - $token->getAccount()->getAccountIdentifier() - ); - $workspace = $contentRepository->getWorkspaceFinder()->findOneByName( - $workspaceName->toContentRepositoryWorkspaceName() - ); - - if (!$workspace) { - // @todo: find base workspace for user - /** @var Workspace $baseWorkspace */ - $baseWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); - $editorsNewContentStreamId = ContentStreamId::create(); - $similarlyNamedWorkspaces = $contentRepository->getWorkspaceFinder()->findByPrefix( - $workspaceName->toContentRepositoryWorkspaceName() - ); - if (!empty($similarlyNamedWorkspaces)) { - $workspaceName = $workspaceName->increment($similarlyNamedWorkspaces); - } - - $contentRepository->handle( - CreateWorkspace::create( - $workspaceName->toContentRepositoryWorkspaceName(), - $baseWorkspace->workspaceName, - new WorkspaceTitle((string) $user->getName()), - new WorkspaceDescription(''), - $editorsNewContentStreamId, - UserId::fromString($this->persistenceManager->getIdentifierByObject($user)) - ) - )->block(); - } else { - CatchUpTriggerWithSynchronousOption::synchronously(fn() => - $contentRepository->handle( - RebaseWorkspace::create( - $workspace->workspaceName, - ) - )->block()); - } - } + if (!$isEditor) { + return; + } + $user = $this->partyService->getAssignedPartyOfAccount($token->getAccount()); + if (!$user instanceof User) { + return; } + $workspaceName = WorkspaceNameBuilder::fromAccountIdentifier( + $token->getAccount()->getAccountIdentifier() + ); + $workspace = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName); + if ($workspace !== null) { + CatchUpTriggerWithSynchronousOption::synchronously(fn() => $contentRepository->handle( + RebaseWorkspace::create( + $workspace->workspaceName, + ) + )->block()); + return; + } + + /** @var Workspace $baseWorkspace */ + $baseWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); + $editorsNewContentStreamId = ContentStreamId::create(); + $contentRepository->handle( + CreateWorkspace::create( + $workspaceName, + $baseWorkspace->workspaceName, + new WorkspaceTitle((string) $user->getName()), + new WorkspaceDescription(''), + $editorsNewContentStreamId, + UserId::fromString($this->persistenceManager->getIdentifierByObject($user)) + ) + )->block(); } } diff --git a/Neos.Neos/Classes/Service/Mapping/NodeTypeStringConverter.php b/Neos.Neos/Classes/Service/Mapping/NodeTypeStringConverter.php index d525b32fb54..faab7553e7d 100644 --- a/Neos.Neos/Classes/Service/Mapping/NodeTypeStringConverter.php +++ b/Neos.Neos/Classes/Service/Mapping/NodeTypeStringConverter.php @@ -59,7 +59,7 @@ public function convertFrom( PropertyMappingConfigurationInterface $configuration = null ) { if ($source instanceof NodeType) { - return $source->getName(); + return $source->name->value; } return ''; diff --git a/Neos.Neos/Classes/Service/NodeTypeSchemaBuilder.php b/Neos.Neos/Classes/Service/NodeTypeSchemaBuilder.php index f3a96315ec6..b48f920c261 100644 --- a/Neos.Neos/Classes/Service/NodeTypeSchemaBuilder.php +++ b/Neos.Neos/Classes/Service/NodeTypeSchemaBuilder.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeType; +use Neos\ContentRepository\Core\SharedModel\Node\NodeName; /** * Renders the Node Type Schema in a format the User Interface understands; @@ -71,9 +72,9 @@ public function generateNodeTypeSchema() } $schema['inheritanceMap']['subTypes'][$nodeTypeName] = []; - foreach ($this->nodeTypeManager->getSubNodeTypes($nodeType->getName(), true) as $subNodeType) { + foreach ($this->nodeTypeManager->getSubNodeTypes($nodeType->name, true) as $subNodeType) { /** @var NodeType $subNodeType */ - $schema['inheritanceMap']['subTypes'][$nodeTypeName][] = $subNodeType->getName(); + $schema['inheritanceMap']['subTypes'][$nodeTypeName][] = $subNodeType->name->value; } } @@ -104,9 +105,9 @@ protected function generateConstraints() } } - foreach ($nodeType->getAutoCreatedChildNodes() as $key => $_x) { + foreach ($this->nodeTypeManager->getTetheredNodesConfigurationForNodeType($nodeType) as $key => $_x) { foreach ($nodeTypes as $innerNodeTypeName => $innerNodeType) { - if ($nodeType->allowsGrandchildNodeType($key, $innerNodeType)) { + if ($this->nodeTypeManager->isNodeTypeAllowedAsChildToTetheredNode($nodeType, NodeName::fromString($key), $innerNodeType)) { $constraints[$nodeTypeName]['childNodes'][$key]['nodeTypes'][$innerNodeTypeName] = true; } } diff --git a/Neos.Neos/Classes/Utility/NodeTypeWithFallbackProvider.php b/Neos.Neos/Classes/Utility/NodeTypeWithFallbackProvider.php new file mode 100644 index 00000000000..5cc304c3fc1 --- /dev/null +++ b/Neos.Neos/Classes/Utility/NodeTypeWithFallbackProvider.php @@ -0,0 +1,27 @@ +contentRepositoryRegistry->get($node->subgraphIdentity->contentRepositoryId)->getNodeTypeManager(); + + return $nodeTypeManager->hasNodeType($node->nodeTypeName) + ? $nodeTypeManager->getNodeType($node->nodeTypeName) + : $nodeTypeManager->getNodeType(NodeTypeNameFactory::forFallback()); + } +} diff --git a/Neos.Neos/Classes/Utility/User.php b/Neos.Neos/Classes/Utility/User.php index 051eedb8fb5..9ecaaf1d110 100644 --- a/Neos.Neos/Classes/Utility/User.php +++ b/Neos.Neos/Classes/Utility/User.php @@ -2,27 +2,31 @@ namespace Neos\Neos\Utility; -use Neos\Neos\Domain\Model\WorkspaceName; +use Neos\Neos\Domain\Service\WorkspaceNameBuilder; /** * Utility functions for dealing with users in the Content Repository. + * + * @deprecated with Neos 9.0 please use the respective replacements instead. */ class User { /** * Constructs a personal workspace name for the user with the given username. * + * @deprecated with Neos 9.0 please use {@see WorkspaceNameBuilder::fromAccountIdentifier} instead. * @param string $username * @return string */ public static function getPersonalWorkspaceNameForUsername($username): string { - return (string)WorkspaceName::fromAccountIdentifier($username); + return WorkspaceNameBuilder::fromAccountIdentifier($username)->value; } /** * Will reduce the username to ascii alphabet and numbers. * + * @deprecated with Neos 9.0 please implement your own slug genration. You might also want to look into transliteration with {@see \Behat\Transliterator\Transliterator}. * @param string $username * @return string */ diff --git a/Neos.Neos/Classes/View/FusionExceptionView.php b/Neos.Neos/Classes/View/FusionExceptionView.php index 5176990ff4b..4406031ca8c 100644 --- a/Neos.Neos/Classes/View/FusionExceptionView.php +++ b/Neos.Neos/Classes/View/FusionExceptionView.php @@ -14,10 +14,8 @@ namespace Neos\Neos\View; -use GuzzleHttp\Psr7\ServerRequest; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; @@ -36,10 +34,10 @@ use Neos\Fusion\Core\RuntimeFactory; use Neos\Fusion\Exception\RuntimeException; use Neos\Neos\Domain\Model\RenderingMode; +use Neos\Neos\Domain\Repository\DomainRepository; use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; use Neos\Neos\Domain\Service\SiteNodeUtility; -use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\FrontendRouting\SiteDetection\SiteDetectionResult; class FusionExceptionView extends AbstractView @@ -90,7 +88,7 @@ class FusionExceptionView extends AbstractView protected ContentRepositoryRegistry $contentRepositoryRegistry; #[Flow\Inject] - protected RenderingModeService $userInterfaceModeService; + protected DomainRepository $domainRepository; /** * @return string @@ -102,9 +100,12 @@ class FusionExceptionView extends AbstractView public function render() { $requestHandler = $this->bootstrap->getActiveRequestHandler(); - $httpRequest = $requestHandler instanceof HttpRequestHandler - ? $requestHandler->getHttpRequest() - : ServerRequest::fromGlobals(); + + if (!$requestHandler instanceof HttpRequestHandler) { + throw new \RuntimeException('The FusionExceptionView only works in web requests.', 1695975353); + } + + $httpRequest = $requestHandler->getHttpRequest(); $siteDetectionResult = SiteDetectionResult::fromRequest($httpRequest); $contentRepository = $this->contentRepositoryRegistry->get($siteDetectionResult->contentRepositoryId); @@ -114,14 +115,14 @@ public function render() ); $dimensionSpacePoint = $fusionExceptionViewInternals->getArbitraryDimensionSpacePoint(); - $contentStreamId = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()) - ?->currentContentStreamId; + $liveWorkspace = $contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); $currentSiteNode = null; - if ($contentStreamId instanceof ContentStreamId) { - $currentSiteNode = $this->siteNodeUtility->findCurrentSiteNode( - $siteDetectionResult->contentRepositoryId, - $contentStreamId, + $site = $this->siteRepository->findOneByNodeName($siteDetectionResult->siteNodeName); + if ($liveWorkspace && $site) { + $currentSiteNode = $this->siteNodeUtility->findSiteNodeBySite( + $site, + $liveWorkspace->currentContentStreamId, $dimensionSpacePoint, VisibilityConstraints::frontend() ); @@ -160,13 +161,12 @@ public function render() try { $output = $fusionRuntime->render('error'); - $output = $this->extractBodyFromOutput($output); + return $this->extractBodyFromOutput($output); } catch (RuntimeException $exception) { throw $exception->getPrevious() ?: $exception; + } finally { + $fusionRuntime->popContext(); } - $fusionRuntime->popContext(); - - return $output; } return ''; @@ -204,14 +204,14 @@ protected function getFusionRuntime( $fusionConfiguration = $this->fusionService->createFusionConfigurationFromSite($site); $fusionGlobals = FusionGlobals::fromArray([ - 'request' => $this->controllerContext->getRequest(), + 'request' => $controllerContext->getRequest(), 'renderingModeName' => RenderingMode::FRONTEND ]); $this->fusionRuntime = $this->runtimeFactory->createFromConfiguration( $fusionConfiguration, $fusionGlobals ); - $this->fusionRuntime->setControllerContext($this->controllerContext); + $this->fusionRuntime->setControllerContext($controllerContext); if (isset($this->options['enableContentCache']) && $this->options['enableContentCache'] !== null) { $this->fusionRuntime->setEnableContentCache($this->options['enableContentCache']); diff --git a/Neos.Neos/Classes/View/FusionView.php b/Neos.Neos/Classes/View/FusionView.php index e9c2ba43ab7..c507576e069 100644 --- a/Neos.Neos/Classes/View/FusionView.php +++ b/Neos.Neos/Classes/View/FusionView.php @@ -15,6 +15,7 @@ namespace Neos\Neos\View; use GuzzleHttp\Psr7\Message; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; @@ -27,9 +28,10 @@ use Neos\Neos\Domain\Model\RenderingMode; use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService; -use Neos\Neos\Domain\Service\SiteNodeUtility; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\Domain\Service\RenderingModeService; use Neos\Neos\Exception; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; use Psr\Http\Message\ResponseInterface; /** @@ -38,12 +40,10 @@ class FusionView extends AbstractView { use FusionViewI18nTrait; + use NodeTypeWithFallbackProvider; - /** - * @Flow\Inject - * @var SiteNodeUtility - */ - protected $siteNodeUtility; + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; #[Flow\Inject] protected RuntimeFactory $runtimeFactory; @@ -54,12 +54,6 @@ class FusionView extends AbstractView #[Flow\Inject] protected RenderingModeService $renderingModeService; - /** - * @Flow\Inject - * @var ContentRepositoryRegistry - */ - protected $contentRepositoryRegistry; - /** * Renders the view * @@ -71,7 +65,13 @@ public function render(): string|ResponseInterface { $currentNode = $this->getCurrentNode(); - $currentSiteNode = $this->siteNodeUtility->findSiteNode($currentNode); + $subgraph = $this->contentRepositoryRegistry->subgraphForNode($currentNode); + $currentSiteNode = $subgraph->findClosestNode($currentNode->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_SITE)); + + if (!$currentSiteNode) { + throw new \RuntimeException('No site node found!', 1697053346); + } + $fusionRuntime = $this->getFusionRuntime($currentSiteNode); $fusionRuntime->pushContextArray([ @@ -195,12 +195,8 @@ public function getFusionPath() protected function getClosestDocumentNode(Node $node): ?Node { - $subgraph = $this->contentRepositoryRegistry->subgraphForNode($node); - while ($node !== null && !$node->nodeType->isOfType('Neos.Neos:Document')) { - $node = $subgraph->findParentNode($node->nodeAggregateId); - } - - return $node; + return $this->contentRepositoryRegistry->subgraphForNode($node) + ->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); } /** diff --git a/Neos.Neos/Classes/ViewHelpers/Backend/DocumentBreadcrumbPathViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Backend/DocumentBreadcrumbPathViewHelper.php index 6505fe97b78..4ca88d29f08 100644 --- a/Neos.Neos/Classes/ViewHelpers/Backend/DocumentBreadcrumbPathViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Backend/DocumentBreadcrumbPathViewHelper.php @@ -18,23 +18,24 @@ use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * Render a bread crumb path by using the labels of documents leading to the given node path */ class DocumentBreadcrumbPathViewHelper extends AbstractViewHelper { + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; + /** * @var boolean */ protected $escapeOutput = false; - /** - * @Flow\Inject - * @var ContentRepositoryRegistry - */ - protected $contentRepositoryRegistry; - public function initializeArguments(): void { parent::initializeArguments(); @@ -50,7 +51,7 @@ public function render(): mixed $currentNode = $node; while ($currentNode instanceof Node) { - if ($currentNode->nodeType->isOfType('Neos.Neos:Document')) { + if ($this->getNodeType($currentNode)->isOfType(NodeTypeNameFactory::NAME_DOCUMENT)) { $documentNodes[] = $currentNode; } $currentNode = $subgraph->findParentNode($currentNode->nodeAggregateId); diff --git a/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php index d2885f59ed4..bb81fab4a05 100644 --- a/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Link/NodeViewHelper.php @@ -18,10 +18,11 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\Projection\ContentGraph\NodePath; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\FrontendRouting\NodeAddress; use Neos\Neos\FrontendRouting\NodeAddressFactory; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Http\Exception as HttpException; use Neos\Flow\Log\ThrowableStorageInterface; @@ -36,6 +37,7 @@ use Neos\Neos\FrontendRouting\Exception\NodeNotFoundException; use Neos\Neos\FrontendRouting\NodeShortcutResolver; use Neos\Neos\FrontendRouting\NodeUriBuilder; +use Neos\Neos\Utility\NodeTypeWithFallbackProvider; /** * A view helper for creating links with URIs pointing to nodes. @@ -125,6 +127,10 @@ class NodeViewHelper extends AbstractTagBasedViewHelper { use FusionContextTrait; + use NodeTypeWithFallbackProvider; + + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; /** * @var string @@ -143,12 +149,6 @@ class NodeViewHelper extends AbstractTagBasedViewHelper */ protected $nodeShortcutResolver; - /** - * @Flow\Inject - * @var ContentRepositoryRegistry - */ - protected $contentRepositoryRegistry; - /** * @Flow\Inject * @var ThrowableStorageInterface @@ -298,7 +298,7 @@ public function render(): string json_encode($subgraph, JSON_PARTIAL_OUTPUT_ON_ERROR) ), 1601372444)); } - if ($resolvedNode && $resolvedNode->nodeType->isOfType('Neos.Neos:Shortcut')) { + if ($resolvedNode && $this->getNodeType($resolvedNode)->isOfType(NodeTypeNameFactory::NAME_SHORTCUT)) { try { $shortcutNodeAddress = $this->nodeShortcutResolver->resolveShortcutTarget( $nodeAddress, diff --git a/Neos.Neos/Classes/ViewHelpers/Node/ClosestDocumentViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Node/ClosestDocumentViewHelper.php index cb0a9bdbc65..2a56aa07627 100644 --- a/Neos.Neos/Classes/ViewHelpers/Node/ClosestDocumentViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Node/ClosestDocumentViewHelper.php @@ -14,21 +14,20 @@ namespace Neos\Neos\ViewHelpers\Node; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindClosestNodeFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; -use Neos\Neos\Ui\ContentRepository\Service\NodeService; +use Neos\Neos\Domain\Service\NodeTypeNameFactory; /** * ViewHelper to find the closest document node to a given node */ class ClosestDocumentViewHelper extends AbstractViewHelper { - /** - * @Flow\Inject - * @var NodeService - */ - protected $nodeService; + #[Flow\Inject] + protected ContentRepositoryRegistry $contentRepositoryRegistry; public function initializeArguments(): void { @@ -38,6 +37,10 @@ public function initializeArguments(): void public function render(): ?Node { - return $this->nodeService->getClosestDocument($this->arguments['node']); + /** @var Node $node */ + $node = $this->arguments['node']; + + return $this->contentRepositoryRegistry->subgraphForNode($node) + ->findClosestNode($node->nodeAggregateId, FindClosestNodeFilter::create(nodeTypeConstraints: NodeTypeNameFactory::NAME_DOCUMENT)); } } diff --git a/Neos.Neos/Classes/ViewHelpers/Rendering/AbstractRenderingStateViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Rendering/AbstractRenderingStateViewHelper.php deleted file mode 100644 index 8fe7291cdad..00000000000 --- a/Neos.Neos/Classes/ViewHelpers/Rendering/AbstractRenderingStateViewHelper.php +++ /dev/null @@ -1,96 +0,0 @@ -contentRepositoryRegistry->get( - $node->subgraphIdentity->contentRepositoryId - ); - return NodeAddressFactory::create($contentRepository)->createFromNode($node); - } - - $baseNode = null; - $view = $this->viewHelperVariableContainer->getView(); - if ($view instanceof FusionAwareViewInterface) { - $fusionObject = $view->getFusionObject(); - $currentContext = $fusionObject->getRuntime()->getCurrentContext(); - if (isset($currentContext['node'])) { - $baseNode = $currentContext['node']; - } - } - if ($baseNode === null) { - throw new ViewHelperException( - 'The ' . get_class($this) . ' needs a Node to determine the state.' - . ' We could not find one in your context so please provide it as "node" argument to the ViewHelper.', - 1427267133 - ); - } - /** @var Node $baseNode */ - $contentRepository = $this->contentRepositoryRegistry->get( - $baseNode->subgraphIdentity->contentRepositoryId - ); - return NodeAddressFactory::create($contentRepository)->createFromNode($baseNode); - } - - - protected function hasAccessToBackend(): bool - { - try { - return $this->privilegeManager->isPrivilegeTargetGranted('Neos.Neos:Backend.GeneralAccess'); - } catch (Exception $exception) { - return false; - } - } -} diff --git a/Neos.Neos/Classes/ViewHelpers/Rendering/InBackendViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Rendering/InBackendViewHelper.php index e7565bcdf60..cc56d427269 100644 --- a/Neos.Neos/Classes/ViewHelpers/Rendering/InBackendViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Rendering/InBackendViewHelper.php @@ -14,7 +14,9 @@ namespace Neos\Neos\ViewHelpers\Rendering; -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; +use Neos\Fusion\ViewHelpers\FusionContextTrait; +use Neos\Neos\Domain\Model\RenderingMode; /** * ViewHelper to find out if Neos is rendering the backend. @@ -37,19 +39,9 @@ * Shown in the backend. * */ -class InBackendViewHelper extends AbstractRenderingStateViewHelper +class InBackendViewHelper extends AbstractViewHelper { - /** - * Initialize the arguments. - * - * @return void - * @throws \Neos\FluidAdaptor\Core\ViewHelper\Exception - */ - public function initializeArguments() - { - parent::initializeArguments(); - $this->registerArgument('node', Node::class, 'Node'); - } + use FusionContextTrait; /** * @return boolean @@ -57,7 +49,10 @@ public function initializeArguments() */ public function render() { - $nodeAddress = $this->getNodeAddressOfContextNode($this->arguments['node']); - return (!$nodeAddress->isInLiveWorkspace() && $this->hasAccessToBackend()); + $renderingMode = $this->getContextVariable('renderingMode'); + if ($renderingMode instanceof RenderingMode) { + return $renderingMode->isEdit || $renderingMode->isPreview; + } + return false; } } diff --git a/Neos.Neos/Classes/ViewHelpers/Rendering/InEditModeViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Rendering/InEditModeViewHelper.php index 6d4f9ece5c1..3104fd71919 100644 --- a/Neos.Neos/Classes/ViewHelpers/Rendering/InEditModeViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Rendering/InEditModeViewHelper.php @@ -15,6 +15,9 @@ namespace Neos\Neos\ViewHelpers\Rendering; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; +use Neos\Fusion\ViewHelpers\FusionContextTrait; +use Neos\Neos\Domain\Model\RenderingMode; /** * ViewHelper to find out if Neos is rendering an edit mode. @@ -55,8 +58,10 @@ * Shown in all other cases. * */ -class InEditModeViewHelper extends AbstractRenderingStateViewHelper +class InEditModeViewHelper extends AbstractViewHelper { + use FusionContextTrait; + /** * Initialize the arguments. * @@ -66,11 +71,6 @@ class InEditModeViewHelper extends AbstractRenderingStateViewHelper public function initializeArguments() { parent::initializeArguments(); - $this->registerArgument( - 'node', - Node::class, - 'Optional Node to use context from' - ); $this->registerArgument( 'mode', 'string', @@ -84,7 +84,14 @@ public function initializeArguments() */ public function render() { - // TODO: implement + $renderingMode = $this->getContextVariable('renderingMode'); + if ($renderingMode instanceof RenderingMode) { + $mode = $this->arguments['mode']; + if ($mode) { + return $renderingMode->isEdit && $renderingMode->name === $mode; + } + return $renderingMode->isEdit; + } return false; } } diff --git a/Neos.Neos/Classes/ViewHelpers/Rendering/InPreviewModeViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Rendering/InPreviewModeViewHelper.php index 480bb4d30f8..831395f256c 100644 --- a/Neos.Neos/Classes/ViewHelpers/Rendering/InPreviewModeViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Rendering/InPreviewModeViewHelper.php @@ -15,6 +15,9 @@ namespace Neos\Neos\ViewHelpers\Rendering; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; +use Neos\Fusion\ViewHelpers\FusionContextTrait; +use Neos\Neos\Domain\Model\RenderingMode; /** * ViewHelper to find out if Neos is rendering a preview mode. @@ -55,8 +58,10 @@ * Shown in all other cases. * */ -class InPreviewModeViewHelper extends AbstractRenderingStateViewHelper +class InPreviewModeViewHelper extends AbstractViewHelper { + use FusionContextTrait; + /** * Initialize the arguments. * @@ -66,11 +71,6 @@ class InPreviewModeViewHelper extends AbstractRenderingStateViewHelper public function initializeArguments() { parent::initializeArguments(); - $this->registerArgument( - 'node', - Node::class, - 'Optional Node to use context from' - ); $this->registerArgument( 'mode', 'string', @@ -80,7 +80,14 @@ public function initializeArguments() public function render(Node $node = null, string $mode = null): bool { - // TODO: implement + $renderingMode = $this->getContextVariable('renderingMode'); + if ($renderingMode instanceof RenderingMode) { + $mode = $this->arguments['mode']; + if ($mode) { + return $renderingMode->isPreview && $renderingMode->name === $mode; + } + return $renderingMode->isPreview; + } return false; } } diff --git a/Neos.Neos/Classes/ViewHelpers/Rendering/LiveViewHelper.php b/Neos.Neos/Classes/ViewHelpers/Rendering/LiveViewHelper.php index 597221bd3ad..41e1452fc12 100644 --- a/Neos.Neos/Classes/ViewHelpers/Rendering/LiveViewHelper.php +++ b/Neos.Neos/Classes/ViewHelpers/Rendering/LiveViewHelper.php @@ -15,6 +15,9 @@ namespace Neos\Neos\ViewHelpers\Rendering; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\FluidAdaptor\Core\ViewHelper\AbstractViewHelper; +use Neos\Fusion\ViewHelpers\FusionContextTrait; +use Neos\Neos\Domain\Model\RenderingMode; /** * ViewHelper to find out if Neos is rendering the live website. @@ -39,27 +42,19 @@ * Shown in the backend. * */ -class LiveViewHelper extends AbstractRenderingStateViewHelper +class LiveViewHelper extends AbstractViewHelper { - /** - * Initialize the arguments. - * - * @return void - * @throws \Neos\FluidAdaptor\Core\ViewHelper\Exception - */ - public function initializeArguments() - { - parent::initializeArguments(); - $this->registerArgument('node', Node::class, 'Node'); - } + use FusionContextTrait; /** * @throws \Neos\FluidAdaptor\Core\ViewHelper\Exception */ public function render(): bool { - $nodeAddress = $this->getNodeAddressOfContextNode($this->arguments['node']); - - return $nodeAddress->isInLiveWorkspace(); + $renderingMode = $this->getContextVariable('renderingMode'); + if ($renderingMode instanceof RenderingMode) { + return $renderingMode->name === RenderingMode::FRONTEND; + } + return true; } } diff --git a/Neos.Neos/Configuration/NodeTypes.Sites.yaml b/Neos.Neos/Configuration/NodeTypes.Sites.yaml deleted file mode 100644 index fa2556e5904..00000000000 --- a/Neos.Neos/Configuration/NodeTypes.Sites.yaml +++ /dev/null @@ -1,3 +0,0 @@ -'Neos.Neos:Sites': - superTypes: - 'Neos.ContentRepository:Root': true diff --git a/Neos.Neos/Configuration/Objects.yaml b/Neos.Neos/Configuration/Objects.yaml index 6af4b7726b6..fdc548b70fe 100644 --- a/Neos.Neos/Configuration/Objects.yaml +++ b/Neos.Neos/Configuration/Objects.yaml @@ -31,10 +31,6 @@ Neos\Neos\FrontendRouting\Projection\DocumentUriPathFinder: factoryObjectName: 'Doctrine\ORM\EntityManagerInterface' factoryMethodName: 'getConnection' - -Neos\Neos\Domain\Service\NodeSearchServiceInterface: - className: Neos\Neos\Domain\Service\NodeSearchService - Neos\Neos\Service\XliffService: properties: xliffToJsonTranslationsCache: diff --git a/Neos.Neos/Configuration/Policy.yaml b/Neos.Neos/Configuration/Policy.yaml index 004c42eee77..6fb5d917727 100644 --- a/Neos.Neos/Configuration/Policy.yaml +++ b/Neos.Neos/Configuration/Policy.yaml @@ -154,10 +154,6 @@ privilegeTargets: label: General access to the workspace module matcher: 'management/workspaces' - 'Neos.Neos:Backend.Module.Management.History': - label: General access to the history module - matcher: 'management/history' - 'Neos.Neos:Backend.Module.Administration': label: General access to the administration module matcher: 'administration' @@ -293,19 +289,15 @@ roles: privilegeTarget: 'Neos.Neos:Backend.Module.Management.Workspaces' permission: GRANT - - - privilegeTarget: 'Neos.Neos:Backend.Module.Management.History' - permission: GRANT - 'Neos.Neos:RestrictedEditor': label: Restricted Editor - description: Grants access to the content, media, workspace and history module. The user is allowed to publish to internal workspaces. + description: Grants access to the content, media, and workspace module. The user is allowed to publish to internal workspaces. parentRoles: ['Neos.Neos:AbstractEditor'] 'Neos.Neos:Editor': label: Editor - description: Grants access to the content, media, workspace and history module. The user is allowed to publish to the live workspace. + description: Grants access to the content, media, and workspace module. The user is allowed to publish to the live workspace. parentRoles: ['Neos.Neos:AbstractEditor', 'Neos.Neos:LivePublisher'] 'Neos.Neos:UserManager': diff --git a/Neos.Neos/Configuration/Settings.yaml b/Neos.Neos/Configuration/Settings.yaml index 16a96abe01f..4f45714082b 100755 --- a/Neos.Neos/Configuration/Settings.yaml +++ b/Neos.Neos/Configuration/Settings.yaml @@ -328,12 +328,6 @@ Neos: description: 'Neos.Neos:Modules:workspaces.description' icon: fas fa-th-large mainStylesheet: 'Lite' - history: - label: 'Neos.Neos:Modules:history.label' - controller: 'Neos\Neos\Controller\Module\Management\HistoryController' - description: 'Neos.Neos:Modules:history.description' - icon: fas fa-calendar-alt - mainStylesheet: 'Lite' administration: label: 'Neos.Neos:Modules:administration.label' controller: 'Neos\Neos\Controller\Module\AdministrationController' @@ -394,18 +388,6 @@ Neos: icon: fas fa-user mainStylesheet: 'Lite' - # Settings for the Neos Event Log (** DO NOT USE, NO PUBLIC API YET **) - eventLog: - enabled: false - monitorEntities: - Neos\Flow\Security\Account: - events: - created: Account.Created - deleted: Account.Deleted - data: - accountIdentifier: '${entity.accountIdentifier}' - authenticationProviderName: '${entity.authenticationProviderName}' - name: '${entity.party.name.fullName}' transliterationRules: da: Å: Aa @@ -468,14 +450,6 @@ Neos: session: name: Neos_Session - persistence: - doctrine: - eventListeners: - Neos\Neos\EventLog\Integrations\EntityIntegrationService: - events: - - onFlush - listener: Neos\Neos\EventLog\Integrations\EntityIntegrationService - error: exceptionHandler: renderingGroups: @@ -512,11 +486,6 @@ Neos: neos-plugin: Plugins ContentRepository: - # This instructs neos to fallback to the given type if a node type can't be found (because it was removed or has - # been renamed for example). The default "Neos.Neos:FallbackNode" renders a warning in backend and is ignored - # in frontend rendering - fallbackNodeType: 'Neos.Neos:FallbackNode' - # Definition of available content dimensions. Additional content dimensions may be defined in third-party packages # or via global settings. # diff --git a/Neos.Neos/Configuration/Testing/Behat/Settings.yaml b/Neos.Neos/Configuration/Testing/Behat/Settings.yaml index ceccd786d8d..50d05027e29 100644 --- a/Neos.Neos/Configuration/Testing/Behat/Settings.yaml +++ b/Neos.Neos/Configuration/Testing/Behat/Settings.yaml @@ -1,5 +1 @@ - -Neos: - Neos: - eventLog: - enabled: true +# Behat settings diff --git a/Neos.Neos/Configuration/Testing/Settings.yaml b/Neos.Neos/Configuration/Testing/Settings.yaml index 59558ff8a17..ca3ba18cf4f 100644 --- a/Neos.Neos/Configuration/Testing/Settings.yaml +++ b/Neos.Neos/Configuration/Testing/Settings.yaml @@ -1,8 +1,6 @@ Neos: Neos: - eventLog: - enabled: false userInterface: inspector: dataTypes: diff --git a/Neos.Neos/Documentation/References/NeosFusionReference.rst b/Neos.Neos/Documentation/References/NeosFusionReference.rst index 8c344012224..742e8445eef 100644 --- a/Neos.Neos/Documentation/References/NeosFusionReference.rst +++ b/Neos.Neos/Documentation/References/NeosFusionReference.rst @@ -9,17 +9,6 @@ Neos.Fusion This package contains general-purpose Fusion objects, which are usable both within Neos and standalone. -.. _Neos_Fusion__Array: - -Neos.Fusion:Array ------------------ - -:[key]: (string) A nested definition (simple value, expression or object) that evaluates to a string -:[key].@ignoreProperties: (array) A list of properties to ignore from being "rendered" during evaluation -:[key].@position: (string/integer) Define the ordering of the nested definition - -.. note:: The Neos.Fusion:Array object has been renamed to Neos.Fusion:Join the old name is DEPRECATED; - .. _Neos_Fusion__Join: Neos.Fusion:Join @@ -104,57 +93,6 @@ Example of numeric keys (discouraged):: 20 = Neos.NodeTypes:Text } - -.. _Neos_Fusion__Collection: - -Neos.Fusion:Collection ----------------------- - -Render each item in ``collection`` using ``itemRenderer``. - -:collection: (array/Iterable, **required**) The array or iterable to iterate over -:itemName: (string, defaults to ``item``) Context variable name for each item -:itemKey: (string, defaults to ``itemKey``) Context variable name for each item key, when working with array -:iterationName: (string, defaults to ``iterator``) A context variable with iteration information will be available under the given name: ``index`` (zero-based), ``cycle`` (1-based), ``isFirst``, ``isLast`` -:itemRenderer: (string, **required**) The renderer definition (simple value, expression or object) will be called once for every collection element, and its results will be concatenated (if ``itemRenderer`` cannot be rendered the path ``content`` is used as fallback for convenience in afx) - -.. note:: The Neos.Fusion:Collection object is DEPRECATED use Neos.Fusion:Loop instead. - -Example using an object ``itemRenderer``:: - - myCollection = Neos.Fusion:Collection { - collection = ${[1, 2, 3]} - itemName = 'element' - itemRenderer = Neos.Fusion:Template { - templatePath = 'resource://...' - element = ${element} - } - } - - -Example using an expression ``itemRenderer``:: - - myCollection = Neos.Fusion:Collection { - collection = ${[1, 2, 3]} - itemName = 'element' - itemRenderer = ${element * 2} - } - -.. _Neos_Fusion__RawCollection: - -Neos.Fusion:RawCollection -------------------------- - -Render each item in ``collection`` using ``itemRenderer`` and return the result as an array (opposed to *string* for :ref:`Neos_Fusion__Collection`) - -:collection: (array/Iterable, **required**) The array or iterable to iterate over -:itemName: (string, defaults to ``item``) Context variable name for each item -:itemKey: (string, defaults to ``itemKey``) Context variable name for each item key, when working with array -:iterationName: (string, defaults to ``iterator``) A context variable with iteration information will be available under the given name: ``index`` (zero-based), ``cycle`` (1-based), ``isFirst``, ``isLast`` -:itemRenderer: (mixed, **required**) The renderer definition (simple value, expression or object) will be called once for every collection element (if ``itemRenderer`` cannot be rendered the path ``content`` is used as fallback for convenience in afx) - -.. note:: The Neos.Fusion:RawCollection object is DEPRECATED use Neos.Fusion:Map instead.** - .. _Neos_Fusion__Loop: Neos.Fusion:Loop @@ -194,7 +132,7 @@ Example using an expression ``itemRenderer``:: Neos.Fusion:Map --------------- -Render each item in ``items`` using ``itemRenderer`` and return the result as an array (opposed to *string* for :ref:`Neos_Fusion__Collection`) +Render each item in ``items`` using ``itemRenderer`` and return the result as an array (opposed to *string* for :ref:`Neos_Fusion__Join`) :items: (array/Iterable, **required**) The array or iterable to iterate over (to calculate ``iterator.isLast`` items have to be ``countable``) :itemName: (string, defaults to ``item``) Context variable name for each item @@ -256,7 +194,7 @@ Simple Example:: } } -The ordering of matcher definitions can be specified with the ``@position`` property (see :ref:`Neos_Fusion__Array`). +The ordering of matcher definitions can be specified with the ``@position`` property (see :ref:`Neos_Fusion__Join`). Thus, the priority of existing matchers (e.g. the default Neos document rendering) can be changed by setting or overriding the ``@position`` property. @@ -536,27 +474,13 @@ Example:: value = ${1+2} } -.. _Neos_Fusion__RawArray: - -Neos.Fusion:RawArray --------------------- - -Evaluate nested definitions as an array (opposed to *string* for :ref:`Neos_Fusion__Array`) - -:[key]: (mixed) A nested definition (simple value, expression or object), ``[key]`` will be used for the resulting array key -:[key].@position: (string/integer) Define the ordering of the nested definition - -.. tip:: For simple cases an expression with an array literal ``${[1, 2, 3]}`` might be easier to read - -.. note:: The Neos.Fusion:RawArray object has been renamed to Neos.Fusion:DataStructure the old name is DEPRECATED; - .. _Neos_Fusion__Tag: Neos.Fusion:DataStructure -------------------- -Evaluate nested definitions as an array (opposed to *string* for :ref:`Neos_Fusion__Array`) +Evaluate nested definitions as an array (opposed to *string* for :ref:`Neos_Fusion__Join`) :[key]: (mixed) A nested definition (simple value, expression or object), ``[key]`` will be used for the resulting array key :[key].@position: (string/integer) Define the ordering of the nested definition @@ -596,54 +520,16 @@ Evaluates to:: -.. _Neos_Fusion__Attributes: - -Neos.Fusion:Attributes ----------------------- - -A Fusion object to render HTML tag attributes. This object is used by the :ref:`Neos_Fusion__Tag` object to -render the attributes of a tag. But it's also useful standalone to render extensible attributes in a Fluid template. - -:[key]: (string) A single attribute, array values are joined with whitespace. Boolean values will be rendered as an empty or absent attribute. -:@allowEmpty: (boolean) Whether empty attributes (HTML5 syntax) should be used for empty, false or null attribute values - -.. note:: The ``Neos.Fusion:Attributes`` object is DEPRECATED in favor of a solution inside Neos.Fusion:Tag which takes attributes - as ``Neos.Fusion:DataStructure`` now. If you have to render attributes as string without a tag you can use - ``Neos.Fusion:Join`` with ``@glue` but you will have to concatenate array attributes yourself. - -Example: -^^^^^^^^ - -:: - - attributes = Neos.Fusion:Attributes { - foo = 'bar' - class = Neos.Fusion:DataStructure { - class1 = 'class1' - class2 = 'class2' - } - } - -Evaluates to:: - - foo="bar" class="class1 class2" - -Unsetting an attribute: -^^^^^^^^^^^^^^^^^^^^^^^ - -It's possible to unset an attribute by assigning ``false`` or ``${null}`` as a value. No attribute will be rendered for -this case. - .. _Neos_Fusion__Http_Message: Neos.Fusion:Http.Message ------------------------ -A prototype based on :ref:`Neos_Fusion__Array` for rendering an HTTP message (response). It should be used to +A prototype based on :ref:`Neos_Fusion__Join` for rendering an HTTP message (response). It should be used to render documents since it generates a full HTTP response and allows to override the HTTP status code and headers. -:httpResponseHead: (:ref:`Neos_Fusion__Http_ResponseHead`) An HTTP response head with properties to adjust the status and headers, the position in the ``Array`` defaults to the very beginning -:[key]: (string) A nested definition (see :ref:`Neos_Fusion__Array`) +:httpResponseHead: (:ref:`Neos_Fusion__Http_ResponseHead`) An HTTP response head with properties to adjust the status and headers, the position in the ``Join`` defaults to the very beginning +:[key]: (string) A nested definition (see :ref:`Neos_Fusion__Join`) Example: ^^^^^^^^ @@ -725,35 +611,6 @@ Link to backend modules (other than `content`):: } } -.. _Neos_Fusion__UriBuilder: - -Neos.Fusion:UriBuilder ----------------------- - -Built a URI to a controller action - -:package: (string) The package key (e.g. ``'My.Package'``) -:subpackage: (string) The subpackage, empty by default -:controller: (string) The controller name (e.g. ``'Registration'``) -:action: (string) The action name (e.g. ``'new'``) -:arguments: (array) Arguments to the action by named key -:format: (string) An optional request format (e.g. ``'html'``) -:section: (string) An optional fragment (hash) for the URI -:additionalParams: (array) Additional URI query parameters by named key -:addQueryString: (boolean) Whether to keep the query parameters of the current URI -:argumentsToBeExcludedFromQueryString: (array) Query parameters to exclude for ``addQueryString`` -:absolute: (boolean) Whether to create an absolute URI - -.. note:: The use of ``Neos.Fusion:UriBuilder`` is deprecated. Use :ref:`_Neos_Fusion__ActionUri` instead. - -Example:: - - uri = Neos.Fusion:UriBuilder { - package = 'My.Package' - controller = 'Registration' - action = 'new' - } - .. _Neos_Fusion__ResourceUri: Neos.Fusion:ResourceUri @@ -873,22 +730,22 @@ which do not need a particular node type to work on. Neos.Neos:Page -------------- -Subclass of :ref:`Neos_Fusion__Http_Message`, which is based on :ref:`Neos_Fusion__Array`. Main entry point +Subclass of :ref:`Neos_Fusion__Http_Message`, which is based on :ref:`Neos_Fusion__Join`. Main entry point into rendering a page; responsible for rendering the ```` tag and everything inside. :doctype: (string) Defaults to ```` :htmlTag: (:ref:`Neos_Fusion__Tag`) The opening ```` tag -:htmlTag.attributes: (:ref:`Neos_Fusion__Attributes`) Attributes for the ```` tag +:htmlTag.attributes: (:ref:`Neos_Fusion__DataStructure`) Attributes for the ```` tag :headTag: (:ref:`Neos_Fusion__Tag`) The opening ```` tag -:head: (:ref:`Neos_Fusion__Array`) HTML markup for the ```` tag +:head: (:ref:`Neos_Fusion__Join`) HTML markup for the ```` tag :head.titleTag: (:ref:`Neos_Fusion__Tag`) The ```` tag -:head.javascripts: (:ref:`Neos_Fusion__Array`) Script includes in the head should go here -:head.stylesheets: (:ref:`Neos_Fusion__Array`) Link tags for stylesheets in the head should go here +:head.javascripts: (:ref:`Neos_Fusion__Join`) Script includes in the head should go here +:head.stylesheets: (:ref:`Neos_Fusion__Join`) Link tags for stylesheets in the head should go here :body.templatePath: (string) Path to a fluid template for the page body :bodyTag: (:ref:`Neos_Fusion__Tag`) The opening ``<body>`` tag -:bodyTag.attributes: (:ref:`Neos_Fusion__Attributes`) Attributes for the ``<body>`` tag +:bodyTag.attributes: (:ref:`Neos_Fusion__DataStructure`) Attributes for the ``<body>`` tag :body: (:ref:`Neos_Fusion__Template`) HTML markup for the ``<body>`` tag -:body.javascripts: (:ref:`Neos_Fusion__Array`) Body footer JavaScript includes +:body.javascripts: (:ref:`Neos_Fusion__Join`) Body footer JavaScript includes :body.[key]: (mixed) Body template variables Examples: @@ -958,7 +815,7 @@ Render nested content from a ``ContentCollection`` node. Individual nodes are re :nodePath: (string, **required**) The relative node path of the ``ContentCollection`` (e.g. ``'main'``) :@context.node: (Node) The content collection node, resolved from ``nodePath`` by default :tagName: (string) Tag name for the wrapper element -:attributes: (:ref:`Neos_Fusion__Attributes`) Tag attributes for the wrapper element +:attributes: (:ref:`Neos_Fusion__DataStructure`) Tag attributes for the wrapper element Example:: @@ -1025,7 +882,7 @@ auto-generated Fusion to define prototypes for each node type extending ``Neos.N :templatePath: (string) The template path and filename, defaults to ``'resource://[packageKey]/Private/Templates/NodeTypes/[nodeType].html'`` (for auto-generated prototypes) :[key]: (mixed) Template variables, all node type properties are available by default (for auto-generated prototypes) -:attributes: (:ref:`Neos_Fusion__Attributes`) Extensible attributes, used in the default templates +:attributes: (:ref:`Neos_Fusion__DataStructure`) Extensible attributes, used in the default templates Example:: @@ -1109,73 +966,33 @@ Get argument in controller action:: Neos.Neos:Menu -------------- -Render a menu with items for nodes. Extends :ref:`Neos_Fusion__Template`. - -:templatePath: (string) Override the template path -:entryLevel: (integer) Start the menu at the given depth -:maximumLevels: (integer) Restrict the maximum depth of items in the menu (relative to ``entryLevel``) -:startingPoint: (Node) The parent node of the first menu level (defaults to ``node`` context variable) -:lastLevel: (integer) Restrict the menu depth by node depth (relative to site node) -:filter: (string) Filter items by node type (e.g. ``'!My.Site:News,Neos.Neos:Document'``), defaults to ``'Neos.Neos:Document'`` -:renderHiddenInIndex: (boolean) Whether nodes with ``hiddenInIndex`` should be rendered, defaults to ``false`` -:itemCollection: (array) Explicitly set the Node items for the menu (alternative to ``startingPoints`` and levels) -:attributes: (:ref:`Neos_Fusion__Attributes`) Extensible attributes for the whole menu -:normal.attributes: (:ref:`Neos_Fusion__Attributes`) Attributes for normal state -:active.attributes: (:ref:`Neos_Fusion__Attributes`) Attributes for active state -:current.attributes: (:ref:`Neos_Fusion__Attributes`) Attributes for current state - -.. note:: The ``items`` of the ``Menu`` are internally calculated with the prototype :ref:`Neos_Neos__MenuItems` which - you can use directly aswell. - -Menu item properties: -^^^^^^^^^^^^^^^^^^^^^ - -:node: (Node) A node instance (with resolved shortcuts) that should be used to link to the item -:originalNode: (Node) Original node for the item -:state: (string) Menu state of the item: ``'normal'``, ``'current'`` (the current node) or ``'active'`` (ancestor of current node) -:label: (string) Full label of the node -:menuLevel: (integer) Menu level the item is rendered on - -Examples: -^^^^^^^^^ - -Custom menu template: -""""""""""""""""""""" - -:: - - menu = Neos.Neos:Menu { - entryLevel = 1 - maximumLevels = 3 - templatePath = 'resource://My.Site/Private/Templates/FusionObjects/MyMenu.html' - } +Render a menu with items for nodes. -Menu including site node: -""""""""""""""""""""""""" +:attributes: (:ref:`Neos_Fusion__DataStructure`) attributes for the whole menu +:[key]: (mixed) all other fusion properties are passed over to :ref:`Neos_Neos__MenuItems` internally to calculate the `items` -:: +Example:: menu = Neos.Neos:Menu { - itemCollection = ${q(site).add(q(site).children('[instanceof Neos.Neos:Document]')).get()} + attributes.class = 'menu' + maximumLevels = 3 } -Menu with custom starting point: -"""""""""""""""""""""""""""""""" - -:: +.. note:: The ``items`` of the ``Menu`` are internally calculated with the prototype :ref:`Neos_Neos__MenuItems` which + you can use directly aswell. - menu = Neos.Neos:Menu { - entryLevel = 2 - maximumLevels = 1 - startingPoint = ${q(site).children('[uriPathSegment="metamenu"]').get(0)} - } +.. note:: The ``rendering`` of the ``Menu`` is performed with the prototype :ref:`Neos_Neos__MenuItemListRenderer`. + If the rendering does not suit your useCase it we recommended to create your own variants of the menu and renderer prototype. .. _Neos_Neos__BreadcrumbMenu: Neos.Neos:BreadcrumbMenu ------------------------ -Render a breadcrumb (ancestor documents), based on :ref:`Neos_Neos__Menu`. +Render a breadcrumb (ancestor documents). + +:attributes: (:ref:`Neos_Fusion__DataStructure`) attributes for the whole menu +:[key]: (mixed) all other fusion properties are passed over to :ref:`Neos_Neos__BreadcrumbMenuItems` internally Example:: @@ -1184,91 +1001,36 @@ Example:: .. note:: The ``items`` of the ``BreadcrumbMenu`` are internally calculated with the prototype :ref:`Neos_Neos__MenuItems` which you can use directly aswell. +.. note:: The ``rendering`` of the ``BreadcrumbMenu`` is performed with the prototype :ref:`Neos_Neos__MenuItemListRenderer`. + If the rendering does not suit your useCase it we recommended to create your own variants of the menu and renderer prototype. + .. _Neos_Neos__DimensionMenu: .. _Neos_Neos__DimensionsMenu: Neos.Neos:DimensionsMenu ------------------------ -Create links to other node variants (e.g. variants of the current node in other dimensions) by using this Fusion object. - -If the ``dimension`` setting is given, the menu will only include items for this dimension, with all other configured -dimension being set to the value(s) of the current node. Without any ``dimension`` being configured, all possible -variants will be included. - -If no node variant exists for the preset combination, a ``NULL`` node will be included in the item with a state ``absent``. - -:dimension: (optional, string): name of the dimension which this menu should be based on. Example: "language". -:presets: (optional, array): If set, the presets rendered will be taken from this list of preset identifiers -:includeAllPresets: (boolean, default **false**) If TRUE, include all presets, not only allowed combinations -:renderHiddenInIndex: (boolean, default **true**) If TRUE, render nodes which are marked as "hidded-in-index" - -In the template for the menu, each ``item`` has the following properties: - -:node: (Node) A node instance (with resolved shortcuts) that should be used to link to the item -:state: (string) Menu state of the item: ``normal``, ``current`` (the current node), ``absent`` -:label: (string) Label of the item (the dimension preset label) -:menuLevel: (integer) Menu level the item is rendered on -:dimensions: (array) Dimension values of the node, indexed by dimension name -:targetDimensions: (array) The target dimensions, indexed by dimension name and values being arrays with ``value``, ``label`` and ``isPinnedDimension`` +Create links to other node variants (e.g. variants of the current node in other dimensions). -.. note:: The ``DimensionMenu`` is an alias to ``DimensionsMenu``, available for compatibility reasons only. +:attributes: (:ref:`Neos_Fusion__DataStructure`) attributes for the whole menu +:[key]: (mixed) all other fusion properties are passed over to :ref:`Neos_Neos__DimensionsMenuItems` internally -.. note:: The ``items`` of the ``DimensionsMenu`` are internally calculated with the prototype :ref:`Neos_Neos__DimensionsMenuItems` which +.. note:: The ``items`` of the ``DimensionsMenu`` are internally calculated with the prototype :ref:`Neos_Neos__DimensionsMenuMenuItems` which you can use directly aswell. -Examples -^^^^^^^^ - -Minimal Example, outputting a menu with all configured dimension combinations:: - - variantMenu = Neos.Neos:DimensionsMenu - -This example will create two menus, one for the 'language' and one for the 'country' dimension:: - - languageMenu = Neos.Neos:DimensionsMenu { - dimension = 'language' - } - countryMenu = Neos.Neos:DimensionsMenu { - dimension = 'country' - } +.. note:: The ``rendering`` of the ``DimensionsMenu`` is performed with the prototype :ref:`Neos_Neos__MenuItemListRenderer`. + If the rendering does not suit your useCase it we recommended to create your own variants of the menu and renderer prototype. -If you only want to render a subset of the available presets or manually define a specific order for a menu, -you can override the "presets":: +.. _Neos_Neos__MenuItemListRenderer: - languageMenu = Neos.Neos:DimensionsMenu { - dimension = 'language' - presets = ${['en_US', 'de_DE']} # no matter how many languages are defined, only these two are displayed. - } +Neos.Neos:MenuItemListRenderer +------------------------------- -In some cases, it can be good to ignore the availability of variants when rendering a dimensions menu. Consider a -situation with two independent menus for country and language, where the following variants of a node exist -(language / country): +A very basic renderer that takes a list of MenuItems and renders the result as unordered list. If item states were calculated +they are applied as classnames to the list items. -- english / Germany -- german / Germany -- english / UK - -If the user selects UK, only english will be linked in the language selector. German is only available again, if the -user switches back to Germany first. This can be changed by setting the ``includeAllPresets`` option:: - - languageMenu = Neos.Neos:DimensionsMenu { - dimension = 'language' - includeAllPresets = true - } - -Now the language menu will try to find nodes for all languages, if needed the menu items will point to a different -country than currently selected. The menu tries to find a node to link to by using the current preset for the language -(in this example) and the default presets for any other dimensions. So if fallback rules are in place and a node can be -found, it is used. - -.. note:: The ``item.targetDimensions`` will contain the "intended" dimensions, so that information can be used to - inform the user about the potentially unexpected change of dimensions when following such a link. - -Only if the current node is not available at all (even after considering default presets with their fallback rules), -no node be assigned (so no link will be created and the items will have the ``absent`` state.) - -.. _Neos_Neos__MenuItems: +:items: (array): The MenuItems as generated by :ref:`Neos_Neos__MenuItems`, :ref:`Neos_Neos__DimensionsMenuItems`, :ref:`Neos_Neos__BreadcrumbMenuItems` +:attributes: (optional, array): The attributes to apply on the outer list Neos.Neos:MenuItems ------------------- @@ -1283,6 +1045,7 @@ Create a list of menu-items items for nodes. :renderHiddenInIndex: (boolean) Whether nodes with ``hiddenInIndex`` should be rendered, defaults to ``false`` :itemCollection: (array) Explicitly set the Node items for the menu (alternative to ``startingPoints`` and levels) :itemUriRenderer: (:ref:`Neos_Neos__NodeUri`) prototype to use for rendering the URI of each item +:calculateItemStates: (boolean) activate the *expensive* calculation of item states defaults to ``false`` MenuItems item properties: ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1363,6 +1126,8 @@ If no node variant exists for the preset combination, a ``NULL`` node will be in :presets: (optional, array): If set, the presets rendered will be taken from this list of preset identifiers :includeAllPresets: (boolean, default **false**) If TRUE, include all presets, not only allowed combinations :renderHiddenInIndex: (boolean, default **true**) If TRUE, render nodes which are marked as "hidded-in-index" +:itemUriRenderer: (:ref:`Neos_Neos__NodeUri`) prototype to use for rendering the URI of each item +:calculateItemStates: (boolean) activate the *expensive* calculation of item states defaults to ``false`` Each ``item`` has the following properties: @@ -1456,7 +1221,7 @@ Renders an anchor tag pointing to the node given via the argument. Based on :ref The link text is the node label, unless overridden. :\*: All :ref:`Neos_Neos__NodeUri` properties -:attributes: (:ref:`Neos_Fusion__Attributes`) Link tag attributes +:attributes: (:ref:`Neos_Fusion__DataStructure`) Link tag attributes :content: (string) The label of the link, defaults to ``node.label``. Example:: @@ -1505,7 +1270,7 @@ Neos.Neos:ImageTag Render an image tag for an asset. :\*: All :ref:`Neos_Neos__ImageUri` properties -:attributes: (:ref:`Neos_Fusion__Attributes`) Image tag attributes +:attributes: (:ref:`Neos_Fusion__DataStructure`) Image tag attributes Per default, the attribute loading is set to ``'lazy'``. To fetch a resource immediately, you can set ``attributes.loading`` to ``null``, ``false`` or ``'eager'``. @@ -1587,3 +1352,57 @@ Example:: property = 'title' } } + + +Deprecated Fusion Prototypes +---------------------------- + +The following prototypes are deprecated and will be removed in future versions of Neos! + +.. _Neos_Fusion__UriBuilder: + +Neos.Fusion:UriBuilder +~~~~~~~~~~~~~~~~~~~~~~ + +Built a URI to a controller action + +:package: (string) The package key (e.g. ``'My.Package'``) +:subpackage: (string) The subpackage, empty by default +:controller: (string) The controller name (e.g. ``'Registration'``) +:action: (string) The action name (e.g. ``'new'``) +:arguments: (array) Arguments to the action by named key +:format: (string) An optional request format (e.g. ``'html'``) +:section: (string) An optional fragment (hash) for the URI +:additionalParams: (array) Additional URI query parameters by named key +:addQueryString: (boolean) Whether to keep the query parameters of the current URI +:argumentsToBeExcludedFromQueryString: (array) Query parameters to exclude for ``addQueryString`` +:absolute: (boolean) Whether to create an absolute URI + +.. note:: The use of ``Neos.Fusion:UriBuilder`` is deprecated. Use :ref:`_Neos_Fusion__ActionUri` instead. + +Example:: + + uri = Neos.Fusion:UriBuilder { + package = 'My.Package' + controller = 'Registration' + action = 'new' + } + +Removed Fusion Prototypes +------------------------- + +The following Fusion Prototypes have been removed: + +.. _Neos_Fusion__Array: +* `Neos.Fusion:Array` replaced with :ref:`_Neos_Fusion__Join` +.. _Neos_Fusion__RawArray: +* `Neos.Fusion:RawArray` replaced with :ref:`_Neos_Fusion__DataStructure` +.. _Neos_Fusion__Collection: +* `Neos.Fusion:Collection` replaced with :ref:`_Neos_Fusion__Loop` +.. _Neos_Fusion__RawCollection: +* `Neos.Fusion:RawCollection` replaced with :ref:`_Neos_Fusion__Map` +.. _Neos_Fusion__Attributes: +* `Neos.Fusion:Attributes` use property `attributes` in :ref:`_Neos_Fusion__Tag` + + + diff --git a/Neos.Neos/Documentation/References/NodeMigrations.rst b/Neos.Neos/Documentation/References/NodeMigrations.rst index 40868559ebc..7ffc28d4343 100644 --- a/Neos.Neos/Documentation/References/NodeMigrations.rst +++ b/Neos.Neos/Documentation/References/NodeMigrations.rst @@ -11,19 +11,18 @@ through **filters** in migration files. The Content Repository comes with a number of common transformations: -- ``AddDimensions`` +- ``AddDimensionShineThrough`` - ``AddNewProperty`` - ``ChangeNodeType`` - ``ChangePropertyValue`` +- ``MoveDimensionSpacePoint`` - ``RemoveNode`` - ``RemoveProperty`` -- ``RenameDimension`` -- ``RenameNode`` +- ``RenameNodeAggregate`` - ``RenameProperty`` -- ``SetDimensions`` - ``StripTagsOnProperty`` -They all implement the ``Neos\ContentRepository\Migration\Transformations\TransformationInterface``. Custom transformations +They all implement the ``Neos\ContentRepository\NodeMigration\Transformation\TransformationFactoryInterface``. Custom transformations can be developed against that interface as well, just use the fully qualified class name for those when specifying which transformation to use. @@ -36,70 +35,61 @@ To use node migrations to adjust a setup to changed configuration, a YAML file i migration by setting up filters to select what nodes are being worked on by transformations. The Content Repository comes with a number of filters: -- ``DimensionValues`` -- ``IsRemoved`` +- ``DimensionSpacePoints`` - ``NodeName`` - ``NodeType`` - ``PropertyNotEmpty`` - ``PropertyValue`` -- ``Workspace`` They all implement the ``Neos\ContentRepository\Migration\Filters\FilterInterface``. Custom filters can be developed against that interface as well, just use the fully qualified class name for those when specifying which filter to use. -Here is an example of a migration, ``Version20140708120530.yaml``, that operates on nodes in the "live" workspace -that are marked as removed and applies the ``RemoveNode`` transformation on them: +Here is an example of a migration that operates on all nodes with nodetype `Neos.ContentRepository.Testing:Document` and +changes their property name form `text` to `newText`: .. code-block:: yaml - up: - comments: 'Delete removed nodes that were published to "live" workspace' - warnings: 'There is no way of reverting this migration since the nodes will be deleted in the database.' - migration: - - - filters: - - - type: 'IsRemoved' - settings: [] - - - type: 'Workspace' - settings: - workspaceName: 'live' - transformations: - - - type: 'RemoveNode' - settings: [] - - down: - comments: 'No down migration available' + comments: 'Rename the property of all Neos.ContentRepository.Testing:Document nodes' + migration: + - + filters: + - + type: 'NodeType' + settings: + nodeType: 'Neos.ContentRepository.Testing:Document' + transformations: + - + type: 'RenameProperty' + settings: + from: 'text' + to: 'newText' Like all migrations the file should be placed in a package inside the ``Migrations/ContentRepository`` folder where it will be picked up by the CLI tools provided with the content repository: -- ``./flow node:migrationstatus`` -- ``./flow node:migrate`` +- ``./flow nodemigration:list`` +- ``./flow nodemigration:execute`` -Use ``./flow help <command>`` to get detailed instructions. The ``migrationstatus`` command also prints a short description +Use ``./flow help <command>`` to get detailed instructions. The ``nodemigration:list`` command also prints a short description for each migration. -.. note:: Node migrations in ``Migrations/TYPO3CR`` directories are also supported for historic reasons - Transformations Reference ------------------------- -AddDimensions +AddDimensionShineThrough ~~~~~~~~~~~~~ -Add dimensions on a node. This adds to the existing dimensions, if you need to overwrite existing dimensions, use -SetDimensions. +Add a Dimension Space Point (DSP) Shine-Through; basically making all content available not just in the source (original) DSP, but also in the target-DimensionSpacePoint. + +NOTE: the Source Dimension Space Point must be a parent of the target Dimension Space Point. Options Reference: -``dimensionValues`` (array) - An array of dimension names and values to set. -``addDefaultDimensionValues`` (boolean) - Whether to add the default dimension values for all dimensions that were not given. +``from`` (array) + Source Dimension Space Point as array. E.g. ["language" => "es", "country" => "es"] +``to`` (array) + Target Dimension Space Point where the content has to shine through as array. E.g. ["language" => "es", "country" => "ar"] AddNewProperty ~~~~~~~~~~~~~~ @@ -110,7 +100,9 @@ Options Reference: ``newPropertyName`` (string) The name of the new property to be added. -``value`` (mixed) +``type`` (string) + The type of the property (e.g. string, array, DateTime, ...) +``serializedValue`` (mixed) Property value to be set. ChangeNodeType @@ -123,6 +115,11 @@ Options Reference: ``newType`` (string) The new Node Type to use as a string. +``forceDeleteNonMatchingChildren`` (bool) + This flag allows to enforce the migration. In case of child constraint conflicts the conflicting child nodes get deleted. + + Default is `false`. + ChangePropertyValue ~~~~~~~~~~~~~~~~~~~ @@ -130,9 +127,9 @@ Change the value of a given property. This can apply two transformations: -- If newValue is set, the value will be set to this, with any occurrences of the ``currentValuePlaceholder`` replaced +- If newSerializedValue is set, the value will be set to this, with any occurrences of the ``currentValuePlaceholder`` replaced with the current value of the property. -- If search and replace are given, that replacement will be done on the value (after applying the ``newValue``, if set). +- If search and replace are given, that replacement will be done on the value (after applying the ``newSerializedValue``, if set). This would simply override the existing value: @@ -143,7 +140,7 @@ This would simply override the existing value: type: 'ChangePropertyValue' settings: property: 'title' - newValue: 'a new value' + newSerializedValue: 'a new value' This would prefix the existing value: @@ -154,7 +151,7 @@ This would prefix the existing value: type: 'ChangePropertyValue' settings: property: 'title' - newValue: 'this is a prefix to {current}' + newSerializedValue: 'this is a prefix to {current}' This would prefix existing value and then apply search/replace on the result: @@ -165,7 +162,7 @@ This would prefix existing value and then apply search/replace on the result: type: 'ChangePropertyValue' settings: property: 'title' - newValue: 'this is a prefix to {current}' + newSerializedValue: 'this is a prefix to {current}' search: 'something' replace: 'something else' @@ -179,14 +176,14 @@ value but use a different placeholder: type: 'ChangePropertyValue' settings: property: 'title' - newValue: 'this is a prefix to {__my_unique_placeholder}' + newSerializedValue: 'this is a prefix to {__my_unique_placeholder}' currentValuePlaceholder: '__my_unique_placeholder' Options Reference: ``property`` (string) The name of the property to change. -``newValue`` (string) +``newSerializedValue`` (string) New property value to be set. The value of the option ``currentValuePlaceholder`` (defaults to "{current}") will be used to include the current @@ -199,11 +196,27 @@ Options Reference: The value of this option (defaults to ``{current}``) will be used to include the current property value into the new value. +MoveDimensionSpacePoint +~~~~~~~~~~ + +Moves a dimension space point globally. + +``from`` (array) + Source Dimension Space Point as array. E.g. ["language" => "es", "country" => "es"] +``to`` (array) + Target Dimension Space Point as array. E.g. ["language" => "es", "country" => "ar"] + + RemoveNode ~~~~~~~~~~ Removes the node. +``overriddenDimensionSpacePoint`` (array) + Dimension Space Point as array. E.g. ["country" => "ar"] + + This allows to remove nodes in a virtual specialization or shine-through dimension space points. + RemoveProperty ~~~~~~~~~~~~~~ @@ -214,27 +227,17 @@ Options Reference: ``property`` (string) The name of the property to be removed. -RenameDimension -~~~~~~~~~~~~~~~ - -Rename a dimension. - -Options Reference: - -``newDimensionName`` (string) - The new name for the dimension. -``oldDimensionName`` (string) - The old name of the dimension to rename. - -RenameNode +RenameNodeAggregate ~~~~~~~~~~ -Rename a node. +Rename a node aggregate. + +Hint: Why node aggregate, not node? The node aggregate contains all information, that are equal for a node over all dimensions. So the name of a node is stored in the node aggregate and not in each node anymore. Options Reference: -``newName`` (string) - The new name for the node. +``newNodeName`` (string) + The new name for the node aggregate. RenameProperty ~~~~~~~~~~~~~~ @@ -249,18 +252,6 @@ Options Reference: The new name for the property to change. -SetDimensions -~~~~~~~~~~~~~ -Set dimensions on a node. This always overwrites existing dimensions, if you need to add to existing dimensions, use -AddDimensions. - -Options Reference: - -``dimensionValues`` (array) - An array of dimension names and values to set. -``addDefaultDimensionValues`` (boolean) - Whether to add the default dimension values for all dimensions that were not given. - StripTagsOnProperty ~~~~~~~~~~~~~~~~~~~ @@ -276,22 +267,18 @@ Options Reference: Filters Reference ----------------- -DimensionValues +DimensionSpacePoints ~~~~~~~~~~~~~~~ -Filter nodes by their dimensions. +Filter nodes by origin dimension space point. Options Reference: -``dimensionValues`` (array) - The array of dimension values to filter for. -``filterForDefaultDimensionValues`` (boolean) - Overrides the given dimensionValues with dimension defaults. - -IsRemoved -~~~~~~~~~ - -Selects nodes marked as removed. +``points`` (array) + The array of dimension space point values to filter for. +``includeSpecializations`` (boolean) + If set to `false` it checks for exact matches; but if set to `true`, also dimension space points "underneath" the given + dimension space point are matched (specializations). Default is `false`. NodeName ~~~~~~~~ @@ -337,15 +324,5 @@ Options Reference: ``propertyName`` (string) The property name to filter for with the given property value. -``propertyValue`` (string) +``serializedValue`` (string) The property value to filter for. - -Workspace -~~~~~~~~~ - -Filter nodes by workspace name. - -Options Reference: - -``workspaceName`` (string) - The workspace name to match on. diff --git a/Neos.Neos/Documentation/References/Signals/Neos.rst b/Neos.Neos/Documentation/References/Signals/Neos.rst index 3c63a9bcfd7..172d5bd3552 100644 --- a/Neos.Neos/Documentation/References/Signals/Neos.rst +++ b/Neos.Neos/Documentation/References/Signals/Neos.rst @@ -393,27 +393,6 @@ before passing it on to further rendering -.. _`Neos Signals Reference: HistoryController (``Neos\Neos\Controller\Module\Management\HistoryController``)`: - -HistoryController (``Neos\Neos\Controller\Module\Management\HistoryController``) --------------------------------------------------------------------------------- - -This class contains the following signals. - -viewResolved -^^^^^^^^^^^^ - -Autogenerated Proxy Method - -Emit that the view is resolved. The passed ViewInterface reference, -gives the possibility to add variables to the view, -before passing it on to further rendering - - - - - - .. _`Neos Signals Reference: ImpersonateController (``Neos\Neos\Controller\Backend\ImpersonateController``)`: ImpersonateController (``Neos\Neos\Controller\Backend\ImpersonateController``) diff --git a/Neos.Neos/Documentation/conf.py b/Neos.Neos/Documentation/conf.py index 9306d7ff873..613a54c04a7 100644 --- a/Neos.Neos/Documentation/conf.py +++ b/Neos.Neos/Documentation/conf.py @@ -27,9 +27,9 @@ author = 'Neos Team and Contributors' # The short X.Y version. -version = '8.3' +version = '9.0' # The full version, including alpha/beta/rc tags. -release = '8.3.x' +release = '9.0.x' # -- General configuration --------------------------------------------------- diff --git a/Neos.Neos/Documentation/requirements.in b/Neos.Neos/Documentation/requirements.in new file mode 100644 index 00000000000..52096927cfe --- /dev/null +++ b/Neos.Neos/Documentation/requirements.in @@ -0,0 +1,2 @@ +sphinx==7.2.6 +sphinx_rtd_theme==1.3.0 diff --git a/Neos.Neos/Documentation/requirements.txt b/Neos.Neos/Documentation/requirements.txt index 6b3439d4217..12e992402fd 100644 --- a/Neos.Neos/Documentation/requirements.txt +++ b/Neos.Neos/Documentation/requirements.txt @@ -1,2 +1,62 @@ -sphinx==3.2.1 -sphinx_rtd_theme==1.0.0 +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile requirements.in +# +alabaster==0.7.13 + # via sphinx +babel==2.13.0 + # via sphinx +certifi==2023.7.22 + # via requests +charset-normalizer==3.3.0 + # via requests +docutils==0.18.1 + # via + # sphinx + # sphinx-rtd-theme +idna==3.4 + # via requests +imagesize==1.4.1 + # via sphinx +jinja2==3.1.2 + # via sphinx +markupsafe==2.1.3 + # via jinja2 +packaging==23.2 + # via sphinx +pygments==2.16.1 + # via sphinx +requests==2.31.0 + # via sphinx +snowballstemmer==2.2.0 + # via sphinx +sphinx==7.2.6 + # via + # -r requirements.in + # sphinx-rtd-theme + # sphinxcontrib-applehelp + # sphinxcontrib-devhelp + # sphinxcontrib-htmlhelp + # sphinxcontrib-jquery + # sphinxcontrib-qthelp + # sphinxcontrib-serializinghtml +sphinx-rtd-theme==1.3.0 + # via -r requirements.in +sphinxcontrib-applehelp==1.0.7 + # via sphinx +sphinxcontrib-devhelp==1.0.5 + # via sphinx +sphinxcontrib-htmlhelp==2.0.4 + # via sphinx +sphinxcontrib-jquery==4.1 + # via sphinx-rtd-theme +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.6 + # via sphinx +sphinxcontrib-serializinghtml==1.1.9 + # via sphinx +urllib3==2.0.6 + # via requests diff --git a/Neos.Neos/Migrations/ContentRepository/Version20120921140942.yaml b/Neos.Neos/Migrations/ContentRepository/Version20120921140942.yaml deleted file mode 100644 index d05ac9eb623..00000000000 --- a/Neos.Neos/Migrations/ContentRepository/Version20120921140942.yaml +++ /dev/null @@ -1,315 +0,0 @@ -up: - comments: 'This is the migration to adjust sites to the new TYPO3.Phoenix.ContentTypes namespace' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Page' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Page' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Section' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Section' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Shortcut' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Shortcut' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Headline' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Headline' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Text' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Text' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Image' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Image' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:TextWithImage' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:TextWithImage' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Html' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Html' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Menu' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Menu' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Column' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Column' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:TwoColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:TwoColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:ThreeColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:ThreeColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:FourColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:FourColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.TYPO3:Plugin' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.Phoenix.ContentTypes:Plugin' - -down: - comments: 'This migrates nodes from the TYPO3.Phoenix.ContentTypes namespace back to the TYPO3.TYPO3 namespace.' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Page' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Page' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Section' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Section' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Shortcut' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Shortcut' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Headline' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Headline' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Text' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Text' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Image' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Image' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:TextWithImage' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:TextWithImage' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Html' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Html' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Menu' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Menu' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Column' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Column' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:TwoColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:TwoColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:ThreeColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:ThreeColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:FourColumn' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:FourColumn' - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Phoenix.ContentTypes:Plugin' - transformations: - - - type: 'ChangeNodeType' - settings: - newType: 'TYPO3.TYPO3:Plugin' diff --git a/Neos.Neos/Migrations/ContentRepository/Version20140723115900.yaml b/Neos.Neos/Migrations/ContentRepository/Version20140723115900.yaml deleted file mode 100644 index 11d8ad36f12..00000000000 --- a/Neos.Neos/Migrations/ContentRepository/Version20140723115900.yaml +++ /dev/null @@ -1,23 +0,0 @@ -up: - comments: 'Migrate from "languages" dimension to "language" dimension.' - migration: - - - filters: [] - transformations: - - - type: 'RenameDimension' - settings: - oldDimensionName: 'languages' - newDimensionName: 'language' - -down: - comments: 'Migrate from "language" dimension to "languages" dimension.' - migration: - - - filters: [] - transformations: - - - type: 'RenameDimension' - settings: - oldDimensionName: 'language' - newDimensionName: 'languages' diff --git a/Neos.Neos/Migrations/ContentRepository/Version20140930125621.yaml b/Neos.Neos/Migrations/ContentRepository/Version20140930125621.yaml deleted file mode 100644 index 1deb79c7d17..00000000000 --- a/Neos.Neos/Migrations/ContentRepository/Version20140930125621.yaml +++ /dev/null @@ -1,54 +0,0 @@ -up: - comments: 'Migrate shortcut nodes: targetMode value adjustment and rename targetNode property' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Neos:Shortcut' - transformations: - - - type: 'ChangePropertyValue' - settings: - property: 'targetMode' - search: 'selectedNode' - replace: 'selectedTarget' - - - type: 'RenameProperty' - settings: - from: 'targetNode' - to: 'target' - - - type: 'ChangePropertyValue' - settings: - property: 'target' - newValue: 'node://{current}' - -down: - comments: 'Migrate shortcut nodes: targetMode value adjustment and rename target property' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Neos:Shortcut' - transformations: - - - type: 'ChangePropertyValue' - settings: - property: 'targetMode' - search: 'selectedTarget' - replace: 'selectedNode' - - - type: 'RenameProperty' - settings: - from: 'target' - to: 'targetNode' - - - type: 'ChangePropertyValue' - settings: - property: 'targetNode' - search: 'node://' - replace: '' diff --git a/Neos.Neos/Migrations/ContentRepository/Version20141103100401.yaml b/Neos.Neos/Migrations/ContentRepository/Version20141103100401.yaml deleted file mode 100644 index 58704da49e2..00000000000 --- a/Neos.Neos/Migrations/ContentRepository/Version20141103100401.yaml +++ /dev/null @@ -1,16 +0,0 @@ -up: - comments: 'Migrate serialized Media objects to relation format.' - warnings: 'No down migration possible for this migration. There is no way back. Make sure you have a backup of your database.' - migration: - - - filters: [] - transformations: - - - type: 'TYPO3\Neos\TYPO3CR\Transformations\ImageVariantTransformation' - settings: [] - - - type: 'TYPO3\Neos\TYPO3CR\Transformations\AssetTransformation' - settings: [] - -down: - comments: 'No down migration possible.' \ No newline at end of file diff --git a/Neos.Neos/Migrations/ContentRepository/Version20150907194505.yaml b/Neos.Neos/Migrations/ContentRepository/Version20150907194505.yaml deleted file mode 100644 index e4fd85d9d8c..00000000000 --- a/Neos.Neos/Migrations/ContentRepository/Version20150907194505.yaml +++ /dev/null @@ -1,28 +0,0 @@ -up: - comments: 'Migrate PluginViews references from node paths to identifiers.' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Neos:PluginView' - transformations: - - - type: 'TYPO3\Neos\TYPO3CR\Transformations\PluginViewTransformation' - settings: [] - -down: - comments: 'Migrate PluginViews references from identifiers to node paths.' - migration: - - - filters: - - - type: 'NodeType' - settings: - nodeType: 'TYPO3.Neos:PluginView' - transformations: - - - type: 'TYPO3\Neos\TYPO3CR\Transformations\PluginViewTransformation' - settings: - reverse: true \ No newline at end of file diff --git a/Neos.Neos/Migrations/Mysql/Version20231012072631.php b/Neos.Neos/Migrations/Mysql/Version20231012072631.php new file mode 100644 index 00000000000..0bfc08bc314 --- /dev/null +++ b/Neos.Neos/Migrations/Mysql/Version20231012072631.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace Neos\Flow\Persistence\Doctrine\Migrations; + +use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; + +final class Version20231012072631 extends AbstractMigration +{ + public function getDescription(): string + { + return 'Removes the table for the EventLog (neos_neos_eventlog_domain_model_event)'; + } + + public function up(Schema $schema): void + { + $this->abortIf( + !$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MariaDb1027Platform, + "Migration can only be executed safely on '\Doctrine\DBAL\Platforms\MariaDb1027Platform'." + ); + + $this->addSql('DROP TABLE IF EXISTS neos_neos_eventlog_domain_model_event'); + } + + public function down(Schema $schema): void + { + $this->abortIf( + !$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MariaDb1027Platform, + "Migration can only be executed safely on '\Doctrine\DBAL\Platforms\MariaDb1027Platform'." + ); + + $this->addSql('CREATE TABLE neos_neos_eventlog_domain_model_event (parentevent int(10) unsigned DEFAULT NULL, timestamp datetime NOT NULL, uid int(10) unsigned NOT NULL AUTO_INCREMENT, eventtype varchar(255) NOT NULL, accountidentifier varchar(255) DEFAULT NULL, data longtext NOT NULL COMMENT \'(DC2Type:flow_json_array)\', dtype varchar(255) NOT NULL, nodeidentifier varchar(255) DEFAULT NULL, documentnodeidentifier varchar(255) DEFAULT NULL, workspacename varchar(255) DEFAULT NULL, dimension longtext DEFAULT NULL COMMENT \'(DC2Type:array)\', dimensionshash varchar(32) DEFAULT NULL, PRIMARY KEY (uid), KEY eventtype (eventtype), KEY IDX_D6DBC30A5B684C08 (parentevent), KEY documentnodeidentifier (documentnodeidentifier), KEY dimensionshash (dimensionshash), KEY workspacename_parentevent (`workspacename`,`parentevent`), CONSTRAINT `FK_30AB3A75B684C08` FOREIGN KEY (`parentevent`) REFERENCES `neos_neos_eventlog_domain_model_event` (`uid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'); + } +} diff --git a/Neos.Neos/NodeTypes/Content/FallbackNode.yaml b/Neos.Neos/NodeTypes/FallbackNode.yaml similarity index 100% rename from Neos.Neos/NodeTypes/Content/FallbackNode.yaml rename to Neos.Neos/NodeTypes/FallbackNode.yaml diff --git a/Neos.Neos/NodeTypes/Mixin/Document.yaml b/Neos.Neos/NodeTypes/Mixin/Document.yaml index 41d37e48cea..f00b1f0dd85 100644 --- a/Neos.Neos/NodeTypes/Mixin/Document.yaml +++ b/Neos.Neos/NodeTypes/Mixin/Document.yaml @@ -11,6 +11,8 @@ constraints: nodeTypes: '*': false + # explicitly disallow to create a homepage below a regular document + 'Neos.Neos:Site': false 'Neos.Neos:Document': true postprocessors: 'CreationDialogPostprocessor': diff --git a/Neos.Neos/NodeTypes/Mixin/Site.yaml b/Neos.Neos/NodeTypes/Mixin/Site.yaml new file mode 100644 index 00000000000..c2d38ef77a3 --- /dev/null +++ b/Neos.Neos/NodeTypes/Mixin/Site.yaml @@ -0,0 +1,10 @@ +# +# Abstract NodeType for a Neos.Neos site. +# Each homepage must extend this NodeType. +# Nodes of this type must be direct children of the Neos.Neos:Site Root +# and must not be created at any other place in the tree. +# +'Neos.Neos:Site': + abstract: true + superTypes: + 'Neos.Neos:Document': true diff --git a/Neos.Neos/NodeTypes/Root/Sites.yaml b/Neos.Neos/NodeTypes/Root/Sites.yaml new file mode 100644 index 00000000000..229957b03dd --- /dev/null +++ b/Neos.Neos/NodeTypes/Root/Sites.yaml @@ -0,0 +1,11 @@ +# +# Root NodeType for a Neos.Neos content repository. +# Any Neos Site node must be its direct child. +# +'Neos.Neos:Sites': + superTypes: + 'Neos.ContentRepository:Root': true + constraints: + nodeTypes: + '*': false + 'Neos.Neos:Site': true diff --git a/Neos.Neos/NodeTypes/Unstructured.yaml b/Neos.Neos/NodeTypes/Unstructured.yaml new file mode 100644 index 00000000000..91b17e7d48e --- /dev/null +++ b/Neos.Neos/NodeTypes/Unstructured.yaml @@ -0,0 +1,5 @@ +# legacy type for nodes without type +'unstructured': + constraints: + nodeTypes: + '*': true diff --git a/Neos.Neos/Readme.rst b/Neos.Neos/Readme.rst index 3f58184c434..180132b1c77 100644 --- a/Neos.Neos/Readme.rst +++ b/Neos.Neos/Readme.rst @@ -18,3 +18,21 @@ Contribute If you want to contribute to Neos, please have a look at https://github.com/neos/neos-development-collection - it is the repository used for development and all pull requests should go into it. + + +Build frontend assets +--------------------- + +If you need to rebuild the frontend assets you need to run the following commands within the +Neos.Neos package directory: + +For develpment:: + + yarn + yarn build + +For production:: + + yarn + yarn build:production + diff --git a/Neos.Neos/Resources/Private/Fusion/Backend/History/Root.fusion b/Neos.Neos/Resources/Private/Fusion/Backend/History/Root.fusion deleted file mode 100644 index 23fa6fde2f8..00000000000 --- a/Neos.Neos/Resources/Private/Fusion/Backend/History/Root.fusion +++ /dev/null @@ -1,140 +0,0 @@ -include: resource://Neos.Fusion/Private/Fusion/Root.fusion - -Neos.Neos.Module.Management.HistoryController.index = Neos.Fusion:Template { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/Index.html' - eventsByDate = ${eventsByDate} - nextPage = ${nextPage} - - eventRenderer = Neos.Neos:History.EventRenderer -} - -prototype(Neos.Neos:History.EventRenderer) < prototype(Neos.Fusion:Case) { - nodeEvent { - condition = ${event.eventType == 'Node.Published'} - type = 'Neos.Neos:History.NodeEventRenderer' - } - - accountCreatedEvent { - condition = ${event.eventType == 'Account.Created'} - type = 'Neos.Neos:History.AccountCreatedEvent' - } - accountDeletedEvent { - condition = ${event.eventType == 'Account.Deleted'} - type = 'Neos.Neos:History.AccountDeletedEvent' - } -} - -# -# Node events -# - -prototype(Neos.Neos:History.NodeEventRenderer) < prototype(Neos.Fusion:Array) { - @context.documentEventsByType = ${Neos.Array.groupBy(Neos.Array.filter(event.childEvents, 'documentEvent'), 'eventType')} - @context.contentEventsByType = ${Neos.Array.groupBy(Neos.Array.filterNegated(event.childEvents, 'documentEvent'), 'eventType')} - - documentEvents = Neos.Fusion:Collection { - collection = ${documentEventsByType} - itemName = 'eventsOfMatchedType' - - itemRenderer = Neos.Fusion:Case { - default { - condition = true - type = ${'Neos.Neos:History.PublishedNode.' + Array.first(eventsOfMatchedType).eventType} - } - } - } - - contentEvents = Neos.Neos:History.PublishedNode.ContentChanged { - subEventType = ${Array.first(Array.first(contentEventsByType)).eventType} - @if.hasContentEvents = ${Array.length(contentEventsByType) > 0} - } -} - -prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) < prototype(Neos.Fusion:Template) { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/Index.html' - sectionName = 'eventElement' - - subEventType = ${Array.first(eventsOfMatchedType).eventType} - event = ${event} - linkedNode = Neos.Fusion:Template { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/NodeLink.html' - event = ${event} - @process.trim = ${String.trim(value)} - } - user = Neos.Fusion:Template { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/User.html' - event = ${event} - @process.trim = ${String.trim(value)} - } - -} - -prototype(Neos.Neos:History.PublishedNode.Node.Adopt) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.adopted' - descriptionTranslationArguments = ${[this.user, Neos.Rendering.renderDimensions(Array.first(eventsOfMatchedType).data.targetDimensions), I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.LabelChanged) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.renamed' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), Array.first(eventsOfMatchedType).data.oldLabel, this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.Added) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.added' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.Removed) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.removed' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.Copy) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.copied' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.Move) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.moved' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.Node.Updated) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.changed' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.ContentChanged) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationId = 'history.eventDescription.node.changedContent' - descriptionTranslationArguments = ${[this.user, I18n.translate(Neos.Rendering.labelForNodeType(event.data.nodeType)), this.linkedNode]} -} - -prototype(Neos.Neos:History.PublishedNode.MissingEvent) < prototype(Neos.Neos:History.PublishedNode.AbstractSubEvent) { - descriptionTranslationArguments = ${[this.user]} -} - -# -# Account events -# - -prototype(Neos.Neos:History.AbstractAccountEvent) < prototype(Neos.Fusion:Template) { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/Index.html' - sectionName = 'eventElement' - - user = Neos.Fusion:Template { - templatePath = 'resource://Neos.Neos/Private/Templates/Module/Management/History/User.html' - event = ${event} - } - - event = ${event} - descriptionTranslationArguments = ${[this.user, event.data.accountIdentifier, event.data.name]} -} - -prototype(Neos.Neos:History.AccountCreatedEvent) < prototype(Neos.Neos:History.AbstractAccountEvent) { - descriptionTranslationId = 'history.eventDescription.account.created' -} - -prototype(Neos.Neos:History.AccountDeletedEvent) < prototype(Neos.Neos:History.AbstractAccountEvent) { - descriptionTranslationId = 'history.eventDescription.account.deleted' -} - diff --git a/Neos.Neos/Resources/Private/Fusion/Backend/Views/Login.fusion b/Neos.Neos/Resources/Private/Fusion/Backend/Views/Login.fusion index 91a8b7cc997..7c8d824fc46 100644 --- a/Neos.Neos/Resources/Private/Fusion/Backend/Views/Login.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Backend/Views/Login.fusion @@ -88,9 +88,6 @@ prototype(Neos.Neos:View.Login) < prototype(Neos.Fusion:Component) { document.querySelector('.neos-login-btn').classList.toggle('neos-hidden'); document.querySelector('.neos-login-btn.neos-disabled').classList.toggle('neos-hidden'); }); - try { - document.querySelector('form[name=\"login\"] input[name=\"lastVisitedNode\"]').value = sessionStorage.getItem('Neos.Neos.lastVisitedNode'); - } catch(e) {} "}</script> </body> </html> @@ -111,7 +108,6 @@ prototype(Neos.Neos:Component.Login.Form) < prototype(Neos.Fusion:Component) { renderer = afx` <Neos.Fusion.Form:Form form.target.action="authenticate" attributes.name="login"> - <Neos.Fusion.Form:Hidden field.name="lastVisitedNode" /> <fieldset> <div class="neos-controls"> <Neos.Fusion.Form:Input @@ -152,7 +148,7 @@ prototype(Neos.Neos:Component.Login.Form) < prototype(Neos.Fusion:Component) { </script> <div class="neos-tooltip-arrow"></div> <div class="neos-tooltip-inner" role="alert"> - {I18n.id('flashMessage.' + flashMessage.code).value(flashMessage).package('Neos.Neos').source('Main')} + {flashMessage.message} </div> </div> </Neos.Fusion:Loop> @@ -160,4 +156,4 @@ prototype(Neos.Neos:Component.Login.Form) < prototype(Neos.Fusion:Component) { </fieldset> </Neos.Fusion.Form:Form> ` -} \ No newline at end of file +} diff --git a/Neos.Neos/Resources/Private/Fusion/Error/Root.fusion b/Neos.Neos/Resources/Private/Fusion/Error/Root.fusion index eb268cd26b6..8928db35a87 100644 --- a/Neos.Neos/Resources/Private/Fusion/Error/Root.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Error/Root.fusion @@ -1,4 +1,5 @@ include: resource://Neos.Fusion/Private/Fusion/Root.fusion +include: ../Prototypes/ErrorPage.fusion include: Views/*.fusion Neos.Fusion.FusionParserException = Neos.Neos:Error.View.FusionParserException { diff --git a/Neos.Neos/Resources/Private/Fusion/Error/Views/FusionParserException.fusion b/Neos.Neos/Resources/Private/Fusion/Error/Views/FusionParserException.fusion index 51ffb9cd382..39cd4982755 100644 --- a/Neos.Neos/Resources/Private/Fusion/Error/Views/FusionParserException.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Error/Views/FusionParserException.fusion @@ -5,7 +5,7 @@ prototype(Neos.Neos:Error.View.FusionParserException) < prototype(Neos.Fusion:Co flowPathRoot = '' renderer = afx` - <Neos.Neos:Error.View.Page title='Exception while parsing Fusion'> + <Neos.Neos:ErrorPage title='Exception while parsing Fusion'> <body class='neos'> <div class='neos-error-screen'> <h3>{String.htmlspecialchars(props.exception.headingMessagePart)}</h3> @@ -24,6 +24,6 @@ prototype(Neos.Neos:Error.View.FusionParserException) < prototype(Neos.Fusion:Co </details> </div> </body> - </Neos.Neos:Error.View.Page> + </Neos.Neos:ErrorPage> ` } diff --git a/Neos.Neos/Resources/Private/Fusion/ErrorCase.fusion b/Neos.Neos/Resources/Private/Fusion/ErrorCase.fusion index b5bc4aa1111..83f191b2043 100644 --- a/Neos.Neos/Resources/Private/Fusion/ErrorCase.fusion +++ b/Neos.Neos/Resources/Private/Fusion/ErrorCase.fusion @@ -10,10 +10,7 @@ error = Neos.Fusion:Case { default { @position = 'end 9999' condition = true - renderer = Neos.Fusion:Template { - templatePath = 'resource://Neos.Neos/Private/Templates/Error/Index.html' - layoutRootPath = 'resource://Neos.Neos/Private/Layouts/' - + renderer = Neos.Neos:DefaultExceptionRenderer { exception = ${exception} renderingOptions = ${renderingOptions} statusCode = ${statusCode} @@ -22,3 +19,29 @@ error = Neos.Fusion:Case { } } } + +/** @internal */ +prototype(Neos.Neos:DefaultExceptionRenderer) < prototype(Neos.Fusion:Component) { + /** @var exception \Exception */ + exception = null + renderingOptions = null + + renderer = afx` + <Neos.Neos:ErrorPage title='Neos Error'> + <body class="neos"> + <div class="neos-error-screen"> + <div class="neos-message-header"> + <div class="neos-message-icon"> + <i class="fas fa-exclamation-triangle"></i> + </div> + <h1>{Translation.id('error.exception.' + props.renderingOptions.renderingGroup + '.title').package('Neos.Neos').locale(Neos.Backend.interfaceLanguage()).translate()}</h1> + </div> + <p> + {String.nl2br(Translation.id('error.exception.' + props.renderingOptions.renderingGroup + '.description').package('Neos.Neos').locale(Neos.Backend.interfaceLanguage()).translate())} + </p> + <p @if={props.renderingOptions.renderTechnicalDetails} class="technical-details">#{props.exception.code}: {props.exception.message}</p> + </div> + </body> + </Neos.Neos:ErrorPage> + ` +} diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenu.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenu.fusion index 2e7903596d6..0a9b9fcc365 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenu.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenu.fusion @@ -1,17 +1,29 @@ # Neos.Neos:BreadcrumbMenu provides a breadcrumb navigation based on menu items. # -prototype(Neos.Neos:BreadcrumbMenu) < prototype(Neos.Neos:Menu) { - templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/BreadcrumbMenu.html' +prototype(Neos.Neos:BreadcrumbMenu) < prototype(Neos.Fusion:Component) { + attributes = Neos.Fusion:DataStructure - itemCollection = ${q(documentNode).parents('[instanceof Neos.Neos:Document]').get()} - // Show always the current node, event when it is hidden in index - items.@process.addCurrent = Neos.Fusion:Value { - currentItem = Neos.Neos:MenuItems { - renderHiddenInIndex = true - itemCollection = ${[documentNode]} - } - value = ${Array.concat(this.currentItem, value)} + @private { + items = Neos.Neos:BreadcrumbMenuItems { + @ignoreProperties = ${['attributes']} + @apply.props = ${props} + } } - attributes.class = 'breadcrumb' + renderer = Neos.Neos:MenuItemListRenderer { + items = ${private.items} + attributes = ${props.attributes} + } + + @exceptionHandler = 'Neos\\Fusion\\Core\\ExceptionHandlers\\ContextDependentHandler' + + @cache { + mode = 'cached' + entryIdentifier { + documentNode = ${Neos.Caching.entryIdentifierForNode(documentNode)} + } + entryTags { + 1 = ${Neos.Caching.nodeTypeTag('Neos.Neos:Document', documentNode)} + } + } } diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenuItems.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenuItems.fusion index e06d3b8790e..3e66c9b455e 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenuItems.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/BreadcrumbMenuItems.fusion @@ -1,10 +1,14 @@ prototype(Neos.Neos:BreadcrumbMenuItems) < prototype(Neos.Neos:MenuItems) { itemCollection = ${q(documentNode).parents('[instanceof Neos.Neos:Document]').get()} + maximumLevels = 0 + @process { // Show always the current node, event when it is hidden in index addCurrent = Neos.Fusion:Value { currentItem = Neos.Neos:MenuItems { + calculateItemStates = ${props.calculateItemStates} renderHiddenInIndex = true + maximumLevels = 0 itemCollection = ${[documentNode]} } value = ${Array.concat(this.currentItem, value)} diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Content.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Content.fusion index fbd82078ffd..f86689e8b42 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Content.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Content.fusion @@ -8,7 +8,7 @@ prototype(Neos.Neos:Content) < prototype(Neos.Fusion:Template) { node = ${node} - attributes = Neos.Fusion:Attributes + attributes = Neos.Fusion:DataStructure attributes.class = '' # The following is used to automatically append a class attribute that reflects the underlying node type of a Fusion object, @@ -18,7 +18,7 @@ prototype(Neos.Neos:Content) < prototype(Neos.Fusion:Template) { # attributes.class.@process.nodeType > # } # in your site's Fusion if you don't need that behavior. - attributes.class.@process.nodeType = ${Array.push(value, String.toLowerCase(String.pregReplace(node.nodeType.name, '/[[:^alnum:]]/', '-')))} + attributes.class.@process.nodeType = ${Array.push(value, String.toLowerCase(String.pregReplace(node.nodeTypeName.value, '/[[:^alnum:]]/', '-')))} # The following line must not be removed as it adds required meta data to all content elements in backend @process.contentElementWrapping { diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCase.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCase.fusion index 5a0a7152f0e..79bce3f566e 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCase.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/ContentCase.fusion @@ -6,6 +6,6 @@ prototype(Neos.Neos:ContentCase) < prototype(Neos.Fusion:Case) { default { @position = 'end' condition = true - type = ${node.nodeType.name} + type = ${Neos.Node.getNodeType(node).name.value} } } diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/DimensionsMenu.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/DimensionsMenu.fusion index bba25da41a0..fccffdb3e06 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/DimensionsMenu.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/DimensionsMenu.fusion @@ -1,34 +1,29 @@ # Neos.Neos:DimensionsMenu provides dimension (e.g. language) menu rendering -prototype(Neos.Neos:DimensionsMenu) < prototype(Neos.Neos:Menu) { - templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/DimensionsMenu.html' - - # the "absent" state is assigned to items for dimension (combinations) for which no node variant exists - absent.attributes = Neos.Fusion:Attributes { - class = 'normal' +prototype(Neos.Neos:DimensionsMenu) < prototype(Neos.Fusion:Component) { + attributes = Neos.Fusion:DataStructure + + @private { + items = Neos.Neos:DimensionsMenuItems { + @ignoreProperties = ${['attributes']} + @apply.props = ${props} + } } - # if documents which are hidden in index should be rendered or not - renderHiddenInIndex = true - - # name of the dimension to use (optional) - dimension = null - - # list of presets, if the default order should be overridden, only used with "dimension" set - presets = null - - # if true, items for all presets will be included, ignoring dimension constraints - includeAllPresets = false - - @context { - dimension = ${this.dimension} - presets = ${this.presets} - includeAllPresets = ${this.includeAllPresets} + renderer = Neos.Neos:MenuItemListRenderer { + items = ${private.items} + attributes = ${props.attributes} } - items = Neos.Neos:DimensionsMenuItems { - includeAllPresets = ${includeAllPresets} - dimension = ${dimension} - presets = ${presets} + @exceptionHandler = 'Neos\\Fusion\\Core\\ExceptionHandlers\\ContextDependentHandler' + + @cache { + mode = 'cached' + entryIdentifier { + documentNode = ${Neos.Caching.entryIdentifierForNode(documentNode)} + } + entryTags { + 1 = ${Neos.Caching.nodeTypeTag('Neos.Neos:Document', documentNode)} + } } } diff --git a/Neos.Neos/Resources/Private/Fusion/Error/Views/Page.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/ErrorPage.fusion similarity index 90% rename from Neos.Neos/Resources/Private/Fusion/Error/Views/Page.fusion rename to Neos.Neos/Resources/Private/Fusion/Prototypes/ErrorPage.fusion index 58c2788735c..bfeaf3e6924 100644 --- a/Neos.Neos/Resources/Private/Fusion/Error/Views/Page.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/ErrorPage.fusion @@ -1,4 +1,8 @@ -prototype(Neos.Neos:Error.View.Page) < prototype(Neos.Fusion:Component) { +/** + * Only for internal use! + * @internal + */ +prototype(Neos.Neos:ErrorPage) < prototype(Neos.Fusion:Component) { title = '' content = '' diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion index f82b10bca43..571d14fdc7a 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/FallbackNode.fusion @@ -1,4 +1,15 @@ -prototype(Neos.Neos:FallbackNode) < prototype(Neos.Neos:Content) { - templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/FallbackNode.html' +prototype(Neos.Neos:FallbackNode) < prototype(Neos.Neos:ContentComponent) { @if.onlyRenderInBackend = ${renderingMode.isEdit || renderingMode.isPreview} + + renderer = afx` + <div> + <div class="neos-message-header"> + <div class="neos-message-icon"><i class="fas fa-exclamation-triangle"></i></div> + <h1>{Translation.id('error.invalidNodeType.title').package('Neos.Neos').locale(Neos.Backend.interfaceLanguage()).translate()}</h1> + </div> + <div class="neos-message-wrapper"> + <p class="neos-message-content">{Translation.id('error.invalidNodeType.description').package('Neos.Neos').locale(Neos.Backend.interfaceLanguage()).translate()}</p> + </div> + </div> + ` } diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Menu.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Menu.fusion index 69b7a76c866..aca16e43107 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Menu.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Menu.fusion @@ -1,48 +1,18 @@ # Neos.Neos:Menu provides basic menu rendering # -prototype(Neos.Neos:Menu) < prototype(Neos.Fusion:Template) { - templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/Menu.html' +prototype(Neos.Neos:Menu) < prototype(Neos.Fusion:Component) { + attributes = Neos.Fusion:DataStructure - entryLevel = ${this.startingPoint ? 0 : 1} - maximumLevels = 2 - startingPoint = null - lastLevel = null - filter = 'Neos.Neos:Document' - renderHiddenInIndex = false - itemCollection = null - - node = ${node} - - attributes = Neos.Fusion:Attributes - - active.attributes = Neos.Fusion:Attributes { - class = 'active' - } - current.attributes = Neos.Fusion:Attributes { - class = 'current' - } - normal.attributes = Neos.Fusion:Attributes { - class = 'normal' - } - - @context { - entryLevel = ${this.entryLevel} - maximumLevels = ${this.maximumLevels} - startingPoint = ${this.startingPoint} - lastLevel = ${this.lastLevel} - filter = ${this.filter} - renderHiddenInIndex = ${this.renderHiddenInIndex} - itemCollection = ${this.itemCollection} + @private { + items = Neos.Neos:MenuItems { + @ignoreProperties = ${['attributes']} + @apply.props = ${props} + } } - items = Neos.Neos:MenuItems { - entryLevel = ${entryLevel} - maximumLevels = ${maximumLevels} - startingPoint = ${startingPoint} - lastLevel = ${lastLevel} - filter = ${filter} - renderHiddenInIndex = ${renderHiddenInIndex} - itemCollection = ${itemCollection} + renderer = Neos.Neos:MenuItemListRenderer { + items = ${private.items} + attributes = ${props.attributes} } @exceptionHandler = 'Neos\\Fusion\\Core\\ExceptionHandlers\\ContextDependentHandler' diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItemListRenderer.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItemListRenderer.fusion new file mode 100644 index 00000000000..54203902617 --- /dev/null +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItemListRenderer.fusion @@ -0,0 +1,17 @@ +# Neos.Neos:MenuItemListRenderer provides basic menu rendering +# +prototype(Neos.Neos:MenuItemListRenderer) < prototype(Neos.Fusion:Component) { + items = null + attributes = Neos.Fusion:DataStructure + + renderer = afx` + <ul {...props.attributes}> + <Neos.Fusion:Loop items={props.items} itemName="item"> + <li class={item.state}> + <Neos.Fusion:Tag tagName={item.uri ? 'a' : 'span'} attributes.href={item.uri} attributes.title={item.label}>{item.label}</Neos.Fusion:Tag> + <Neos.Neos:MenuItemListRenderer @if={item.children} items={item.children} /> + </li> + </Neos.Fusion:Loop> + </ul> + ` +} diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItems.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItems.fusion index 01dbeb06484..d2ef5d4b7f1 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItems.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/MenuItems.fusion @@ -9,6 +9,7 @@ prototype(Neos.Neos:MenuItems) { filter = 'Neos.Neos:Document' renderHiddenInIndex = false itemCollection = null + calculateItemStates = false // This property is used internally by `MenuItemsImplementation` to render each items uri. // It can be modified to change behaviour for all rendered uris. diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion index 59216dc14a1..b0cdf9685c0 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Page.fusion @@ -79,20 +79,6 @@ prototype(Neos.Neos:Page) < prototype(Neos.Fusion:Http.Message) { @process.appendJavaScripts = ${value + this.javascripts} } - # This enables redirecting to the last visited page after login - lastVisitedNodeScript = Neos.Fusion:Tag { - @position = 'before closingBodyTag' - - tagName = 'script' - attributes { - data-neos-node = ${Neos.Node.serializedNodeAddress(node)} - src = Neos.Fusion:ResourceUri { - path = 'resource://Neos.Neos/Public/JavaScript/LastVisitedNode.js' - } - async = true - } - } - closingBodyTag = '</body>' closingBodyTag.@position = 'end 100' diff --git a/Neos.Neos/Resources/Private/Fusion/Prototypes/Shortcut.fusion b/Neos.Neos/Resources/Private/Fusion/Prototypes/Shortcut.fusion index 0039b2efbd1..7ffe67d67e5 100644 --- a/Neos.Neos/Resources/Private/Fusion/Prototypes/Shortcut.fusion +++ b/Neos.Neos/Resources/Private/Fusion/Prototypes/Shortcut.fusion @@ -1,15 +1,96 @@ # Neos.Neos.Shortcut is given a representation for editing purposes # -prototype(Neos.Neos:Shortcut) < prototype(Neos.Fusion:Template) { - templatePath = 'resource://Neos.Neos/Private/Templates/FusionObjects/Shortcut.html' +prototype(Neos.Neos:Shortcut) < prototype(Neos.Neos:Page) { + head.stylesheets { + shortcut = afx` + <link rel="stylesheet" href={StaticResource.uri('Neos.Neos', 'Public/Styles/Shortcut.css')} /> + ` + } + body = afx` + <div id="neos-shortcut"> + <p> + <Neos.Neos:Shortcut.Link /> + </p> + </div> + ` +} + +/** @internal */ +prototype(Neos.Neos:Shortcut.Link) < prototype(Neos.Fusion:Component) { targetMode = ${q(node).property('targetMode')} firstChildNode = ${q(node).children('[instanceof Neos.Neos:Document]').get(0)} target = ${q(node).property('target')} targetConverted = ${Neos.Link.hasSupportedScheme(this.target) ? Neos.Link.convertUriToObject(this.target, node) : null} targetSchema = ${Neos.Link.getScheme(this.target)} - node = ${node} + i18n = ${I18n.id(null).package('Neos.Neos').source('Main').locale(Neos.Backend.interfaceLanguage())} + + renderer = Neos.Fusion:Match { + @subject = ${props.targetMode} + + selectedTarget = Neos.Fusion:Join { + @glue = '<br/>' + mainMessage = ${props.i18n.id('shortcut.toSpecificTarget').translate()} + targetSelected = Neos.Fusion:Match { + @if.isTarget = ${props.target} + + @subject = ${props.targetSchema} + + node = Neos.Fusion:Value { + targetUriTag = Neos.Neos:NodeLink { + node = ${props.targetConverted} + } + value = ${props.i18n.id('shortcut.clickToContinueToPage').arguments([this.targetUriTag]).translate()} + } + + asset = Neos.Fusion:Value { + targetUriTag = Neos.Fusion:Tag { + tagName = 'a' + attributes { + target = '_blank' + href = Neos.Fusion:ResourceUri { + resource = ${props.targetConverted.resource} + } + } + content = ${props.targetConverted.label} + } + value = ${props.i18n.id('shortcut.clickToContinueToAsset').arguments([this.targetUriTag]).translate()} + } + + @default = Neos.Fusion:Value { + targetUriTag = afx` + <a href={props.target} target='_blank'>{props.target}</a> + ` + value = ${props.i18n.id('shortcut.clickToContinueToExternalUrl').arguments([this.targetUriTag]).translate()} + } + } + + noTargetSelected = ${props.i18n.id('shortcut.noTargetSelected').translate()} + noTargetSelected.@if.isNotTarget = ${!props.target} + } + + firstChildNode = Neos.Fusion:Value { + targetUriTag = Neos.Neos:NodeLink { + node = ${props.firstChildNode} + } + value = ${props.i18n.id('shortcut.clickToContinueToFirstChildNode').arguments([this.targetUriTag]).translate()} + } + + parentNode = Neos.Fusion:Value { + targetUriTag = Neos.Neos:NodeLink { + node = ${q(node).parent().get(0)} + } + value = ${props.i18n.id('shortcut.clickToContinueToParentNode').arguments([this.targetUriTag]).translate()} + } + } + + @cache { + mode = "uncached" + context { + 0 = "node" + } + } @exceptionHandler = 'Neos\\Neos\\Fusion\\ExceptionHandlers\\NodeWrappingHandler' } diff --git a/Neos.Neos/Resources/Private/Fusion/RawContent/Node.fusion b/Neos.Neos/Resources/Private/Fusion/RawContent/Node.fusion index c977e308285..47ac7fb8562 100644 --- a/Neos.Neos/Resources/Private/Fusion/RawContent/Node.fusion +++ b/Neos.Neos/Resources/Private/Fusion/RawContent/Node.fusion @@ -1,6 +1,6 @@ prototype(Neos.Neos:RawContent.Node) < prototype(Neos.Neos:ContentComponent) { - nodeType = ${node.nodeType.name} + nodeType = ${node.nodeTypeName.value} renderer = Neos.Fusion:Case { custom { diff --git a/Neos.Neos/Resources/Private/Fusion/RootCase.fusion b/Neos.Neos/Resources/Private/Fusion/RootCase.fusion index 957c8d4fd18..7a7f304c411 100644 --- a/Neos.Neos/Resources/Private/Fusion/RootCase.fusion +++ b/Neos.Neos/Resources/Private/Fusion/RootCase.fusion @@ -6,13 +6,11 @@ root = Neos.Fusion:Case root { shortcut { - prototype(Neos.Neos:Page) { - body = Neos.Neos:Shortcut - } - + # this code path will only be taken for backend views, as the node controller + # will take care of resolving the shortcut in the frontend @position = 'start' condition = ${q(node).is('[instanceof Neos.Neos:Shortcut]')} - type = 'Neos.Neos:Page' + renderer = Neos.Neos:Shortcut } editPreviewMode { @@ -30,9 +28,9 @@ root { documentType { @position = 'end 9998' condition = Neos.Fusion:CanRender { - type = ${documentNode.nodeType.name} + type = ${documentNode.nodeTypeName.value} } - type = ${documentNode.nodeType.name} + type = ${documentNode.nodeTypeName.value} } default { @@ -45,7 +43,7 @@ root { rawContent { @position = 'end 10000' - condition = ${Neos.Node.inBackend(documentNode) && documentNode.context.currentRenderingMode.edit} + condition = ${renderingMode.isEdit} renderPath = '/rawContent' } @@ -53,7 +51,7 @@ root { error { @position = 'end 10001' condition = true - type = ${documentNode.nodeType.name} + type = ${documentNode.nodeTypeName.value} } @cache { diff --git a/Neos.Neos/Resources/Private/Partials/Module/Management/Workspaces/ContentChangeAttributes.html b/Neos.Neos/Resources/Private/Partials/Module/Management/Workspaces/ContentChangeAttributes.html index 8322fe6ad2b..0568d7d1c06 100644 --- a/Neos.Neos/Resources/Private/Partials/Module/Management/Workspaces/ContentChangeAttributes.html +++ b/Neos.Neos/Resources/Private/Partials/Module/Management/Workspaces/ContentChangeAttributes.html @@ -1,16 +1,16 @@ {namespace neos=Neos\Neos\ViewHelpers} <f:if condition="{change.isRemoved}"> - <f:then>class="neos-content-change legend-deleted" data-nodepath="{change.node.path}" title="{neos:backend.translate(id: 'workspaces.legend.deleted', source: 'Modules', package: 'Neos.Neos')}"</f:then> + <f:then>class="neos-content-change legend-deleted" data-nodepath="{nodepath}" title="{neos:backend.translate(id: 'workspaces.legend.deleted', source: 'Modules', package: 'Neos.Neos')}"</f:then> <f:else> <f:if condition="{change.isNew}"> - <f:then>class="neos-content-change legend-created" data-nodepath="{change.node.path}" title="{neos:backend.translate(id: 'workspaces.legend.created', source: 'Modules', package: 'Neos.Neos')}"</f:then> + <f:then>class="neos-content-change legend-created" data-nodepath="{nodepath}" title="{neos:backend.translate(id: 'workspaces.legend.created', source: 'Modules', package: 'Neos.Neos')}"</f:then> <f:else> <f:if condition="{change.isMoved}"> - <f:then>class="neos-content-change legend-moved" data-nodepath="{change.node.path}" title="{neos:backend.translate(id: 'workspaces.legend.moved', source: 'Modules', package: 'Neos.Neos')}"</f:then> + <f:then>class="neos-content-change legend-moved" data-nodepath="{nodepath}" title="{neos:backend.translate(id: 'workspaces.legend.moved', source: 'Modules', package: 'Neos.Neos')}"</f:then> <f:else> <f:if condition="{change.node.hidden}"> - <f:then>class="neos-content-change legend-hidden" data-nodepath="{change.node.path}" title="{neos:backend.translate(id: 'workspaces.legend.hidden', source: 'Modules', package: 'Neos.Neos')}"</f:then> - <f:else>class="neos-content-change legend-edited" data-nodepath="{change.node.path}" title="{neos:backend.translate(id: 'workspaces.legend.edited', source: 'Modules', package: 'Neos.Neos')}"</f:else> + <f:then>class="neos-content-change legend-hidden" data-nodepath="{nodepath}" title="{neos:backend.translate(id: 'workspaces.legend.hidden', source: 'Modules', package: 'Neos.Neos')}"</f:then> + <f:else>class="neos-content-change legend-edited" data-nodepath="{nodepath}" title="{neos:backend.translate(id: 'workspaces.legend.edited', source: 'Modules', package: 'Neos.Neos')}"</f:else> </f:if> </f:else> </f:if> diff --git a/Neos.Neos/Resources/Private/Styles/Neos.scss b/Neos.Neos/Resources/Private/Styles/Main.scss similarity index 100% rename from Neos.Neos/Resources/Private/Styles/Neos.scss rename to Neos.Neos/Resources/Private/Styles/Main.scss diff --git a/Neos.Neos/Resources/Private/Styles/Modules/Management/_History.scss b/Neos.Neos/Resources/Private/Styles/Modules/Management/_History.scss deleted file mode 100644 index 972a593916d..00000000000 --- a/Neos.Neos/Resources/Private/Styles/Modules/Management/_History.scss +++ /dev/null @@ -1,129 +0,0 @@ -&.neos-module-management-history { - $dateSize: $unit * 2; - - .neos-history-events-divider { - margin: 0; - padding: 0; - border: 2px solid $grayMedium; - } - - .neos-history { - max-width: 1000px; - margin: 0 auto; - } - - .neos-history-day { - .neos-history-date { - margin-left: 50%; - - .neos-history-date-inner { - text-align: center; - line-height: $dateSize; - overflow: hidden; - - border-radius: 50%; - width: $dateSize; - height: $dateSize; - background: $blueDark; - margin-left: -(($dateSize/2)+2); - font-size: 100%; - border: solid 4px $grayMedium; - } - } - - .neos-history-events { - width: 50%; - padding-top: $unit / 2; - - &::after { - border: 1px solid rgba(0, 0, 0, 0); - content: ""; - clear: both; - } - .neos-history-event { - text-align: left; - clear: both; - position: relative; - padding-top: $relatedMargin; - padding-right: $defaultMargin; - - &::after { - border: 1px solid rgba(0, 0, 0, 0); - content: ""; - clear: both; - } - - .neos-history-event-user { - border-radius: 50%; - width: $unit; - height: $unit; - background: $blueDark; - overflow: hidden; - text-align: center; - line-height: $unit; - float: left; - border: 4px solid $grayMedium; - margin-right: 20px; - } - - .neos-history-event-time { - } - - .neos-history-event-description { - padding: 5px; - margin-right: 20px; - - a { - text-decoration: underline; - } - } - } - } - } - - .neos-history-day:nth-child(even) { - .neos-history-events { - &.neos-history-alignment { - text-align: right; - border-right: 4px solid $grayMedium; - - .neos-history-event-time { - float: right; - margin-right: 10px; - width: 65px; - text-align: right; - } - } - } - } - .neos-history-day:nth-child(odd) { - .neos-history-events { - &.neos-history-alignment { - text-align: left; - margin-left: 50%; - border-left: 4px solid $grayMedium; - - .neos-history-event-time { - float: left; - margin-left: 10px; - width: 65px; - text-align: left; - } - } - } - } - - .neos-history-group { - .neos-history-group-user { - } - } - - .loadMore { - text-align: center; - - button { - margin-top: 25px; - margin-bottom: 25px; - } - } -} diff --git a/Neos.Neos/Resources/Private/Styles/Modules/_Modules.scss b/Neos.Neos/Resources/Private/Styles/Modules/_Modules.scss index 97c637d2be6..1d568f26222 100755 --- a/Neos.Neos/Resources/Private/Styles/Modules/_Modules.scss +++ b/Neos.Neos/Resources/Private/Styles/Modules/_Modules.scss @@ -2,7 +2,6 @@ @import "Administration/Configuration"; @import "Administration/Packages"; @import "Administration/Sites"; - @import "Management/History"; @import "Management/Workspaces"; @include font; diff --git a/Neos.Neos/Resources/Private/Styles/Shortcut.scss b/Neos.Neos/Resources/Private/Styles/Shortcut.scss new file mode 100644 index 00000000000..5a80bb6f8bb --- /dev/null +++ b/Neos.Neos/Resources/Private/Styles/Shortcut.scss @@ -0,0 +1,32 @@ +#neos-shortcut { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: $grayMedium; + z-index: 9999; + @include font; + + p { + position: relative; + margin: 0 auto; + width: 500px; + height: 60px; + top: 50%; + margin-top: -30px; + color: #fff; + font-size: 22px; + line-height: 1.4; + text-align: center; + + a { + color: $blue; + text-decoration: none; + + &:hover { + color: $blueLight; + } + } + } +} diff --git a/Neos.Neos/Resources/Private/Styles/_Global.scss b/Neos.Neos/Resources/Private/Styles/_Global.scss index 76d8bea161c..b44a7102229 100644 --- a/Neos.Neos/Resources/Private/Styles/_Global.scss +++ b/Neos.Neos/Resources/Private/Styles/_Global.scss @@ -5,36 +5,3 @@ .neos-rendering-exception { word-wrap: break-word; } - -#neos-shortcut { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: $grayMedium; - z-index: 9999; - @include font; - - p { - position: relative; - margin: 0 auto; - width: 500px; - height: 60px; - top: 50%; - margin-top: -30px; - color: #fff; - font-size: 22px; - line-height: 1.4; - text-align: center; - - a { - color: $blue; - text-decoration: none; - - &:hover { - color: $blueLight; - } - } - } -} diff --git a/Neos.Neos/Resources/Private/Templates/Error/Index.html b/Neos.Neos/Resources/Private/Templates/Error/Index.html deleted file mode 100755 index b78250efe90..00000000000 --- a/Neos.Neos/Resources/Private/Templates/Error/Index.html +++ /dev/null @@ -1,28 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -<f:layout name="Default" /> - -<f:section name="head"> - <title>Neos Error - - - - - -
-
-
- -
-

{neos:backend.translate(id: 'error.exception.{renderingOptions.renderingGroup}.title', package: 'Neos.Neos')}

-
-

{neos:backend.translate(id: 'error.exception.{renderingOptions.renderingGroup}.description', package: 'Neos.Neos') -> f:format.nl2br()}

- -

#{exception.code}: {exception.message}

-
- -

{neos:backend.translate(id: 'error.exception.{renderingOptions.renderingGroup}.setupMessage', package: 'Neos.Neos')}

-

{neos:backend.translate(id: 'error.exception.goToSetup', package: 'Neos.Neos')}

-
-
- -
diff --git a/Neos.Neos/Resources/Private/Templates/FusionObjects/BreadcrumbMenu.html b/Neos.Neos/Resources/Private/Templates/FusionObjects/BreadcrumbMenu.html deleted file mode 100644 index f96b3e7c63c..00000000000 --- a/Neos.Neos/Resources/Private/Templates/FusionObjects/BreadcrumbMenu.html +++ /dev/null @@ -1,18 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -{namespace ts=Neos\Fusion\ViewHelpers} - - f:format.raw()}> - - f:format.raw()}> - - - {item.label} - - - {item.label} - - - - - - diff --git a/Neos.Neos/Resources/Private/Templates/FusionObjects/DimensionsMenu.html b/Neos.Neos/Resources/Private/Templates/FusionObjects/DimensionsMenu.html deleted file mode 100644 index 4b646319db0..00000000000 --- a/Neos.Neos/Resources/Private/Templates/FusionObjects/DimensionsMenu.html +++ /dev/null @@ -1,22 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -{namespace ts=Neos\Fusion\ViewHelpers} - f:format.raw()}> - - f:format.raw()}> - - - - - - - - - - - - - - - - {item.label} - diff --git a/Neos.Neos/Resources/Private/Templates/FusionObjects/FallbackNode.html b/Neos.Neos/Resources/Private/Templates/FusionObjects/FallbackNode.html deleted file mode 100644 index f9d73915fa9..00000000000 --- a/Neos.Neos/Resources/Private/Templates/FusionObjects/FallbackNode.html +++ /dev/null @@ -1,10 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} - f:format.raw()}> -
-
-

{neos:backend.translate(id: 'error.invalidNodeType.title', package: 'Neos.Neos')}

-
-
-

{neos:backend.translate(id: 'error.invalidNodeType.description', package: 'Neos.Neos')}

-
- diff --git a/Neos.Neos/Resources/Private/Templates/FusionObjects/Menu.html b/Neos.Neos/Resources/Private/Templates/FusionObjects/Menu.html deleted file mode 100644 index 27f33b88ebe..00000000000 --- a/Neos.Neos/Resources/Private/Templates/FusionObjects/Menu.html +++ /dev/null @@ -1,18 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -{namespace ts=Neos\Fusion\ViewHelpers} - f:format.raw()}> - - - - - - f:format.raw()}> - {item.label} - -
    - -
-
- -
-
diff --git a/Neos.Neos/Resources/Private/Templates/FusionObjects/Shortcut.html b/Neos.Neos/Resources/Private/Templates/FusionObjects/Shortcut.html deleted file mode 100644 index 6fa8120681a..00000000000 --- a/Neos.Neos/Resources/Private/Templates/FusionObjects/Shortcut.html +++ /dev/null @@ -1,44 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -
-

- - - {neos:backend.translate(id: 'shortcut.toSpecificTarget', value: 'This is a shortcut to a specific target:')}
- - - - - - Click to continue to the page. - - - - {targetConverted.label}'}"> - Click {targetConverted.label} to see the file. - - - - {target}'}"> - Click {target} to open the link. - - - - - {neos:backend.translate(id: 'shortcut.noTargetSelected', value: '(no target has been selected)')} - -
- - - This is a shortcut to the first child page.
- Click to continue to the page. -
-
- - - This is a shortcut to the parent page.
- Click to continue to the page. -
-
-
-

-
diff --git a/Neos.Neos/Resources/Private/Templates/Module/Management/History/Index.html b/Neos.Neos/Resources/Private/Templates/Module/Management/History/Index.html deleted file mode 100644 index 552056fc2a0..00000000000 --- a/Neos.Neos/Resources/Private/Templates/Module/Management/History/Index.html +++ /dev/null @@ -1,84 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -{namespace ts=Neos\Fusion\ViewHelpers} - -
- {neos:backend.translate(id: 'history.messages.hereIsWhatHappenedRecentlyInNeos', source: 'Modules')} - - - -
-
-
{eventsOnSingleDay.day -> f:format.date(format: 'M d')} -
-
-
-
- - - -
-
-
-
- -

{neos:backend.translate(id: 'history.messages.emptyHistory', source: 'Modules')}

-
-
-
- - -
-
{event.timestamp -> f:format.date(format: 'H:i')}
-
- {event.accountIdentifier -> neos:backend.userInitials()} -
-
- {neos:backend.translate(id: descriptionTranslationId, source: 'Modules', arguments: descriptionTranslationArguments) -> f:format.raw()} -
-
-
- - -
- -
-
- - diff --git a/Neos.Neos/Resources/Private/Templates/Module/Management/History/NodeLink.html b/Neos.Neos/Resources/Private/Templates/Module/Management/History/NodeLink.html deleted file mode 100644 index afa4dda4f7d..00000000000 --- a/Neos.Neos/Resources/Private/Templates/Module/Management/History/NodeLink.html +++ /dev/null @@ -1,5 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} - - {event.data.nodeLabel} - {event.data.nodeLabel} - diff --git a/Neos.Neos/Resources/Private/Templates/Module/Management/History/User.html b/Neos.Neos/Resources/Private/Templates/Module/Management/History/User.html deleted file mode 100644 index 31c3f617a37..00000000000 --- a/Neos.Neos/Resources/Private/Templates/Module/Management/History/User.html +++ /dev/null @@ -1,2 +0,0 @@ -{namespace neos=Neos\Neos\ViewHelpers} -{event.accountIdentifier -> neos:backend.userInitials(format: 'fullFirstName')} diff --git a/Neos.Neos/Resources/Private/Templates/Module/Management/Workspaces/Show.html b/Neos.Neos/Resources/Private/Templates/Module/Management/Workspaces/Show.html index ec5e58e00d4..f3c0bf613b8 100644 --- a/Neos.Neos/Resources/Private/Templates/Module/Management/Workspaces/Show.html +++ b/Neos.Neos/Resources/Private/Templates/Module/Management/Workspaces/Show.html @@ -28,11 +28,11 @@ - + - + @@ -56,15 +56,15 @@ - + - + - + diff --git a/Neos.Neos/Resources/Private/Templates/Service/Nodes/Index.html b/Neos.Neos/Resources/Private/Templates/Service/Nodes/Index.html index 95b517807d9..7f112b3b14a 100644 --- a/Neos.Neos/Resources/Private/Templates/Service/Nodes/Index.html +++ b/Neos.Neos/Resources/Private/Templates/Service/Nodes/Index.html @@ -27,7 +27,7 @@

{neos:backend.translate(id: 'service.nodes.title', value: 'Nodes')}

({node.nodeAggregateId.value}) - [{node.nodeType.name}] + [{node.nodeTypeName.value}] {neos:backend.translate(id: 'service.nodes.show', value: 'Show')}
diff --git a/Neos.Neos/Resources/Private/Templates/Service/Nodes/Show.html b/Neos.Neos/Resources/Private/Templates/Service/Nodes/Show.html index 34f2ff8a711..7c1f2816b76 100644 --- a/Neos.Neos/Resources/Private/Templates/Service/Nodes/Show.html +++ b/Neos.Neos/Resources/Private/Templates/Service/Nodes/Show.html @@ -25,7 +25,7 @@

{neos:backend.translate(id: 'node', value: 'Node')}: {node.label}

_type - {node.nodeType.name} + {node.nodeTypeName.value} diff --git a/Neos.Neos/Resources/Private/Translations/ar/Main.xlf b/Neos.Neos/Resources/Private/Translations/ar/Main.xlf index e98e217cb37..1c1dc971278 100644 --- a/Neos.Neos/Resources/Private/Translations/ar/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/ar/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/ar/Modules.xlf b/Neos.Neos/Resources/Private/Translations/ar/Modules.xlf index 541292d6964..53ee93e5eb0 100644 --- a/Neos.Neos/Resources/Private/Translations/ar/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/ar/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. تم تجاهل كافة التغييرات في فضاء العمل "{0}". - - History - التاريخ - - - This module provides an overview of all relevant events affecting this Neos installation. - هذه الوحدة توفر لمحة عامة عن جميع الأحداث ذات الصلة التي تؤثر على هذا التثبيت لنيوس. - - - Here's what happened recently in Neos - هنا ما حدث مؤخرا في نيوس - - - There have not been recorded any events yet which could be displayed in this history. - أنه لم يتم تسجيل أية أحداث بعد الذي يمكن أن يتم عرضها في هذا التاريخ. - - - {0} created the {1} "{2}". - {0} انشأ ال{1} "{2}". - - - {0} removed the {1} "{2}". - {0} ازال ال{1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - قام {0} بإنشاء المتغير {1} من {2} "{3}". - - - {0} modified the {1} "{2}". - {0} قام بتغيير {1} "{2}". - - - {0} moved the {1} "{2}". - {0} قام بنقل {1} "{2}". - - - {0} copied the {1} "{2}". - {0} قام بنسخ {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} أعادت تسمية {1} "{2}" إلى"{3}". - - - {0} modified content on the {1} "{2}". - {0} مُحتوى مُعدّل على {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} إنشاء مستخدم جديد "{1}" ل {2}. - - - {0} deleted the account "{1}" of {2}. - {0} حذف الحساب "{1}" من {2}. - - - Load More - تحميل المزيد - - - This node has been removed in the meantime - تم إزالة هذه العقدة في الوقت نفسه - Administration diff --git a/Neos.Neos/Resources/Private/Translations/cs/Main.xlf b/Neos.Neos/Resources/Private/Translations/cs/Main.xlf index 38ae665d9d8..143ace064e4 100644 --- a/Neos.Neos/Resources/Private/Translations/cs/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/cs/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/cs/Modules.xlf b/Neos.Neos/Resources/Private/Translations/cs/Modules.xlf index 49b0e68b1fa..533c2fe2a02 100644 --- a/Neos.Neos/Resources/Private/Translations/cs/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/cs/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - Historie - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} vytvořil {1} "{2}". - - - {0} removed the {1} "{2}". - {0} odebrán {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} vytvořil variantu {1} z {2} "{3}". - - - {0} modified the {1} "{2}". - {0} změněn {1} "{2}". - - - {0} moved the {1} "{2}". - {0} přesunut {1} "{2}". - - - {0} copied the {1} "{2}". - {0} zkopírováno {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} přejmenováno {1} "{2}" na "{3}". - - - {0} modified content on the {1} "{2}". - {0} změněný obsah na {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/da/Main.xlf b/Neos.Neos/Resources/Private/Translations/da/Main.xlf index 5ade19b957b..ba95ccf4144 100644 --- a/Neos.Neos/Resources/Private/Translations/da/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/da/Main.xlf @@ -951,10 +951,6 @@ Fejl ved indlæsning. - - The entered username or password was wrong - Indtastede brugernavn eller adgangskode er forkert - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/da/Modules.xlf b/Neos.Neos/Resources/Private/Translations/da/Modules.xlf index a39138d60dc..6d3a4b20a17 100644 --- a/Neos.Neos/Resources/Private/Translations/da/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/da/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Alle ændringer fra arbejdsrummet "{0}" er blevet kasseret. - - History - Historik - - - This module provides an overview of all relevant events affecting this Neos installation. - Dette modul giver et overblik over alle relevante begivenheder, der påvirker denne Neos installation. - - - Here's what happened recently in Neos - Her er, hvad der er sket for nyligt i Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Der er endnu ikke registreret nogen begivenheder, der kunne vises i denne historik. - - - {0} created the {1} "{2}". - {0} oprettede {1} {2}. - - - {0} removed the {1} "{2}". - {0} fjernede {1} {2}. - - - {0} created the variant {1} of the {2} "{3}". - {0} oprettede varianten {1} af {2} {3}. - - - {0} modified the {1} "{2}". - {0} ændrede {1} "{2}". - - - {0} moved the {1} "{2}". - {0} flyttede {1} "{2}". - - - {0} copied the {1} "{2}". - {0} kopierede {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} omdøbte {1} "{2}" til "{3}". - - - {0} modified content on the {1} "{2}". - {0} ændrede indhold på {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} oprettede en ny bruger "{1}" til {2}. - - - {0} deleted the account "{1}" of {2}. - {0} slettede kontoen "{1}" fra {2}. - - - Load More - Indlæs flere - - - This node has been removed in the meantime - Dette element er blevet fjernet i mellemtiden - Administration diff --git a/Neos.Neos/Resources/Private/Translations/de/Main.xlf b/Neos.Neos/Resources/Private/Translations/de/Main.xlf index cb4702d29dd..c1af77d58ac 100644 --- a/Neos.Neos/Resources/Private/Translations/de/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/de/Main.xlf @@ -951,10 +951,6 @@ Beim Laden des Nodetrees trat ein Fehler auf. - - The entered username or password was wrong - Der eingegebene Benutzername oder das Kennwort war falsch - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/de/Modules.xlf b/Neos.Neos/Resources/Private/Translations/de/Modules.xlf index cf68c41c3c2..9ca71770fb7 100644 --- a/Neos.Neos/Resources/Private/Translations/de/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/de/Modules.xlf @@ -271,70 +271,6 @@ Select all current changes Alle aktuellen Änderungen auswählen - - History - Verlauf - - - This module provides an overview of all relevant events affecting this Neos installation. - Dieses Modul bietet einen Überblick über alle relevanten Ereignisse die diese Neos-Installation betreffen. - - - Here's what happened recently in Neos - Dies ist kürzlich in Neos geschehen: - - - There have not been recorded any events yet which could be displayed in this history. - Es wurden noch keine Ereignisse aufgezeichnet die in diesem Verlauf dargestellt werden könnten. - - - {0} created the {1} "{2}". - {0} hat {1} "{2}" erstellt. - - - {0} removed the {1} "{2}". - {0} hat {1} "{2}" entfernt. - - - {0} created the variant {1} of the {2} "{3}". - {0} hat die Variante {1} von {2} "{3}" erstellt. - - - {0} modified the {1} "{2}". - {0} hat {1} "{2}" bearbeitet. - - - {0} moved the {1} "{2}". - {0} hat {1} "{2}" verschoben. - - - {0} copied the {1} "{2}". - {0} hat {1} "{2}" kopiert. - - - {0} renamed the {1} "{2}" to "{3}". - {0} hat {1} "{2}" zu "{3}" umbenannt. - - - {0} modified content on the {1} "{2}". - {0} hat den Inhalt von {1} "{2}" bearbeitet. - - - {0} created a new user "{1}" for {2}. - {0} hat einen neuen Benutzer "{1}" für {2} angelegt. - - - {0} deleted the account "{1}" of {2}. - {0} hat den Benutzer "{1}" von {2} gelöscht. - - - Load More - Mehr laden - - - This node has been removed in the meantime - Dieser Node wurde in der Zwischenzeit entfernt - Administration diff --git a/Neos.Neos/Resources/Private/Translations/el/Main.xlf b/Neos.Neos/Resources/Private/Translations/el/Main.xlf index 722a6dae6c0..ac87481d949 100644 --- a/Neos.Neos/Resources/Private/Translations/el/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/el/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/el/Modules.xlf b/Neos.Neos/Resources/Private/Translations/el/Modules.xlf index 3e2925aa27e..30fd517c90b 100644 --- a/Neos.Neos/Resources/Private/Translations/el/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/el/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - History - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/en/Main.xlf b/Neos.Neos/Resources/Private/Translations/en/Main.xlf index 8bc8cfbd1d4..f05e47f60fd 100644 --- a/Neos.Neos/Resources/Private/Translations/en/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/en/Main.xlf @@ -729,11 +729,6 @@ Node Tree loading error. - - - The entered username or password was wrong - - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/en/Modules.xlf b/Neos.Neos/Resources/Private/Translations/en/Modules.xlf index 6ffc7f45715..4d6370aa8fc 100755 --- a/Neos.Neos/Resources/Private/Translations/en/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/en/Modules.xlf @@ -206,55 +206,6 @@ Select all current changes - - History - - - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - - - Load More - - - This node has been removed in the meantime - - Administration diff --git a/Neos.Neos/Resources/Private/Translations/es/Main.xlf b/Neos.Neos/Resources/Private/Translations/es/Main.xlf index 16d9dda7471..76ab46244d7 100644 --- a/Neos.Neos/Resources/Private/Translations/es/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/es/Main.xlf @@ -951,10 +951,6 @@ Error cargando el árbol de nodos. - - The entered username or password was wrong - El nombre de usuario o la contraseña introducido estaba mal - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/es/Modules.xlf b/Neos.Neos/Resources/Private/Translations/es/Modules.xlf index 376457f4275..81af8328326 100644 --- a/Neos.Neos/Resources/Private/Translations/es/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/es/Modules.xlf @@ -259,70 +259,6 @@ All changes from workspace "{0}" have been discarded. Todos los cambios del espacio de trabajo "{0}" han sido descartados. - - History - Historial - - - This module provides an overview of all relevant events affecting this Neos installation. - Este módulo proporciona una visión general de todos los eventos relevantes que afectan a esta instalación de Neos. - - - Here's what happened recently in Neos - Esto es lo que ocurrió recientemente en Neos - - - There have not been recorded any events yet which could be displayed in this history. - Aún no se ha registrado ningún evento que podamos mostrar en esta historia. - - - {0} created the {1} "{2}". - {0} Creado el {1} "{2}". - - - {0} removed the {1} "{2}". - {0} eliminó el {1}"{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} creó la variante {1} del {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modificado el {1} "{2}". - - - {0} moved the {1} "{2}". - {0} movió el {1} "{2}". - - - {0} copied the {1} "{2}". - {0} ha copiado el {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renombró el {1} "{2}" a "{3}". - - - {0} modified content on the {1} "{2}". - {0} modificó contenido el {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} creó un nuevo usuario "{1}" para {2}. - - - {0} deleted the account "{1}" of {2}. - {0} borró la cuenta "{1}" de {2}. - - - Load More - Cargar más - - - This node has been removed in the meantime - Mientras tanto, este nodo ha sido eliminado - Administration @@ -868,8 +804,8 @@ The inter dimensional fallback graph displays all possible fallbacks (displayed as edges) between subgraphs (content dimension value combinations, displayed as nodes). Primary fallbacks are marked blue and always visible, while lower priority fallbacks are shown on mouseover. The higher the priority the higher the opacity. Click on one of the nodes to only see its fallbacks and variants. Click again to remove the filter. - El gráfico de respaldo interdimensional muestra todos los posibles respaldos (mostrados como bordes) entre subgráficos (combinaciones de valores de dimensión de contenido, mostrados como nodos). -Los recursos alternativos primarios están marcados en azul y siempre visibles, mientras que los recursos alternativos de menor prioridad se muestran al pasar el mouse. Cuanto mayor sea la prioridad, mayor será la opacidad. + El gráfico de respaldo interdimensional muestra todos los posibles respaldos (mostrados como bordes) entre subgráficos (combinaciones de valores de dimensión de contenido, mostrados como nodos). +Los recursos alternativos primarios están marcados en azul y siempre visibles, mientras que los recursos alternativos de menor prioridad se muestran al pasar el mouse. Cuanto mayor sea la prioridad, mayor será la opacidad. Haga clic en uno de los nodos para ver solo sus alternativas y variantes. Haga clic de nuevo para eliminar el filtro. diff --git a/Neos.Neos/Resources/Private/Translations/fi/Main.xlf b/Neos.Neos/Resources/Private/Translations/fi/Main.xlf index f39c28d0db4..bbbbf0a7a9c 100644 --- a/Neos.Neos/Resources/Private/Translations/fi/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/fi/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Julkaise automaattisesti + Julkaise automaattisesti + Auto-Publish to {0} - Julkaise automaattisesti kohteeseen {0} + Julkaise automaattisesti kohteeseen {0} + Review changes - Tarkista muutokset + Tarkista muutokset + Apply - Käytä + Käytä + Apply changes - Tallenna muutokset + Tallenna muutokset + Cancel - Peruuta + Peruuta + Back - Takaisin + Takaisin + Choose - Valitse + Valitse + Type to search - Kirjoita hakeaksesi + Kirjoita hakeaksesi + Content - Sisältö + Sisältö + Node - Solmu + Solmu + Content View - Sisältönäkymä + Sisältönäkymä + Create after - Luo jälkeen + Luo jälkeen + Create new - Luo uusi + Luo uusi + Close - Sulje + Sulje + Copy - Kopioi + Kopioi + Cut - Leikkaa + Leikkaa + Delete - Poista + Poista + Yes, delete the element - Kyllä, poista elementti + Kyllä, poista elementti + Delete the element - Poista elementti + Poista elementti + Discard - Hylkää + Hylkää + Discard changes - Hylkää muutokset + Hylkää muutokset + Edit title - Muokaa otsikkoa + Muokaa otsikkoa + Edit / Preview - Muokkaa / Esikatsele + Muokkaa / Esikatsele + Edit - Muokkaa + Muokkaa + Hide / Unhide - Piilota / Näytä + Piilota / Näytä + Hide - Piilota + Piilota + Unhide - Näytä + Näytä + into - osaksi + osaksi + before - ennen + ennen + after - jälkeen + jälkeen + Loading - Ladataan + Ladataan + New After - Uusi jälkeen + Uusi jälkeen + New Before - Uusi ennen + Uusi ennen + New Into - Uusi + Uusi + Navigate - Siirry + Siirry + OK - OK + OK + Page - Sivu + Sivu + Paste - Liitä + Liitä + Paste After - Liitä jälkeen + Liitä jälkeen + Paste Before - Liitä ennen + Liitä ennen + Paste Into - Liitä + Liitä + Password - Salasana + Salasana + Preview - Esikatsele + Esikatsele + Publish - Julkaise + Julkaise + Publish to {0} - Julkaise kohteeseen {0} + Julkaise kohteeseen {0} + Publish all changes for current page - Julkaise nykyisen sivun kaikki muutokset + Julkaise nykyisen sivun kaikki muutokset + Can't publish because the target workspace is read-only - Julkaisu ei onnistut koska kohdetyötila on vain luku-tilassa + Julkaisu ei onnistut koska kohdetyötila on vain luku-tilassa + Select target workspace - Valitse kohdetyötila + Valitse kohdetyötila + Publishing - Julkaisu + Julkaisu + Published - Julkaistu + Julkaistu + Toggle publish menu - Julkaisuvalikko + Julkaisuvalikko + Target workspace - Kohdetyötila + Kohdetyötila + Current workspace - Nykyinen työtila + Nykyinen työtila + Remove - Poista + Poista + Refresh - Päivitä + Päivitä + Save - Tallenna + Tallenna + Saving - Tallentaa... + Tallentaa... + Saved - Tallennettu + Tallennettu + Search - Etsi + Etsi + Toggle inspector - Näytä/piilota tarkastelu + Näytä/piilota tarkastelu + Username - Käyttäjätunnus + Käyttäjätunnus + You - Sinä + Sinä + [no title] - [ei otsikkoa] + [ei otsikkoa] + Label - Nimike + Nimike + Content Type - Sisältötyyppi + Sisältötyyppi + Path - Polku + Polku + Relative Path - Suhteellinen polku + Suhteellinen polku + Version - Versio + Versio + This operation cannot be undone. - Tätä toimintoa ei voi kumota. + Tätä toimintoa ei voi kumota. + Asset - Nimike + Nimike + Created - Luotu + Luotu + Last modification - Muokattu viimeksi + Muokattu viimeksi + Last publication - Julkaistu + Julkaistu + Identifier - Tunniste + Tunniste + Name - Nimi + Nimi + Workspace - Työtila + Työtila + Structure - Rakenne + Rakenne + Toggle context structure - Vaihda kontekstirakennetta + Vaihda kontekstirakennetta + Filter - Suodata + Suodata + Toggle menu - Avaa valikko + Avaa valikko + Load error! - Latausvirhe! + Latausvirhe! + You have to select a node - Valitse solmu + Valitse solmu + The Root node cannot be deleted. - Pääsolmua ei voi poistaa. + Pääsolmua ei voi poistaa. + You cannot copy this node - Tätä solmua ei voi kopioida + Tätä solmua ei voi kopioida + You cannot cut this node - Tätä solmua ei voi leikata + Tätä solmua ei voi leikata + Content Dimensions - Sisältöulottuvuudet + Sisältöulottuvuudet + Site - Sivusto + Sivusto + Document - Dokumentti + Dokumentti + Reference - Viite + Viite + Host - Verkko-osoite + Verkko-osoite + Scheme - Protokolla + Protokolla + Port - Portti + Portti + Primary - Ensisijainen + Ensisijainen + Package - Package + Package + Deactivated - Poistettu käytöstä + Poistettu käytöstä + Unavailable - Unavailable + Unavailable + Inactive - Inactive + Inactive + Click to edit - Klikkaa muokataksesi + Klikkaa muokataksesi + Click to deactivate - Click to deactivate + Click to deactivate + Click to activate - Click to activate + Click to activate + Click to delete - Klikkaa poistaaksesi + Klikkaa poistaaksesi + Click to create new - Click to create new + Click to create new + Status - Status + Status + Active - Active + Active + Domains - Domains + Domains + Domain - Domain + Domain + Yes, delete it! - Yes, delete it! + Yes, delete it! + Package Key - Paketin avain + Paketin avain + Description - Kuvaus + Kuvaus + Toggle content tree - Toggle content tree + Toggle content tree + Show publish options - Show publish options + Show publish options + Activate Fullscreen edit mode - Activate Fullscreen edit mode + Activate Fullscreen edit mode + Deactivate Fullscreen edit mode - Deactivate Fullscreen edit mode + Deactivate Fullscreen edit mode + Show preview - Show preview + Show preview + General - Yleiset + Yleiset + Structure - Rakenne + Rakenne + Plugins - Liitännäiset + Liitännäiset + Click {0} to continue to the page. - Valitse {0} jatkaaksesi sivulle. + Valitse {0} jatkaaksesi sivulle. + Click {0} to see the file. - Valitse {0} nähdäksesi tiedosto. + Valitse {0} nähdäksesi tiedosto. + Click {0} to open the link. - Valitse {0} avataksesi linkki. + Valitse {0} avataksesi linkki. + (no target has been selected) - (ei valittua kohdetta) + (ei valittua kohdetta) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Tämä on linkki ensimmäiselle alasivulle.<br />Valitse {0} jatkaaksesi sivulle. + Tämä on linkki ensimmäiselle alasivulle.<br />Valitse {0} jatkaaksesi sivulle. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Tämä on linkki ylemmän tason sivulle.<br />Valitse {0} jatkaaksesi sivulle. + Tämä on linkki ylemmän tason sivulle.<br />Valitse {0} jatkaaksesi sivulle. + Full Screen - Koko näyttö + Koko näyttö + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Avaa sivu työtilassa + Avaa sivu työtilassa + Open page in target workspace - Avaa sivu kohdetyötilassa + Avaa sivu kohdetyötilassa + Discard all - Hylkää kaikki + Hylkää kaikki + Discard all changes - Hylkää kaikki muutokset + Hylkää kaikki muutokset + Are you sure that you want to discard all changes in this workspace? - Oletko varma että haluat hylätä kaikki työtilan muutokset? + Oletko varma että haluat hylätä kaikki työtilan muutokset? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? + Publish all - Julkaise kaikki + Julkaise kaikki + Publish all changes - Julkaise kaikki muutokset + Julkaise kaikki muutokset + Are you sure that you want to publish all changes? - Oletko varma että haluat julkaista kaikki muutokset? + Oletko varma että haluat julkaista kaikki muutokset? + Pending changes - Odottavat muutokset + Odottavat muutokset + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Henkilökohtainen työtilasi sisältää julkaisemattomia muutoksia. Vaihtaaksesi toiseen työtilaan sinun täytyy joko julkaista tai hylätä muutokset. + Henkilökohtainen työtilasi sisältää julkaisemattomia muutoksia. Vaihtaaksesi toiseen työtilaan sinun täytyy joko julkaista tai hylätä muutokset. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Julkaise tai hylkää tekemäsi muutokset ja valitse sitten uusi työtila uudelleen. + Julkaise tai hylkää tekemäsi muutokset ja valitse sitten uusi työtila uudelleen. + Editing Modes - Muokkaustilat + Muokkaustilat + Preview Central - Esikatselukeskus + Esikatselukeskus + You still have changes. What do you want to do with them? - Olet tehnyt muutoksia. Mitä haluat tehdä niille? + Olet tehnyt muutoksia. Mitä haluat tehdä niille? + Selected element - Valittu elementti + Valittu elementti + There are fields that are not correctly filled in. - Kaikkia kenttiä ei ole täytetty oikein. + Kaikkia kenttiä ei ole täytetty oikein. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Korostettuja kenttiä ei ole täytetty oikein. Ole hyvä ja täytä ne oikein. + Korostettuja kenttiä ei ole täytetty oikein. Ole hyvä ja täytä ne oikein. + Continue editing - Jatka muokkausta + Jatka muokkausta + Throw away - Heitä pois + Heitä pois + Apply - Käytä + Käytä + Select a Plugin - Valitse laajennus + Valitse laajennus + No plugin configured - Ei määritettyä laajennusta + Ei määritettyä laajennusta + view is displayed on page - näkymä näytetään sivulla + näkymä näytetään sivulla + view is displayed on current page - näkymä näytetään nykyisellä sivulla + näkymä näytetään nykyisellä sivulla + No date set - Ei asetettua päivämäärää + Ei asetettua päivämäärää + Edit code - Muokkaa koodia + Muokkaa koodia + Paste a link, or type to search - Liitä linkki tai kirjoita hakeaksesi + Liitä linkki tai kirjoita hakeaksesi + Unable to load sub node types of: - Ei voitu ladata alasolmuja joiden tyyppi on: + Ei voitu ladata alasolmuja joiden tyyppi on: + Change type - Vaihda tyyppiä + Vaihda tyyppiä + Additional info - Lisätiedot + Lisätiedot + Visibility - Näkyvyys + Näkyvyys + Document options - Dokumentin valinnat + Dokumentin valinnat + The length of this text must be between {minimum} and {maximum} characters. - Tekstin pituuden on oltava {{minimum}}-{{maximum}} merkkiä. + Tekstin pituuden on oltava {{minimum}}-{{maximum}} merkkiä. + This field must contain at least {minimum} characters. - Kentän vähimmäispituus on {{minimum}} merkkiä. + Kentän vähimmäispituus on {{minimum}} merkkiä. + This text may not exceed {maximum} characters. - Tekstin enimmäispituus on {{maximum}} merkkiä. + Tekstin enimmäispituus on {{maximum}} merkkiä. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Ainoastaan kirjaimet ja numerot ovat sallittuja + Ainoastaan kirjaimet ja numerot ovat sallittuja + The given subject was not countable. - Kohde ei ole laskettavissa. + Kohde ei ole laskettavissa. + The count must be between {minimum} and {maximum}. - Määrän on oltava väliltä {{minimum}}-{{maximum}}. + Määrän on oltava väliltä {{minimum}}-{{maximum}}. + The given value was not a valid date. - Arvo ei ole kelvollinen päivämäärä. + Arvo ei ole kelvollinen päivämäärä. + The given date must be between {formatEarliestDate} and {formatLatestDate} - Päivämäärän on oltava väliltä {{formatEarliestDate}}-{{formatLatestDate}} + Päivämäärän on oltava väliltä {{formatEarliestDate}}-{{formatLatestDate}} + The given date must be after {formatEarliestDate} - Päivämäärän on oltava {{formatEarliestDate}} jälkeen + Päivämäärän on oltava {{formatEarliestDate}} jälkeen + The given date must be before {formatLatestDate} - Päivämäärän on oltava ennen {{formatLatestDate}} + Päivämäärän on oltava ennen {{formatLatestDate}} + Please specify a valid email address. - Anna kelvollinen sähköpostiosoite. + Anna kelvollinen sähköpostiosoite. + A valid float number is expected. - Anna kelvollinen liukuluku. + Anna kelvollinen liukuluku. + A valid integer number is expected. - Anna kelvollinen kokonaisluku. + Anna kelvollinen kokonaisluku. + Only letters, numbers, spaces and certain punctuation marks are expected. - Ainoastaan kirjaimet, numerot, välilyönnit ja tietyt välimerkit ovat sallittuja. + Ainoastaan kirjaimet, numerot, välilyönnit ja tietyt välimerkit ovat sallittuja. + This property is required. - Pakollinen ominaisuus. + Pakollinen ominaisuus. + A valid number is expected. - Kelvollinen numero vaaditaan. + Kelvollinen numero vaaditaan. + Please enter a valid number between {minimum} and {maximum} - Anna kelvollinen numero väliltä {{minimum}}-{{maximum}} + Anna kelvollinen numero väliltä {{minimum}}-{{maximum}} + The given subject did not match the pattern ({pattern}) - Syöte ei vastaa mallia ({pattern}) + Syöte ei vastaa mallia ({pattern}) + A valid string is expected. - Kelvollinen merkkijono vaaditaan. + Kelvollinen merkkijono vaaditaan. + Valid text without any XML tags is expected. - Kelvollinen teksti ilman XML-tageja vaaditaan. + Kelvollinen teksti ilman XML-tageja vaaditaan. + The given subject is not a valid UUID. - Syöte ei ole kelvollinen UUID. + Syöte ei ole kelvollinen UUID. + Toggle content dimensions selector - Sisältöulottuvuusvalitsin + Sisältöulottuvuusvalitsin + Start with an empty or pre-filled document? - Käytetäänkö esitäytettyä dokumenttia vai luodaanko tyhjä? + Käytetäänkö esitäytettyä dokumenttia vai luodaanko tyhjä? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Tätä {nodeTypeLabel} ei ole vielä luotu {currentDimensionChoiceText} alle. + Tätä {nodeTypeLabel} ei ole vielä luotu {currentDimensionChoiceText} alle. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Voit luoda sen nyt, käyttäen joko tyhjää {nodeTypeLabel} tai kopioimalla kaiken sisällön näkyvillä olevasta {nodeTypeLabel} {currentDocumentDimensionChoiceText}. + Voit luoda sen nyt, käyttäen joko tyhjää {nodeTypeLabel} tai kopioimalla kaiken sisällön näkyvillä olevasta {nodeTypeLabel} {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Lisäksi luodaan {numberOfNodesMissingInRootline} tämän valintayhdistelmän tarvitsemaa ylemmän tason dokumenttia. + Lisäksi luodaan {numberOfNodesMissingInRootline} tämän valintayhdistelmän tarvitsemaa ylemmän tason dokumenttia. + Create empty - Luo tyhjä + Luo tyhjä + Create and copy - Luo ja kopioi + Luo ja kopioi + Content - Sisältö + Sisältö + Toggle menu group - Valikkoryhmä + Valikkoryhmä + Toggle sticky menu mode - Kiinnitetty valikko + Kiinnitetty valikko + Do you really want to delete - Haluatko varmasti poistaa + Haluatko varmasti poistaa + This will delete the element - Tämä poistaa elementin + Tämä poistaa elementin + and it's children - ja sen alasivut + ja sen alasivut + This action can be undone in the workspace management. - Tämä toiminto voidaan peruttaa työtilahallinnassa. + Tämä toiminto voidaan peruttaa työtilahallinnassa. + Height - Korkeus + Korkeus + Do you really want to delete - Haluatko varmasti poistaa + Haluatko varmasti poistaa + this element - tämä elementti + tämä elementti + This will delete the element. - Tämä poistaa elementin. + Tämä poistaa elementin. + This action can be undone in the workspace management. - Tämä toiminto voidaan peruttaa työtilahallinnassa. + Tämä toiminto voidaan peruttaa työtilahallinnassa. + Media - Media + Media + Crop - Rajaa + Rajaa + Width - Leveys + Leveys + Missing required property: - Vaadittu ominaisuus puuttuu: + Vaadittu ominaisuus puuttuu: + Workspace - Työtila + Työtila + Workspaces - Työtilat + Työtilat + An error occurred during saving - Virhe tallennuksessa + Virhe tallennuksessa + Reload the page to attempt to fix the problem. - Lataa sivu uudelleen yrittääksesi ongelman korjausta. + Lataa sivu uudelleen yrittääksesi ongelman korjausta. + Reload the backend - Lataa hallinta uudelleen + Lataa hallinta uudelleen + Reload - Lataa uudelleen + Lataa uudelleen + In-Place - Upotettu + Upotettu + Raw Content - Pelkkä sisältö + Pelkkä sisältö + Raw Content Mode - Raakasisältötila + Raakasisältötila + Desktop - Tietokone + Tietokone + Login to - TYPO3 Neos Sisäänkirjautuminen + TYPO3 Neos Sisäänkirjautuminen + Authenticating - Varmennetaan + Varmennetaan + Logout - Kirjaudu ulos + Kirjaudu ulos + The entered username or password was wrong - Syötetty käyttäjätunnus tai salasana oli väärä + Syötetty käyttäjätunnus tai salasana oli väärä + Your login has expired. Please log in again. - Kirjautuminen on vanhentunut. Kirjaudu sisään uudelleen. + Kirjautuminen on vanhentunut. Kirjaudu sisään uudelleen. + Welcome to Neos - Welcome to Neos + Welcome to Neos + Go to setup - Mene asennukseen + Mene asennukseen + Technical Information - Technical Information + Technical Information + Missing Homepage - Puuttuva Kotisivu + Puuttuva Kotisivu + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Joko yhtään sivustoa ei ole määritetty, sivustolla ei ole kotisivua tai aktiivista sivustoa ei voitu selvittää. + Joko yhtään sivustoa ei ole määritetty, sivustolla ei ole kotisivua tai aktiivista sivustoa ei voitu selvittää. + You might want to set the site's domain or import a new site in the setup. - Aseta sivuston verkkotunnus tai tuo uusi sivusto. + Aseta sivuston verkkotunnus tai tuo uusi sivusto. + Database Error - Tietokantavirhe + Tietokantavirhe + There is no database connection yet or the Neos database schema has not been created. - There is no database connection yet or the Neos database schema has not been created. + There is no database connection yet or the Neos database schema has not been created. + Run the setup to configure your database. - Run the setup to configure your database. + Run the setup to configure your database. + Page Not Found - Sivua ei löydy + Sivua ei löydy + Sorry, the page you requested was not found. - Valitettavasti hakemaasi sivua ei löydy. + Valitettavasti hakemaasi sivua ei löydy. + Invalid NodeType - Virheellinen solmutyyppi + Virheellinen solmutyyppi + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - Tähän tulostettavan solmutyypin määrittely ei ole saatavailla. Olet ehkä nimennyt solmutyypin uudelleen tai kirjoittanut sen nimen väärin. + Tähän tulostettavan solmutyypin määrittely ei ole saatavailla. Olet ehkä nimennyt solmutyypin uudelleen tai kirjoittanut sen nimen väärin. + Unexpected error while creating node - Odottamaton virhe luotaessa solmua + Odottamaton virhe luotaessa solmua + Unexpected error while deleting node - Odottamaton virhe poistettaessa solmua + Odottamaton virhe poistettaessa solmua + Unexpected error while updating node - Odottamaton virhe päivitettäessä solmua + Odottamaton virhe päivitettäessä solmua + Unexpected error while moving node - Odottamaton virhe siirrettäessä solmua + Odottamaton virhe siirrettäessä solmua + Node Tree loading error. - Solmupuun latausvirhe. + Solmupuun latausvirhe. + - - The entered username or password was wrong - Syötetty käyttäjätunnus tai salasana oli väärä "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" sivulla "{pageLabel}" + "{nodeTypeName}" sivulla "{pageLabel}" + Nodes - Solmut + Solmut + Show - Näytä + Näytä + This node cannot be accessed through a public URL - Tähän solmuun ei ole pääsyä julkisella URL-osoitteella + Tähän solmuun ei ole pääsyä julkisella URL-osoitteella + Node Properties - Solmun ominaisuudet + Solmun ominaisuudet + Copy {source} to {target} - Copy {source} to {target} + Copy {source} to {target} + Move {source} to {target} - Move {source} to {target} + Move {source} to {target} + Please select the position at which you want {source} inserted relative to {target}. - Please select the position at which you want {source} inserted relative to {target}. + Please select the position at which you want {source} inserted relative to {target}. + Insert - Insert + Insert + Insert mode - Insert mode + Insert mode + Choose an Aspect Ratio - Choose an Aspect Ratio + Choose an Aspect Ratio + Bold - Bold + Bold + Italic - Italic + Italic + Underline - Underline + Underline + Subscript - Subscript + Subscript + Superscript - Superscript + Superscript + Strikethrough - Strikethrough + Strikethrough + Link - Linkki + Linkki + Ordered list - Ordered list + Ordered list + Unordered list - Unordered list + Unordered list + Align left - Align left + Align left + Align right - Align right + Align right + Align center - Align center + Align center + Align justify - Align justify + Align justify + Table - Table + Table + Remove format - Remove format + Remove format + Outdent - Outdent + Outdent + Indent - Indent + Indent + Create new - Luo uusi + Luo uusi + No matches found - No matches found + No matches found + Please enter ###CHARACTERS### more character - Please enter ###CHARACTERS### more character + Please enter ###CHARACTERS### more character + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - Syötetty käyttäjätunnus tai salasana oli väärä + Syötetty käyttäjätunnus tai salasana oli väärä + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/fi/Modules.xlf b/Neos.Neos/Resources/Private/Translations/fi/Modules.xlf index d4b09996635..f18714c2aec 100644 --- a/Neos.Neos/Resources/Private/Translations/fi/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/fi/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Kaikki työtilan "{0}" muutokset on hylätty. - - History - Historia - - - This module provides an overview of all relevant events affecting this Neos installation. - Tämä moduuli näyttää kaikki tämän Neos-asennuksen tapahtumat. - - - Here's what happened recently in Neos - Neosin viimeisimmät tapahtumat - - - There have not been recorded any events yet which could be displayed in this history. - Historiassa ei vielä ole tapahtumia. - - - {0} created the {1} "{2}". - {0} loi {1} {2}. - - - {0} removed the {1} "{2}". - {0} poisti {1} {2}. - - - {0} created the variant {1} of the {2} "{3}". - {0} loi muunnoksen {1} {2} {3}:sta. - - - {0} modified the {1} "{2}". - {0} muokkasi {1} "{2}". - - - {0} moved the {1} "{2}". - {0} siirsi {1} "{2}". - - - {0} copied the {1} "{2}". - {0} kopioi {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} nimesi {1} "{2}" uudelleen "{3}":ksi. - - - {0} modified content on the {1} "{2}". - {0} muokkasi sisältöä {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} loi uuden käyttäjän "{1}" {2}:lle. - - - {0} deleted the account "{1}" of {2}. - {0} poisti tilin "{1}" {2}:sta. - - - Load More - Lataa lisää - - - This node has been removed in the meantime - Solmu on poistettu - Administration diff --git a/Neos.Neos/Resources/Private/Translations/fr/Main.xlf b/Neos.Neos/Resources/Private/Translations/fr/Main.xlf index ae82ab71913..c40e136be0b 100644 --- a/Neos.Neos/Resources/Private/Translations/fr/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/fr/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Publication automatique + Publication automatique + Auto-Publish to {0} - Publier auto. vers {0} + Publier auto. vers {0} + Review changes - Réviser les modifications + Réviser les modifications + Apply - Appliquer + Appliquer + Apply changes - Appliquer les modifications + Appliquer les modifications + Cancel - Annuler + Annuler + Back - Retour + Retour + Choose - Selectionner + Selectionner + Type to search - Taper pour rechercher + Taper pour rechercher + Content - Contenu + Contenu + Node - Noeud + Noeud + Content View - Vue "Contenu" + Vue "Contenu" + Create after - Créer après + Créer après + Create new - Créer un nouveau + Créer un nouveau + Close - Fermer + Fermer + Copy - Copier + Copier + Cut - Couper + Couper + Delete - Effacer + Effacer + Yes, delete the element - Oui, supprimer l'élément + Oui, supprimer l'élément + Delete the element - Supprimer l'élément + Supprimer l'élément + Discard - Ignorer + Ignorer + Discard changes - Annuler les modifications + Annuler les modifications + Edit title - Éditer le titre + Éditer le titre + Edit / Preview - Edition / Aperçu + Edition / Aperçu + Edit - Edition + Edition + Hide / Unhide - Masquer / afficher + Masquer / afficher + Hide - Cacher + Cacher + Unhide - Afficher + Afficher + into - dans + dans + before - avant + avant + after - après + après + Loading - En cours + En cours + New After - Nouveau après + Nouveau après + New Before - Nouveau avant + Nouveau avant + New Into - Nouveau dans + Nouveau dans + Navigate - Navigation + Navigation + OK - OK + OK + Page - Page + Page + Paste - Coller + Coller + Paste After - Coller après + Coller après + Paste Before - Coller avant + Coller avant + Paste Into - Collez dans + Collez dans + Password - Mot de passe + Mot de passe + Preview - Prévisualisation + Prévisualisation + Publish - Publier + Publier + Publish to {0} - Publier vers {0} + Publier vers {0} + Publish all changes for current page - Publier tous les changements de la page en cours + Publier tous les changements de la page en cours + Can't publish because the target workspace is read-only - Impossible de publier, l'espace de travail cible est en lecture seule + Impossible de publier, l'espace de travail cible est en lecture seule + Select target workspace - Sélectionnez l'espace de travail cible + Sélectionnez l'espace de travail cible + Publishing - Publication + Publication + Published - Publié + Publié + Toggle publish menu - Basculer le menu de plublication + Basculer le menu de plublication + Target workspace - Espace de travail cible + Espace de travail cible + Current workspace - Espace de travail courant + Espace de travail courant + Remove - Supprimer + Supprimer + Refresh - Rafraîchir + Rafraîchir + Save - Enregistrer + Enregistrer + Saving - Enregistrement... + Enregistrement... + Saved - Sauvegardé + Sauvegardé + Search - Chercher + Chercher + Toggle inspector - Basculer l'inspecteur + Basculer l'inspecteur + Username - Nom d'utilisateur + Nom d'utilisateur + You - Vous + Vous + [no title] - [sans titre] + [sans titre] + Label - Libellé + Libellé + Content Type - Type de noeud + Type de noeud + Path - Chemin + Chemin + Relative Path - Chemin relatif + Chemin relatif + Version - Version + Version + This operation cannot be undone. - Cette opération ne peut pas être annulée. + Cette opération ne peut pas être annulée. + Asset - Ressource + Ressource + Created - Créé + Créé + Last modification - Dernière modification + Dernière modification + Last publication - Dernière publication + Dernière publication + Identifier - Identifiant + Identifiant + Name - Nom + Nom + Workspace - Espace de travail + Espace de travail + Structure - Structure + Structure + Toggle context structure - Basculer la structure du contexte + Basculer la structure du contexte + Filter - Filtrer + Filtrer + Toggle menu - Basculer le menu + Basculer le menu + Load error! - Erreur de chargement ! + Erreur de chargement ! + You have to select a node - Vous devez sélectionner un noeud + Vous devez sélectionner un noeud + The Root node cannot be deleted. - Impossible de supprimer le noeud racine. + Impossible de supprimer le noeud racine. + You cannot copy this node - Vous ne pouvez pas copier ce noeud + Vous ne pouvez pas copier ce noeud + You cannot cut this node - Vous ne pouvez pas couper ce noeud + Vous ne pouvez pas couper ce noeud + Content Dimensions - Dimensions de contenu + Dimensions de contenu + Site - Site + Site + Document - Document + Document + Reference - Référence + Référence + Host - Nom de l'hôte + Nom de l'hôte + Scheme - Schéma + Schéma + Port - Port + Port + Primary - Principal + Principal + Package - Paquet + Paquet + Deactivated - Désactivée + Désactivée + Unavailable - Non disponible + Non disponible + Inactive - Inactif + Inactif + Click to edit - Cliquez pour éditer + Cliquez pour éditer + Click to deactivate - Cliquez pour désactiver + Cliquez pour désactiver + Click to activate - Cliquez pour activer + Cliquez pour activer + Click to delete - Cliquer pour supprimer + Cliquer pour supprimer + Click to create new - Cliquer pour créer un nouveau + Cliquer pour créer un nouveau + Status - Statut + Statut + Active - Actif + Actif + Domains - Domaines + Domaines + Domain - Domaine + Domaine + Yes, delete it! - Oui, le supprimer! + Oui, le supprimer! + Package Key - Clé de package + Clé de package + Description - Description + Description + Toggle content tree - Afficher/Masquer la table des matières + Afficher/Masquer la table des matières + Show publish options - Afficher les options de publication + Afficher les options de publication + Activate Fullscreen edit mode - Activer le mode édition plein écran + Activer le mode édition plein écran + Deactivate Fullscreen edit mode - Désactiver le mode édition plein écran + Désactiver le mode édition plein écran + Show preview - Afficher l'aperçu + Afficher l'aperçu + General - Général + Général + Structure - Structure + Structure + Plugins - Modules + Modules + Click {0} to continue to the page. - Cliquez ici pour continuer vers la page {0}. + Cliquez ici pour continuer vers la page {0}. + Click {0} to see the file. - Cliquez ici pour voir le fichier {0}. + Cliquez ici pour voir le fichier {0}. + Click {0} to open the link. - Cliquez ici pour ouvrir le lien {0}. + Cliquez ici pour ouvrir le lien {0}. + (no target has been selected) - (aucune cible n'a été sélectionné) + (aucune cible n'a été sélectionné) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Il s'agit d'un raccourci vers la première sous-page. <br /> Cliquez sur {0} pour continuer vers la sous-page. + Il s'agit d'un raccourci vers la première sous-page. <br /> Cliquez sur {0} pour continuer vers la sous-page. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Il s'agit d'un raccourci vers la page parente. <br /> Cliquez sur {0} pour continuer vers cette page. + Il s'agit d'un raccourci vers la page parente. <br /> Cliquez sur {0} pour continuer vers cette page. + Full Screen - Plein écran + Plein écran + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Ouvrir la page dans l'espace de travail Live + Ouvrir la page dans l'espace de travail Live + Open page in target workspace - Ouvrir la page dans l'espace de travail cible + Ouvrir la page dans l'espace de travail cible + Discard all - ReJeter tous + ReJeter tous + Discard all changes - Ignorer toutes les modifications + Ignorer toutes les modifications + Are you sure that you want to discard all changes in this workspace? - Êtes-vous sûr de vouloir ignorer toutes les modifications dans cet espace de travail ? + Êtes-vous sûr de vouloir ignorer toutes les modifications dans cet espace de travail ? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Êtes-vous sûr de vouloir ignorer {numberOfChanges} modification(s) dans cet espace de travail ? + Êtes-vous sûr de vouloir ignorer {numberOfChanges} modification(s) dans cet espace de travail ? + Publish all - Publier tous + Publier tous + Publish all changes - Publier toutes les modifications + Publier toutes les modifications + Are you sure that you want to publish all changes? - Êtes-vous sûr de vouloir publier toutes les modifications ? + Êtes-vous sûr de vouloir publier toutes les modifications ? + Pending changes - Modifications en attente + Modifications en attente + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Votre espace de travail personnel contient actuellement des modifications non publiées. Afin de passer à un espace de travail cible différent, vous devrez avant tout publier ou rejeter les changements en attente. + Votre espace de travail personnel contient actuellement des modifications non publiées. Afin de passer à un espace de travail cible différent, vous devrez avant tout publier ou rejeter les changements en attente. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Veuillez consulter vos modifications, publiez ou rejetez-les et puis choisissez un nouvel espace de travail cible à nouveau. + Veuillez consulter vos modifications, publiez ou rejetez-les et puis choisissez un nouvel espace de travail cible à nouveau. + Editing Modes - Modes d'édition + Modes d'édition + Preview Central - Preview Central + Preview Central + You still have changes. What do you want to do with them? - Vous avez encore des modifications. Que voulez-vous faire avec ? + Vous avez encore des modifications. Que voulez-vous faire avec ? + Selected element - Élément sélectionné + Élément sélectionné + There are fields that are not correctly filled in. - Il y a des champs qui ne sont pas correctement remplis. + Il y a des champs qui ne sont pas correctement remplis. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Les champs marqués avec une erreur ne sont pas encore correctement remplis. Veuillez les remplir correctement. + Les champs marqués avec une erreur ne sont pas encore correctement remplis. Veuillez les remplir correctement. + Continue editing - Continuer l'édition + Continuer l'édition + Throw away - Jeter + Jeter + Apply - Appliquer + Appliquer + Select a Plugin - Sélectionnez un Plugin + Sélectionnez un Plugin + No plugin configured - Aucun plugin configuré + Aucun plugin configuré + view is displayed on page - la vue est affichée sur la page + la vue est affichée sur la page + view is displayed on current page - la vue est affichée sur la page en cours + la vue est affichée sur la page en cours + No date set - Aucune date définie + Aucune date définie + Edit code - Modifier le code + Modifier le code + Paste a link, or type to search - Coller un lien, ou taper pour rechercher + Coller un lien, ou taper pour rechercher + Unable to load sub node types of: - Impossible de charger les types de noeuds enfant de: + Impossible de charger les types de noeuds enfant de: + Change type - Modifier le type + Modifier le type + Additional info - Informations complémentaires + Informations complémentaires + Visibility - Visibilité + Visibilité + Document options - Options du document + Options du document + The length of this text must be between {minimum} and {maximum} characters. - La longueur de ce texte doit être comprise entre {{minimum}} et {{maximum}} caractères. + La longueur de ce texte doit être comprise entre {{minimum}} et {{maximum}} caractères. + This field must contain at least {minimum} characters. - Ce champ doit contenir au moins {{minimum}} caractères. + Ce champ doit contenir au moins {{minimum}} caractères. + This text may not exceed {maximum} characters. - Ce texte ne doit pas dépasser {{maximum}} caractères. + Ce texte ne doit pas dépasser {{maximum}} caractères. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Seuls les caractères a à z et les nombres sont autorisés + Seuls les caractères a à z et les nombres sont autorisés + The given subject was not countable. - Le sujet donné n'est pas dénombrable. + Le sujet donné n'est pas dénombrable. + The count must be between {minimum} and {maximum}. - Le décompte doit être compris entre {{minimum}} et {{maximum}}. + Le décompte doit être compris entre {{minimum}} et {{maximum}}. + The given value was not a valid date. - La valeur donnée n'était pas une date valide. + La valeur donnée n'était pas une date valide. + The given date must be between {formatEarliestDate} and {formatLatestDate} - La date doit être comprise entre le {{formatEarliestDate}} et le {{formatLatestDate}} + La date doit être comprise entre le {{formatEarliestDate}} et le {{formatLatestDate}} + The given date must be after {formatEarliestDate} - La date donnée doit être après le {{formatEarliestDate}} + La date donnée doit être après le {{formatEarliestDate}} + The given date must be before {formatLatestDate} - La date donnée doit être avant le {{formatLatestDate}} + La date donnée doit être avant le {{formatLatestDate}} + Please specify a valid email address. - Veuillez entrer une adresse e-mail valide. + Veuillez entrer une adresse e-mail valide. + A valid float number is expected. - Un nombre à virgule flottante valide est attendu. + Un nombre à virgule flottante valide est attendu. + A valid integer number is expected. - Un nombre entier valide est attendu. + Un nombre entier valide est attendu. + Only letters, numbers, spaces and certain punctuation marks are expected. - Seuls les lettres, les nombres, les espaces et certaines ponctuations sont attentus. + Seuls les lettres, les nombres, les espaces et certaines ponctuations sont attentus. + This property is required. - Cette propriété est obligatoire. + Cette propriété est obligatoire. + A valid number is expected. - Un nombre valide est attendu. + Un nombre valide est attendu. + Please enter a valid number between {minimum} and {maximum} - Veuillez entrer un nombre valide entre {{minimum}} et {{maximum}} + Veuillez entrer un nombre valide entre {{minimum}} et {{maximum}} + The given subject did not match the pattern ({pattern}) - Le sujet donné ne correspond pas au modèle ({{pattern}}) + Le sujet donné ne correspond pas au modèle ({{pattern}}) + A valid string is expected. - Une chaîne valide est attendue. + Une chaîne valide est attendue. + Valid text without any XML tags is expected. - Le texte ne doit pas contenir de balises XML. + Le texte ne doit pas contenir de balises XML. + The given subject is not a valid UUID. - Le sujet donné n'est pas un UUID valide. + Le sujet donné n'est pas un UUID valide. + Toggle content dimensions selector - Basculer le sélecteur de dimensions de contenu + Basculer le sélecteur de dimensions de contenu + Start with an empty or pre-filled document? - Commencer avec un document vide ou rempli au préalable ? + Commencer avec un document vide ou rempli au préalable ? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Ce {nodeTypeLabel} n'existe pas encore en {currentDimensionChoiceText}. + Ce {nodeTypeLabel} n'existe pas encore en {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Vous pouvez le créer maintenant, en démarrant soir d'un {nodeTypeLabel} vide ou copier tout le contenu du {nodeTypeLabel} actuellement visible dans {currentDocumentDimensionChoiceText}. + Vous pouvez le créer maintenant, en démarrant soir d'un {nodeTypeLabel} vide ou copier tout le contenu du {nodeTypeLabel} actuellement visible dans {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - En outre, on compte {numberOfNodesMissingInRootline} anciens documents qui n’existent pas non plus selon la variante choisie, et qui sera ainsi créé. + En outre, on compte {numberOfNodesMissingInRootline} anciens documents qui n’existent pas non plus selon la variante choisie, et qui sera ainsi créé. + Create empty - Créer un vide + Créer un vide + Create and copy - Créer et copier + Créer et copier + Content - Contenu + Contenu + Toggle menu group - Activer/Désactiver le groupe de menu + Activer/Désactiver le groupe de menu + Toggle sticky menu mode - Basculer le menu "sticky" + Basculer le menu "sticky" + Do you really want to delete - Confirmez-vous la suppression + Confirmez-vous la suppression + This will delete the element - Cet action supprimera l'élément + Cet action supprimera l'élément + and it's children - et ses sous-éléments + et ses sous-éléments + This action can be undone in the workspace management. - Cette opération peut être annulée dans le module de l'espace de travail. + Cette opération peut être annulée dans le module de l'espace de travail. + Height - Hauteur + Hauteur + Do you really want to delete - Confirmez-vous la suppression + Confirmez-vous la suppression + this element - cet élément + cet élément + This will delete the element. - Ceci supprimera l'élément. + Ceci supprimera l'élément. + This action can be undone in the workspace management. - Cette opération peut être annulée dans le module de l'espace de travail. + Cette opération peut être annulée dans le module de l'espace de travail. + Media - Média + Média + Crop - Recadrer + Recadrer + Width - Largeur  + Largeur  + Missing required property: - Propriété requise manquante: + Propriété requise manquante: + Workspace - Espace de travail + Espace de travail + Workspaces - Espaces de travail + Espaces de travail + An error occurred during saving - Une erreur s'est produite au cours de la sauvegarde + Une erreur s'est produite au cours de la sauvegarde + Reload the page to attempt to fix the problem. - Recharger la page pour tenter de résoudre le problème. + Recharger la page pour tenter de résoudre le problème. + Reload the backend - Recharger l'interface d'administration + Recharger l'interface d'administration + Reload - Recharger + Recharger + In-Place - Édition "In-Place" + Édition "In-Place" + Raw Content - Contenu brut + Contenu brut + Raw Content Mode - Mode de contenu brut + Mode de contenu brut + Desktop - Ordinateur de bureau + Ordinateur de bureau + Login to - Ouverture de session + Ouverture de session + Authenticating - Authentification en cours + Authentification en cours + Logout - Déconnexion + Déconnexion + The entered username or password was wrong - Le nom d'utilisateur ou mot de passe entré est inconnu + Le nom d'utilisateur ou mot de passe entré est inconnu + Your login has expired. Please log in again. - Votre connexion a expiré. S'il vous plaît vous connecter à nouveau. + Votre connexion a expiré. S'il vous plaît vous connecter à nouveau. + Welcome to Neos - Bienvenue sur Neos + Bienvenue sur Neos + Go to setup - Allez dans l'assistant de configuration + Allez dans l'assistant de configuration + Technical Information - Informations techniques + Informations techniques + Missing Homepage - Page d'accueil manquante + Page d'accueil manquante + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Aucun site n'a été configuré, le site ne contient aucune page d'accueil ou le site actif n'a pas pu être déterminé. + Aucun site n'a été configuré, le site ne contient aucune page d'accueil ou le site actif n'a pas pu être déterminé. + You might want to set the site's domain or import a new site in the setup. - Vous pouvez définir le nom de domaine du site ou importer un nouveau site depuis l'assistant de configuration. + Vous pouvez définir le nom de domaine du site ou importer un nouveau site depuis l'assistant de configuration. + Database Error - Erreur de la base de données + Erreur de la base de données + There is no database connection yet or the Neos database schema has not been created. - Il n'y a pas encore de connexion à la base de données ou le schéma de base de données Neos n'a pas encore été créé. + Il n'y a pas encore de connexion à la base de données ou le schéma de base de données Neos n'a pas encore été créé. + Run the setup to configure your database. - Lancez l'installation pour configurer votre base de données. + Lancez l'installation pour configurer votre base de données. + Page Not Found - Page introuvable + Page introuvable + Sorry, the page you requested was not found. - Désolé, la page demandée n'a pas été trouvée. + Désolé, la page demandée n'a pas été trouvée. + Invalid NodeType - Type de noeud invalide + Type de noeud invalide + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - La configuration du type de noeud qui doit s'afficher ici n'est pas disponible. Le type de noeud a probablement été renommé. Validez que vous avez bien exécuté toutes les migrations. Ou peut-être est-ce simplement une erreur de frappe. + La configuration du type de noeud qui doit s'afficher ici n'est pas disponible. Le type de noeud a probablement été renommé. Validez que vous avez bien exécuté toutes les migrations. Ou peut-être est-ce simplement une erreur de frappe. + Unexpected error while creating node - Erreur inattendue lors de la création du nœud + Erreur inattendue lors de la création du nœud + Unexpected error while deleting node - Erreur inattendue lors de la suppression du nœud + Erreur inattendue lors de la suppression du nœud + Unexpected error while updating node - Erreur inattendue lors de la mise à jour du nœud + Erreur inattendue lors de la mise à jour du nœud + Unexpected error while moving node - Erreur inattendue lors du déplacement du nœud + Erreur inattendue lors du déplacement du nœud + Node Tree loading error. - Erreur de chargement de l'arborescence. + Erreur de chargement de l'arborescence. + - - The entered username or password was wrong - Le nom d'utilisateur ou mot de passe entré est inconnu "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" sur la page "{pageLabel}" + "{nodeTypeName}" sur la page "{pageLabel}" + Nodes - Noeuds + Noeuds + Show - Afficher + Afficher + This node cannot be accessed through a public URL - Ce nœud n'est pas accessible via une URL publique + Ce nœud n'est pas accessible via une URL publique + Node Properties - Propriétés du noeud + Propriétés du noeud + Copy {source} to {target} - Copier {source} vers {target} + Copier {source} vers {target} + Move {source} to {target} - Déplacer {source} vers {target} + Déplacer {source} vers {target} + Please select the position at which you want {source} inserted relative to {target}. - Veuillez sélectionner la position à laquelle vous souhaitez {source} être inséré par rapport à {target}. + Veuillez sélectionner la position à laquelle vous souhaitez {source} être inséré par rapport à {target}. + Insert - Insérer + Insérer + Insert mode - Mode &insertion + Mode &insertion + Choose an Aspect Ratio - Choisissez un format d'aspect + Choisissez un format d'aspect + Bold - Gras + Gras + Italic - Italique + Italique + Underline - Souligné + Souligné + Subscript - Indice + Indice + Superscript - Exposant + Exposant + Strikethrough - Barré + Barré + Link - Lien + Lien + Ordered list - Liste ordonnée + Liste ordonnée + Unordered list - Liste non-ordonnée + Liste non-ordonnée + Align left - Aligner à gauche + Aligner à gauche + Align right - Aligner à droite + Aligner à droite + Align center - Aligner au centre + Aligner au centre + Align justify - Aligner et justifier + Aligner et justifier + Table - Tableau + Tableau + Remove format - Supprimer le formatage + Supprimer le formatage + Outdent - Retrait négatif + Retrait négatif + Indent - Retrait + Retrait + Create new - Créer un nouveau + Créer un nouveau + No matches found - Aucune correspondance trouvée + Aucune correspondance trouvée + Please enter ###CHARACTERS### more character - S’il vous plaît entrez ###CHARACTERS### plus de caractère + S’il vous plaît entrez ###CHARACTERS### plus de caractère + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - Le nom d'utilisateur ou mot de passe entré est inconnu + Le nom d'utilisateur ou mot de passe entré est inconnu + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/fr/Modules.xlf b/Neos.Neos/Resources/Private/Translations/fr/Modules.xlf index c469c027789..48dd2eb9250 100644 --- a/Neos.Neos/Resources/Private/Translations/fr/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/fr/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Toutes les modifications d'espace de travail « {0} » ont été ignorées. - - History - Historique - - - This module provides an overview of all relevant events affecting this Neos installation. - Ce module donne un aperçu de tous les événements pertinents qui touchent votre site. - - - Here's what happened recently in Neos - Voici ce qui s'est passé récemment dans Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Aucun événement n'a été enregistré qui peut être affiché dans le module d'historique. - - - {0} created the {1} "{2}". - {0} a créé le {1} "{2}". - - - {0} removed the {1} "{2}". - {0} a supprimé le {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} a créé la variante {1} de {2} "{3}". - - - {0} modified the {1} "{2}". - {0} a modifié la {1} "{2}". - - - {0} moved the {1} "{2}". - {0} a déplacé {1} "{2}". - - - {0} copied the {1} "{2}". - {0} a copié le {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} a renommé le {1} "{2}" en "{3}". - - - {0} modified content on the {1} "{2}". - {0} a modifié le contenu de {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} a créé un nouvel utilisateur "{1}" pour {2}. - - - {0} deleted the account "{1}" of {2}. - {0} a supprimé un utilisateur "{1}" de {2}. - - - Load More - Plus de résultats - - - This node has been removed in the meantime - Ce nœud a été supprimé dans l'intervalle - Administration diff --git a/Neos.Neos/Resources/Private/Translations/hu/Main.xlf b/Neos.Neos/Resources/Private/Translations/hu/Main.xlf index c6937253513..1d217aa9898 100644 --- a/Neos.Neos/Resources/Private/Translations/hu/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/hu/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Automatikus közzététel + Automatikus közzététel + Auto-Publish to {0} - Automatikus közzététel ide {0} + Automatikus közzététel ide {0} + Review changes - Változások áttekintése + Változások áttekintése + Apply - Alkamaz + Alkamaz + Apply changes - Változtatások alkalmazása + Változtatások alkalmazása + Cancel - Mégsem + Mégsem + Back - Vissza + Vissza + Choose - Választás + Választás + Type to search - Keresendő szöveg + Keresendő szöveg + Content - Tartalom + Tartalom + Node - Csomópont + Csomópont + Content View - Tartalom megtekintése + Tartalom megtekintése + Create after - Létrehozás ezután + Létrehozás ezután + Create new - Új létrehozása + Új létrehozása + Close - Bezárás + Bezárás + Copy - Másolás + Másolás + Cut - Kivágás + Kivágás + Delete - Törlés + Törlés + Yes, delete the element - Igen, törlöm az elemet + Igen, törlöm az elemet + Delete the element - Elem törlése + Elem törlése + Discard - Elvet + Elvet + Discard changes - Változtatások elvetése + Változtatások elvetése + Edit title - Cím szerkesztése + Cím szerkesztése + Edit / Preview - Szerkesztés / előnézet + Szerkesztés / előnézet + Edit - Szerkesztés + Szerkesztés + Hide / Unhide - Elrejtés / felfedés + Elrejtés / felfedés + Hide - Elrejtés + Elrejtés + Unhide - Felfedés + Felfedés + into - ide + ide + before - előtt + előtt + after - után + után + Loading - Betöltés + Betöltés + New After - Új ezután + Új ezután + New Before - Új ezelőtt + Új ezelőtt + New Into - Új ide + Új ide + Navigate - Navigáció + Navigáció + OK - OK + OK + Page - Oldal + Oldal + Paste - Beillesztés + Beillesztés + Paste After - Beillesztés ezután + Beillesztés ezután + Paste Before - Beillesztés ezelőtt + Beillesztés ezelőtt + Paste Into - Beillesztés ide + Beillesztés ide + Password - Jelszó + Jelszó + Preview - Előnézet + Előnézet + Publish - Publikálás + Publikálás + Publish to {0} - Publikálás ide {0} + Publikálás ide {0} + Publish all changes for current page - Az aktuális oldal változásainak publikálása + Az aktuális oldal változásainak publikálása + Can't publish because the target workspace is read-only - Nem publikálható mert a munkaterület írásvédett + Nem publikálható mert a munkaterület írásvédett + Select target workspace - Munkaterület választása + Munkaterület választása + Publishing - Publikálás + Publikálás + Published - Publikált + Publikált + Toggle publish menu - Publikáció menu láthatósága + Publikáció menu láthatósága + Target workspace - Cél munkaterület + Cél munkaterület + Current workspace - Aktuális munkaterület + Aktuális munkaterület + Remove - Eltávolítás + Eltávolítás + Refresh - Frissités + Frissités + Save - Mentés + Mentés + Saving - Mentés + Mentés + Saved - Mentve + Mentve + Search - Keresés + Keresés + Toggle inspector - Ellenőrző láthatósága + Ellenőrző láthatósága + Username - Felhasználó + Felhasználó + You - Ön + Ön + [no title] - [névtelen] + [névtelen] + Label - Címke + Címke + Content Type - Tartalom típus + Tartalom típus + Path - Elérési út + Elérési út + Relative Path - Relatív elérési út + Relatív elérési út + Version - Verzió + Verzió + This operation cannot be undone. - Ez a művelet nem vonható vissza. + Ez a művelet nem vonható vissza. + Asset - Tartalom + Tartalom + Created - Létrehozva + Létrehozva + Last modification - Utolsó módosítás + Utolsó módosítás + Last publication - Utolsó közzététel + Utolsó közzététel + Identifier - Azonosító + Azonosító + Name - Név + Név + Workspace - Munkaterület + Munkaterület + Structure - Struktúra + Struktúra + Toggle context structure - Context struktúra láthatósága + Context struktúra láthatósága + Filter - Szűrő + Szűrő + Toggle menu - Menü láthatósága + Menü láthatósága + Load error! - Betöltési hiba! + Betöltési hiba! + You have to select a node - Ki kell választania egy csomópont + Ki kell választania egy csomópont + The Root node cannot be deleted. - A gyökércsomópontot nem lehet törölni. + A gyökércsomópontot nem lehet törölni. + You cannot copy this node - Ez a csomópontot nem lehet másolni + Ez a csomópontot nem lehet másolni + You cannot cut this node - Ezt a csomópontot nem vághatja ki + Ezt a csomópontot nem vághatja ki + Content Dimensions - Tartalom mérete + Tartalom mérete + Site - Oldal + Oldal + Document - Dokumentum + Dokumentum + Reference - Referencia + Referencia + Host - Kiszolgáló + Kiszolgáló + Scheme - Séma + Séma + Port - Port + Port + Primary - Elsődleges + Elsődleges + Package - Csomag + Csomag + Deactivated - Deaktiválva + Deaktiválva + Unavailable - Elérhetetlen + Elérhetetlen + Inactive - Inaktív + Inaktív + Click to edit - Szerkesztés + Szerkesztés + Click to deactivate - Deaktiválás + Deaktiválás + Click to activate - Aktiválás + Aktiválás + Click to delete - Kattintson ide a törléshez + Kattintson ide a törléshez + Click to create new - Új létrehozása + Új létrehozása + Status - Állapot + Állapot + Active - Aktív + Aktív + Domains - Domainek + Domainek + Domain - Domain + Domain + Yes, delete it! - Igen, töröl! + Igen, töröl! + Package Key - Csomagszám + Csomagszám + Description - Leírás + Leírás + Toggle content tree - Tartalmi fa megnyitása/bezárása + Tartalmi fa megnyitása/bezárása + Show publish options - Publikálási beállítások + Publikálási beállítások + Activate Fullscreen edit mode - Teljes képernyős szerkesztési mód aktiválása + Teljes képernyős szerkesztési mód aktiválása + Deactivate Fullscreen edit mode - Teljes képernyős szerkesztési mód kikapcsolása + Teljes képernyős szerkesztési mód kikapcsolása + Show preview - Előnézet + Előnézet + General - Általános  + Általános  + Structure - Struktúra + Struktúra + Plugins - Bővítmények + Bővítmények + Click {0} to continue to the page. - Kattintson {0} az oldalra lépéshez. + Kattintson {0} az oldalra lépéshez. + Click {0} to see the file. - Kattintson {0} hogy lássa a file-t. + Kattintson {0} hogy lássa a file-t. + Click {0} to open the link. - Kattintson {0} a link megnyitásához. + Kattintson {0} a link megnyitásához. + (no target has been selected) - (nincs cél kiválasztva) + (nincs cél kiválasztva) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Ez egy parancsikon az első gyermek oldalra. Kattintson ide az oldalra lépéshet {0}. + Ez egy parancsikon az első gyermek oldalra. Kattintson ide az oldalra lépéshet {0}. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Ez egy parancsikon a szülő oldalra. Kattintson ide az oldalra lépéshez {0}. + Ez egy parancsikon a szülő oldalra. Kattintson ide az oldalra lépéshez {0}. + Full Screen - Teljes képernyő + Teljes képernyő + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Élő nézet megnyitása + Élő nézet megnyitása + Open page in target workspace - Oldal megnyitása a cél munkaterületben + Oldal megnyitása a cél munkaterületben + Discard all - Összes elvetése + Összes elvetése + Discard all changes - Összes változtatás elvetése + Összes változtatás elvetése + Are you sure that you want to discard all changes in this workspace? - Biztos benne, hogy elveti az összes módosítást ezen a munkaterületen? + Biztos benne, hogy elveti az összes módosítást ezen a munkaterületen? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Biztos elvet {numberOfChanges} módosítást a munkafelületen? + Biztos elvet {numberOfChanges} módosítást a munkafelületen? + Publish all - Minden közzététele + Minden közzététele + Publish all changes - Minden változtatás közzététele + Minden változtatás közzététele + Are you sure that you want to publish all changes? - Biztos benne, hogy közzéteszi az összes változást? + Biztos benne, hogy közzéteszi az összes változást? + Pending changes - Függőben lévő módosítások + Függőben lévő módosítások + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - A jelenlegi munkaterület nem publikált módosításokat tartalmaz. Csak akkor tud munkaterületet váltani ha publikálja vagy elveti a módosításokat. + A jelenlegi munkaterület nem publikált módosításokat tartalmaz. Csak akkor tud munkaterületet váltani ha publikálja vagy elveti a módosításokat. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Kérjük ellenőrizze a módosításait, publikálja vagy vesse el őket és ezután válasszon ismét munkaterületet. + Kérjük ellenőrizze a módosításait, publikálja vagy vesse el őket és ezután válasszon ismét munkaterületet. + Editing Modes - Szerkesztési módok + Szerkesztési módok + Preview Central - Előnézet + Előnézet + You still have changes. What do you want to do with them? - Függőben vannak módosítások. Mit szeretne tenni velük? + Függőben vannak módosítások. Mit szeretne tenni velük? + Selected element - Kiválasztott elem + Kiválasztott elem + There are fields that are not correctly filled in. - Egyes mezők nincsenek megfelelően kitöltve. + Egyes mezők nincsenek megfelelően kitöltve. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Az hibajelzéssel ellátott mezők nincsenek megfelelően kitöltve. Kérjük ellenőrizze a mezőket. + Az hibajelzéssel ellátott mezők nincsenek megfelelően kitöltve. Kérjük ellenőrizze a mezőket. + Continue editing - Szerkesztés folytatása + Szerkesztés folytatása + Throw away - Elvetés + Elvetés + Apply - Alkamaz + Alkamaz + Select a Plugin - Bővitmény kiválasztása + Bővitmény kiválasztása + No plugin configured - Nincs beállítva bővitmény + Nincs beállítva bővitmény + view is displayed on page - bővitmény nézet az oldalon + bővitmény nézet az oldalon + view is displayed on current page - bővitmény nézet az aktuális oldalon + bővitmény nézet az aktuális oldalon + No date set - Nincs dátum beállítva + Nincs dátum beállítva + Edit code - Kód szerkesztése + Kód szerkesztése + Paste a link, or type to search - Link beillesztése vagy írjon a kereséshez + Link beillesztése vagy írjon a kereséshez + Unable to load sub node types of: - Nem sikerült betölteni a következő típusú al csomópontot: + Nem sikerült betölteni a következő típusú al csomópontot: + Change type - Típus megváltoztatása + Típus megváltoztatása + Additional info - További információ + További információ + Visibility - Láthatóság + Láthatóság + Document options - Dokumentum beállításai + Dokumentum beállításai + The length of this text must be between {minimum} and {maximum} characters. - A szöveg hossza {minimum} és {maximum} karakter között kell legyen. + A szöveg hossza {minimum} és {maximum} karakter között kell legyen. + This field must contain at least {minimum} characters. - Ez a mező legalább {minimum} karakter kell legyen. + Ez a mező legalább {minimum} karakter kell legyen. + This text may not exceed {maximum} characters. - Ez a szöveg maximum {maximum} karakter lehet. + Ez a szöveg maximum {maximum} karakter lehet. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Csak reguláris karakterek és számok megengedettek. + Csak reguláris karakterek és számok megengedettek. + The given subject was not countable. - A megadott objektum nem számolható meg. + A megadott objektum nem számolható meg. + The count must be between {minimum} and {maximum}. - A számnak {minimum} és {maximum} között kell lennie. + A számnak {minimum} és {maximum} között kell lennie. + The given value was not a valid date. - A megadott érték nem érvényes dátum. + A megadott érték nem érvényes dátum. + The given date must be between {formatEarliestDate} and {formatLatestDate} - A dátumnak {formatEarliestDate} és {formatLatestDate} között kell lennie + A dátumnak {formatEarliestDate} és {formatLatestDate} között kell lennie + The given date must be after {formatEarliestDate} - A dátumnak {formatEarliestDate} után kell lennie + A dátumnak {formatEarliestDate} után kell lennie + The given date must be before {formatLatestDate} - A dátumnak {formatLatestDate} előtt kell lennie + A dátumnak {formatLatestDate} előtt kell lennie + Please specify a valid email address. - Adjon meg egy érvényes e-mail címet. + Adjon meg egy érvényes e-mail címet. + A valid float number is expected. - Egy érvényes lebegőpontos szám szükséges. + Egy érvényes lebegőpontos szám szükséges. + A valid integer number is expected. - Egy érvényes egész szám szükséges. + Egy érvényes egész szám szükséges. + Only letters, numbers, spaces and certain punctuation marks are expected. - Csak betűk, számok, szóközök és egyes írásjelek érvényesek. + Csak betűk, számok, szóközök és egyes írásjelek érvényesek. + This property is required. - Ez a tulajdonság szükséges. + Ez a tulajdonság szükséges. + A valid number is expected. - Érvényes szám szükséges. + Érvényes szám szükséges. + Please enter a valid number between {minimum} and {maximum} - Adjon meg egy érvényes számot {minimum} és {maximum} között + Adjon meg egy érvényes számot {minimum} és {maximum} között + The given subject did not match the pattern ({pattern}) - Az megadott tárgy nem található a mintában. {pattern} adott + Az megadott tárgy nem található a mintában. {pattern} adott + A valid string is expected. - Érvényes karakterlánc szükséges. + Érvényes karakterlánc szükséges. + Valid text without any XML tags is expected. - XML tagok nélküli text szükséges. + XML tagok nélküli text szükséges. + The given subject is not a valid UUID. - Az adott tárgy nem egy érvényes UUID. + Az adott tárgy nem egy érvényes UUID. + Toggle content dimensions selector - Tartalom méretezés láthatósága + Tartalom méretezés láthatósága + Start with an empty or pre-filled document? - Indít egy üres vagy kitöltött dokumentummal? + Indít egy üres vagy kitöltött dokumentummal? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Ez a {nodeTypeLabel} még nem létezik a {currentDimensionChoiceText}. + Ez a {nodeTypeLabel} még nem létezik a {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Tudod teremt ez most, vagy egy üres kezdve {nodeTypeLabel} vagy minden tartalom másolása a jelenleg látható {nodeTypeLabel} a {currentDocumentDimensionChoiceText}. + Tudod teremt ez most, vagy egy üres kezdve {nodeTypeLabel} vagy minden tartalom másolása a jelenleg látható {nodeTypeLabel} a {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Ezen kívül, vannak {numberOfNodesMissingInRootline} őse a dokumentumokat, amelyek nem találhatók meg a választott változatra sem, és ami jön létre is. + Ezen kívül, vannak {numberOfNodesMissingInRootline} őse a dokumentumokat, amelyek nem találhatók meg a választott változatra sem, és ami jön létre is. + Create empty - Üres fájl létrehozása + Üres fájl létrehozása + Create and copy - Létrehozása és másolása + Létrehozása és másolása + Content - Tartalom + Tartalom + Toggle menu group - Toggle menü csoport + Toggle menü csoport + Toggle sticky menu mode - Váltás ragacsos menüt mode + Váltás ragacsos menüt mode + Do you really want to delete - Biztosan törlöd + Biztosan törlöd + This will delete the element - Igen, törlöm az elemet + Igen, törlöm az elemet + and it's children - és ez a gyermek + és ez a gyermek + This action can be undone in the workspace management. - Ez a művelet lehet visszafordítani a munkaterület kezelését. + Ez a művelet lehet visszafordítani a munkaterület kezelését. + Height - Magasság + Magasság + Do you really want to delete - Biztosan törlöd + Biztosan törlöd + this element - ez az elem + ez az elem + This will delete the element. - Igen, törlöm az elemet. + Igen, törlöm az elemet. + This action can be undone in the workspace management. - Ez a művelet lehet visszafordítani a munkaterület kezelését. + Ez a művelet lehet visszafordítani a munkaterület kezelését. + Media - Média + Média + Crop - Vágás + Vágás + Width - Szélesség + Szélesség + Missing required property: - Ez a kötelező mező nincs kitöltve: + Ez a kötelező mező nincs kitöltve: + Workspace - Munkaterület + Munkaterület + Workspaces - Munkaterület + Munkaterület + An error occurred during saving - Hiba történt mentés közben + Hiba történt mentés közben + Reload the page to attempt to fix the problem. - Újratölti az oldalt, hogy megpróbálja megoldani a problémát. + Újratölti az oldalt, hogy megpróbálja megoldani a problémát. + Reload the backend - Újratölti a háttér + Újratölti a háttér + Reload - Újratöltés + Újratöltés + In-Place - -Ban-hely + -Ban-hely + Raw Content - Nyers tartalom + Nyers tartalom + Raw Content Mode - Nyers tartalom mód + Nyers tartalom mód + Desktop - Asztal + Asztal + Login to - Logika-hoz + Logika-hoz + Authenticating - Hitelesítés + Hitelesítés + Logout - Kijelentkezés + Kijelentkezés + The entered username or password was wrong - A megadott Felhasználónév vagy jelszó volt a baj + A megadott Felhasználónév vagy jelszó volt a baj + Your login has expired. Please log in again. - Lejárt a bejelentkezési adatait. Kérjük, jelentkezzen be újra. + Lejárt a bejelentkezési adatait. Kérjük, jelentkezzen be újra. + Welcome to Neos - Welcome to Neos + Welcome to Neos + Go to setup - Kattintsona a beállításhoz + Kattintsona a beállításhoz + Technical Information - Technical Information + Technical Information + Missing Homepage - Hiányzó honlap + Hiányzó honlap + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Nem a helyszínen definiálva van, a webhely nem tartalmaz egy honlap vagy az aktív webhely nem kell meghatározni. + Nem a helyszínen definiálva van, a webhely nem tartalmaz egy honlap vagy az aktív webhely nem kell meghatározni. + You might want to set the site's domain or import a new site in the setup. - Érdemes az oldal domain vagy importálhatja egy új oldal a telepítés. + Érdemes az oldal domain vagy importálhatja egy új oldal a telepítés. + Database Error - Adatbázis hiba + Adatbázis hiba + There is no database connection yet or the Neos database schema has not been created. - Nincs adatbázis kapcsolat vagy a Neos adatbázis séma nem lett létrehozva. + Nincs adatbázis kapcsolat vagy a Neos adatbázis séma nem lett létrehozva. + Run the setup to configure your database. - Futtassa a telepítőt az adatbázis beállításához. + Futtassa a telepítőt az adatbázis beállításához. + Page Not Found - Az oldal nem található + Az oldal nem található + Sorry, the page you requested was not found. - Nem található a kért cikk. (Automatic Translation). + Nem található a kért cikk. (Automatic Translation). + Invalid NodeType - Érvénytelen csomópont + Érvénytelen csomópont + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - A csomópont konfigurációja nem érhető el. Valószínűleg a csomópontot átnevezték és hiányzik a migrálás vagy egyszerűen elírta. + A csomópont konfigurációja nem érhető el. Valószínűleg a csomópontot átnevezték és hiányzik a migrálás vagy egyszerűen elírta. + Unexpected error while creating node - Váratlan hiba a csomópont létrehozása során + Váratlan hiba a csomópont létrehozása során + Unexpected error while deleting node - Váratlan hiba a csomópont törlése során + Váratlan hiba a csomópont törlése során + Unexpected error while updating node - Váratlan hiba a csomópont frissítése során + Váratlan hiba a csomópont frissítése során + Unexpected error while moving node - Váratlan hiba a csomópont mozgatása során + Váratlan hiba a csomópont mozgatása során + Node Tree loading error. - Csomópont fa töltési hiba. + Csomópont fa töltési hiba. + - - The entered username or password was wrong - A megadott Felhasználónév vagy jelszó volt a baj "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" oldalon "{pageLabel}" + "{nodeTypeName}" oldalon "{pageLabel}" + Nodes - Csomópontok + Csomópontok + Show - Mutat + Mutat + This node cannot be accessed through a public URL - Ez a csomópont nem érhető el nyilvános URL-címen + Ez a csomópont nem érhető el nyilvános URL-címen + Node Properties - Csomópont tulajdonságai + Csomópont tulajdonságai + Copy {source} to {target} - Másolás {source} {target} + Másolás {source} {target} + Move {source} to {target} - Mozgatás {source} {target} + Mozgatás {source} {target} + Please select the position at which you want {source} inserted relative to {target}. - Válassza ki azt a pozíciót, ahová {source} értékét kívánja beilleszteni {target}. + Válassza ki azt a pozíciót, ahová {source} értékét kívánja beilleszteni {target}. + Insert - Beszúrás + Beszúrás + Insert mode - Beszúrás mód + Beszúrás mód + Choose an Aspect Ratio - Képarány + Képarány + Bold - Vastag betűtípus + Vastag betűtípus + Italic - Dőlt betűtípus + Dőlt betűtípus + Underline - Aláhúzott + Aláhúzott + Subscript - Alsó index + Alsó index + Superscript - Felső index + Felső index + Strikethrough - Áthúzás + Áthúzás + Link - Hivatkozás + Hivatkozás + Ordered list - Sorkizárt + Sorkizárt + Unordered list - Szétszort + Szétszort + Align left - Balra igazítás + Balra igazítás + Align right - Jobbra igazítás + Jobbra igazítás + Align center - Középre igazítás + Középre igazítás + Align justify - Sorkizárt + Sorkizárt + Table - Asztal + Asztal + Remove format - Formázás eltávolítása + Formázás eltávolítása + Outdent - Befejezés + Befejezés + Indent - Bekezdés + Bekezdés + Create new - Új létrehozása + Új létrehozása + No matches found - Nincs egyezés + Nincs egyezés + Please enter ###CHARACTERS### more character - Kérjük adjon meg ###CHARACTERS### több karaktert + Kérjük adjon meg ###CHARACTERS### több karaktert + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - A megadott Felhasználónév vagy jelszó volt a baj + A megadott Felhasználónév vagy jelszó volt a baj + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/hu/Modules.xlf b/Neos.Neos/Resources/Private/Translations/hu/Modules.xlf index a3cc012a8cb..d2c87170899 100644 --- a/Neos.Neos/Resources/Private/Translations/hu/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/hu/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Minden változás a munkafelületen "{0}" el lett vetve. - - History - Előzmények - - - This module provides an overview of all relevant events affecting this Neos installation. - Ez a modul áttekintést ad az összes fontos eseményről, amely befolyásolja a Neos telepítést. - - - Here's what happened recently in Neos - Itt van, ami nemrégiben történt a Neos-on - - - There have not been recorded any events yet which could be displayed in this history. - Nincs még felvett eseméyn, ami megjeleníthető lenne az előzményekben. - - - {0} created the {1} "{2}". - {0} létrehozta {1} "{2}". - - - {0} removed the {1} "{2}". - {0} eltávolította {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} létrehozta a változatot {1} a {2} "{3}". - - - {0} modified the {1} "{2}". - {0} módosult {1} "{2}". - - - {0} moved the {1} "{2}". - {0} mozgatta {1} "{2}". - - - {0} copied the {1} "{2}". - {0} másolta {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} átnevezte {1} "{2}" "{3}"-ra. - - - {0} modified content on the {1} "{2}". - {0} megváltoztatta a tartalmat {1} "{2}"-re. - - - {0} created a new user "{1}" for {2}. - {0} létrehozott egy új felhasználót "{1}" {2}. - - - {0} deleted the account "{1}" of {2}. - {0} törölt egy felhasználót "{1}" {2}. - - - Load More - Többet - - - This node has been removed in the meantime - Ezt a csomópontot idő közben eltávolították - Administration diff --git a/Neos.Neos/Resources/Private/Translations/id_ID/Main.xlf b/Neos.Neos/Resources/Private/Translations/id_ID/Main.xlf index c586f0c9bad..2b14cee94cf 100644 --- a/Neos.Neos/Resources/Private/Translations/id_ID/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/id_ID/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Auto-Publish + Auto-Publish + Auto-Publish to {0} - Publikasikan otomatis ke {0} + Publikasikan otomatis ke {0} + Review changes - Meninjau perubahan + Meninjau perubahan + Apply - Menerapkan + Menerapkan + Apply changes - Menerapkan perubahan + Menerapkan perubahan + Cancel - Batalkan + Batalkan + Back - Kembali + Kembali + Choose - Memilih + Memilih + Type to search - Ketik untuk mencari + Ketik untuk mencari + Content - Konten + Konten + Node - Node + Node + Content View - Tampilan Konten + Tampilan Konten + Create after - Membuat setelah + Membuat setelah + Create new - Buat baru + Buat baru + Close - Tutup + Tutup + Copy - Salin + Salin + Cut - Potong + Potong + Delete - Hapus + Hapus + Yes, delete the element - Ya, menghapus elemen + Ya, menghapus elemen + Delete the element - Menghapus elemen + Menghapus elemen + Discard - Abaikan + Abaikan + Discard changes - Batalkan Perubahan + Batalkan Perubahan + Edit title - Edit judul + Edit judul + Edit / Preview - Mengedit / melihat pratinjau + Mengedit / melihat pratinjau + Edit - Ubah + Ubah + Hide / Unhide - Sembunyikan / Tampilkan + Sembunyikan / Tampilkan + Hide - Sembunyikan + Sembunyikan + Unhide - Tampilkan + Tampilkan + into - ke + ke + before - sebelum + sebelum + after - setelah + setelah + Loading - Memuat + Memuat + New After - Baru setelah + Baru setelah + New Before - Baru sebelum + Baru sebelum + New Into - Baru ke + Baru ke + Navigate - Navigasi + Navigasi + OK - OK + OK + Page - Halaman + Halaman + Paste - Tempel + Tempel + Paste After - Sisipkan setelah + Sisipkan setelah + Paste Before - Sisipkan sebelum + Sisipkan sebelum + Paste Into - Sisipkan ke + Sisipkan ke + Password - Kata sandi + Kata sandi + Preview - Tinjauan + Tinjauan + Publish - Terbitkan + Terbitkan + Publish to {0} - Mempublikasikan ke {0} + Mempublikasikan ke {0} + Publish all changes for current page - Mempublikasikan semua perubahan untuk halaman saat ini + Mempublikasikan semua perubahan untuk halaman saat ini + Can't publish because the target workspace is read-only - Tidak dapat mempublikasikan karena target kerja adalah read-only + Tidak dapat mempublikasikan karena target kerja adalah read-only + Select target workspace - Memilih target kerja + Memilih target kerja + Publishing - Penerbitan + Penerbitan + Published - Telah terbit + Telah terbit + Toggle publish menu - Toogle menu penerbitan + Toogle menu penerbitan + Target workspace - Target bidang kerja + Target bidang kerja + Current workspace - Bidang kerja saat ini + Bidang kerja saat ini + Remove - Hapus + Hapus + Refresh - Muat ulang + Muat ulang + Save - Simpan + Simpan + Saving - Menyimpan + Menyimpan + Saved - Disimpan + Disimpan + Search - Pencarian + Pencarian + Toggle inspector - Toggle Inspektur + Toggle Inspektur + Username - Nama Pengguna + Nama Pengguna + You - Anda + Anda + [no title] - [tidak ada judul] + [tidak ada judul] + Label - Label + Label + Content Type - Jenis konten + Jenis konten + Path - Jalur + Jalur + Relative Path - Jalur relatif + Jalur relatif + Version - Versi + Versi + This operation cannot be undone. - Operasi ini tidak bisa dibatalkan. + Operasi ini tidak bisa dibatalkan. + Asset - Aset + Aset + Created - Dibuat + Dibuat + Last modification - Modifikasi terakhir + Modifikasi terakhir + Last publication - Publikasi terakhir + Publikasi terakhir + Identifier - Pengenal + Pengenal + Name - Nama + Nama + Workspace - Bidang Kerja + Bidang Kerja + Structure - Struktur + Struktur + Toggle context structure - Toggle konteks struktur + Toggle konteks struktur + Filter - Penyaring + Penyaring + Toggle menu - Toggle menu + Toggle menu + Load error! - Kesalahan muatan! + Kesalahan muatan! + You have to select a node - Anda harus memilih sebuah node + Anda harus memilih sebuah node + The Root node cannot be deleted. - Node akar tidak dapat dihapus. + Node akar tidak dapat dihapus. + You cannot copy this node - Anda tidak dapat menyalin node ini + Anda tidak dapat menyalin node ini + You cannot cut this node - Anda tidak bisa memotong node ini + Anda tidak bisa memotong node ini + Content Dimensions - Dimensi konten + Dimensi konten + Site - Situs + Situs + Document - Dokumen + Dokumen + Reference - Referensi + Referensi + Host - Host + Host + Scheme - Skema + Skema + Port - Port + Port + Primary - Utama + Utama + Package - Paket + Paket + Deactivated - Dinonaktifkan + Dinonaktifkan + Unavailable - Tidak tersedia + Tidak tersedia + Inactive - Tidak aktif + Tidak aktif + Click to edit - Klik untuk mengubah + Klik untuk mengubah + Click to deactivate - Klik untuk menonaktifkan + Klik untuk menonaktifkan + Click to activate - Klik untuk mengaktifkan + Klik untuk mengaktifkan + Click to delete - Klik untuk menghapus + Klik untuk menghapus + Click to create new - Klik untuk buat yang baru + Klik untuk buat yang baru + Status - Status + Status + Active - Aktif + Aktif + Domains - Domain + Domain + Domain - Domain + Domain + Yes, delete it! - Ya, hapus! + Ya, hapus! + Package Key - Kunci paket + Kunci paket + Description - Deskripsi + Deskripsi + Toggle content tree - Beralih ke pohon konten + Beralih ke pohon konten + Show publish options - Tampilkan opsi publikasi + Tampilkan opsi publikasi + Activate Fullscreen edit mode - Aktifkan mode ubah Layar Penuh + Aktifkan mode ubah Layar Penuh + Deactivate Fullscreen edit mode - Nonaktifkan mode ubah Layar Penuh + Nonaktifkan mode ubah Layar Penuh + Show preview - Tampilkan pratinjau + Tampilkan pratinjau + General - Umum + Umum + Structure - Struktur + Struktur + Plugins - Plugin + Plugin + Click {0} to continue to the page. - Klik {0} untuk melanjutkan ke halaman. + Klik {0} untuk melanjutkan ke halaman. + Click {0} to see the file. - Klik {0} untuk melihat file. + Klik {0} untuk melihat file. + Click {0} to open the link. - Klik {0} untuk membuka link. + Klik {0} untuk membuka link. + (no target has been selected) - (tidak ada target telah dipilih) + (tidak ada target telah dipilih) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Ini adalah shortcut untuk halaman pertama anak. <br /> klik {0} untuk melanjutkan ke halaman. + Ini adalah shortcut untuk halaman pertama anak. <br /> klik {0} untuk melanjutkan ke halaman. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Ini adalah shortcut untuk halaman induk. <br /> klik {0} untuk melanjutkan ke halaman. + Ini adalah shortcut untuk halaman induk. <br /> klik {0} untuk melanjutkan ke halaman. + Full Screen - Layar penuh + Layar penuh + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Buka halaman di bidang kerja hidup + Buka halaman di bidang kerja hidup + Open page in target workspace - Buka halaman di bidang kerja target + Buka halaman di bidang kerja target + Discard all - Membuang semua + Membuang semua + Discard all changes - Buang semua perubahan + Buang semua perubahan + Are you sure that you want to discard all changes in this workspace? - Apakah Anda yakin bahwa Anda ingin membuang semua perubahan dalam bidang kerja ini? + Apakah Anda yakin bahwa Anda ingin membuang semua perubahan dalam bidang kerja ini? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Apakah Anda yakin ingin membuang perubahan {numberOfChanges} di ruang kerja ini? + Apakah Anda yakin ingin membuang perubahan {numberOfChanges} di ruang kerja ini? + Publish all - Mempublikasikan semua + Mempublikasikan semua + Publish all changes - Mempublikasikan semua perubahan + Mempublikasikan semua perubahan + Are you sure that you want to publish all changes? - Apakah Anda yakin bahwa Anda ingin mempublikasikan semua perubahan? + Apakah Anda yakin bahwa Anda ingin mempublikasikan semua perubahan? + Pending changes - Perubahan tertunda + Perubahan tertunda + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Ruang kerja pribadi Anda saat ini berisi perubahan yang tidak diterbitkan. Untuk beralih ke sasaran bidang kerja yang berbeda Anda perlu untuk menerbitkan atau membuang perubahan yang tertunda terlebih dahulu. + Ruang kerja pribadi Anda saat ini berisi perubahan yang tidak diterbitkan. Untuk beralih ke sasaran bidang kerja yang berbeda Anda perlu untuk menerbitkan atau membuang perubahan yang tertunda terlebih dahulu. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Harap Tinjau perubahan, publikasikan atau membuangnya, dan kemudian memilih sasaran bidang kerja baru lagi. + Harap Tinjau perubahan, publikasikan atau membuangnya, dan kemudian memilih sasaran bidang kerja baru lagi. + Editing Modes - Mode Pengeditan + Mode Pengeditan + Preview Central - Pusat Tinjauan + Pusat Tinjauan + You still have changes. What do you want to do with them? - Anda masih memiliki perubahan. Apa yang Anda ingin lakukan dengan perubahan itu? + Anda masih memiliki perubahan. Apa yang Anda ingin lakukan dengan perubahan itu? + Selected element - Elemen yang dipilih + Elemen yang dipilih + There are fields that are not correctly filled in. - Ada bidang yang tidak benar diisi. + Ada bidang yang tidak benar diisi. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Kolom yang ditandai dengan kesalahan belum benar diisi. Silahkan lengkapi dengan benar. + Kolom yang ditandai dengan kesalahan belum benar diisi. Silahkan lengkapi dengan benar. + Continue editing - Lanjutkan mengedit + Lanjutkan mengedit + Throw away - Membuang + Membuang + Apply - Menerapkan + Menerapkan + Select a Plugin - Pilih sebuah Plugin + Pilih sebuah Plugin + No plugin configured - Tidak ada Plugin dikonfigurasi + Tidak ada Plugin dikonfigurasi + view is displayed on page - view ditampilkan pada halaman + view ditampilkan pada halaman + view is displayed on current page - view ditampilkan pada Halaman ini + view ditampilkan pada Halaman ini + No date set - Tidak ada tanggal yang ditetapkan + Tidak ada tanggal yang ditetapkan + Edit code - Mengedit kode + Mengedit kode + Paste a link, or type to search - Sisipkan link, atau ketik ke pencarian + Sisipkan link, atau ketik ke pencarian + Unable to load sub node types of: - Tidak dapat memuat sub node jenis: + Tidak dapat memuat sub node jenis: + Change type - Ubah jenis + Ubah jenis + Additional info - Info tambahan + Info tambahan + Visibility - Visibilitas + Visibilitas + Document options - Piihan Dokumen + Piihan Dokumen + The length of this text must be between {minimum} and {maximum} characters. - Panjang teks ini harus antara {minimum} dan {maximum} karakter. + Panjang teks ini harus antara {minimum} dan {maximum} karakter. + This field must contain at least {minimum} characters. - Bidang ini harus mengandung setidaknya {minimum} karakter. + Bidang ini harus mengandung setidaknya {minimum} karakter. + This text may not exceed {maximum} characters. - Teks ini tidak boleh melebihi {maximum} karakter. + Teks ini tidak boleh melebihi {maximum} karakter. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Hanya karakter biasa (A sampai z, umlauts,...) dan angka yang diperbolehkan. + Hanya karakter biasa (A sampai z, umlauts,...) dan angka yang diperbolehkan. + The given subject was not countable. - Subjek tertentu itu tidak dihitung. + Subjek tertentu itu tidak dihitung. + The count must be between {minimum} and {maximum}. - Jumlah harus antara {minimum} dan {maximum}. + Jumlah harus antara {minimum} dan {maximum}. + The given value was not a valid date. - Nilai yang diberikan bukanlah tanggal yang valid. + Nilai yang diberikan bukanlah tanggal yang valid. + The given date must be between {formatEarliestDate} and {formatLatestDate} - Tanggal yang diberikan harus antara {formatEarliestDate} dan {formatLatestDate} + Tanggal yang diberikan harus antara {formatEarliestDate} dan {formatLatestDate} + The given date must be after {formatEarliestDate} - Tanggal yang diberikan harus setelah {formatEarliestDate} + Tanggal yang diberikan harus setelah {formatEarliestDate} + The given date must be before {formatLatestDate} - Tanggal yang diberikan harus sebelum {formatLatestDate} + Tanggal yang diberikan harus sebelum {formatLatestDate} + Please specify a valid email address. - Silakan tentukan alamat email yang valid. + Silakan tentukan alamat email yang valid. + A valid float number is expected. - Angka valid yang muncul diharapkan. + Angka valid yang muncul diharapkan. + A valid integer number is expected. - Bilangan bulat yang valid diharapkan. + Bilangan bulat yang valid diharapkan. + Only letters, numbers, spaces and certain punctuation marks are expected. - Hanya huruf, angka, spasi dan tanda baca tertentu diharapkan. + Hanya huruf, angka, spasi dan tanda baca tertentu diharapkan. + This property is required. - Properti ini diperlukan. + Properti ini diperlukan. + A valid number is expected. - Nomor yang valid diharapkan. + Nomor yang valid diharapkan. + Please enter a valid number between {minimum} and {maximum} - Masukkan nomor yang valid antara {minimum} dan {maximum} + Masukkan nomor yang valid antara {minimum} dan {maximum} + The given subject did not match the pattern ({pattern}) - Subjek yang diberikan tidak cocok dengan pola ({pattern}) + Subjek yang diberikan tidak cocok dengan pola ({pattern}) + A valid string is expected. - String yang valid diharapkan. + String yang valid diharapkan. + Valid text without any XML tags is expected. - Teks yang valid tanpa tag XML diharapkan. + Teks yang valid tanpa tag XML diharapkan. + The given subject is not a valid UUID. - Subjek tertentu bukanlah UUID yang valid. + Subjek tertentu bukanlah UUID yang valid. + Toggle content dimensions selector - Toggle pemilih dimensi konten + Toggle pemilih dimensi konten + Start with an empty or pre-filled document? - Mulai dengan dokumen kosong atau halaman berisi? + Mulai dengan dokumen kosong atau halaman berisi? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - {nodeTypeLabel} ini tidak ada lagi di {currentDimensionChoiceText}. + {nodeTypeLabel} ini tidak ada lagi di {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Anda dapat membuat itu sekarang, dimulai dengan {nodeTypeLabel} kosong atau menyalin semua konten dari {nodeTypeLabel} saat ini terlihat di {currentDocumentDimensionChoiceText}. + Anda dapat membuat itu sekarang, dimulai dengan {nodeTypeLabel} kosong atau menyalin semua konten dari {nodeTypeLabel} saat ini terlihat di {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Selain itu, ada {numberOfNodesMissingInRootline} pusat dokumen yang tidak ada di varian pilihan dan yang akan dibuat juga. + Selain itu, ada {numberOfNodesMissingInRootline} pusat dokumen yang tidak ada di varian pilihan dan yang akan dibuat juga. + Create empty - Membuat kosong + Membuat kosong + Create and copy - Membuat dan Salin + Membuat dan Salin + Content - Konten + Konten + Toggle menu group - Toggle menu grup + Toggle menu grup + Toggle sticky menu mode - Toggle mode menu sticky + Toggle mode menu sticky + Do you really want to delete - Apakah Anda benar-benar ingin menghapus + Apakah Anda benar-benar ingin menghapus + This will delete the element - Ini akan menghapus elemen + Ini akan menghapus elemen + and it's children - dan sub bagian itu + dan sub bagian itu + This action can be undone in the workspace management. - Tindakan ini dapat dibatalkan dalam pengelolaan bidang kerja. + Tindakan ini dapat dibatalkan dalam pengelolaan bidang kerja. + Height - Tinggi + Tinggi + Do you really want to delete - Apakah Anda benar-benar ingin menghapus + Apakah Anda benar-benar ingin menghapus + this element - elemen ini + elemen ini + This will delete the element. - Ini akan menghapus elemen. + Ini akan menghapus elemen. + This action can be undone in the workspace management. - Tindakan ini dapat dibatalkan dalam pengelolaan bidang kerja. + Tindakan ini dapat dibatalkan dalam pengelolaan bidang kerja. + Media - Media + Media + Crop - Potong + Potong + Width - Lebar + Lebar + Missing required property: - Kehilangan properti yang diperlukan: + Kehilangan properti yang diperlukan: + Workspace - Bidang Kerja + Bidang Kerja + Workspaces - Bidang Kerja + Bidang Kerja + An error occurred during saving - Terjadi error saat menyimpan + Terjadi error saat menyimpan + Reload the page to attempt to fix the problem. - Reload halaman untuk mencoba untuk memperbaiki masalah. + Reload halaman untuk mencoba untuk memperbaiki masalah. + Reload the backend - Muat ulang backend + Muat ulang backend + Reload - Muat ulang + Muat ulang + In-Place - Di-tempat + Di-tempat + Raw Content - Konten Mentah + Konten Mentah + Raw Content Mode - Mode Konten Mentah + Mode Konten Mentah + Desktop - Destop + Destop + Login to - Login ke + Login ke + Authenticating - Autentikasi + Autentikasi + Logout - Keluar + Keluar + The entered username or password was wrong - Username atau password yang dimasukkan salah + Username atau password yang dimasukkan salah + Your login has expired. Please log in again. - Login Anda telah kedaluwarsa. Silakan log in lagi. + Login Anda telah kedaluwarsa. Silakan log in lagi. + Welcome to Neos - Selamat datang di Neos + Selamat datang di Neos + Go to setup - Pergi ke pengaturan + Pergi ke pengaturan + Technical Information - Informasi Teknis + Informasi Teknis + Missing Homepage - Homepage hilang + Homepage hilang + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Entah tidak ada situs telah ditetapkan, situs tidak mengandung homepage atau situs aktif tidak bisa ditentukan. + Entah tidak ada situs telah ditetapkan, situs tidak mengandung homepage atau situs aktif tidak bisa ditentukan. + You might want to set the site's domain or import a new site in the setup. - Anda mungkin ingin untuk mengatur domain situs atau mengimpor situs baru di setup. + Anda mungkin ingin untuk mengatur domain situs atau mengimpor situs baru di setup. + Database Error - Database Error + Database Error + There is no database connection yet or the Neos database schema has not been created. - Belum ada koneksi basis data atau skema basis data Neos belum dibuat. + Belum ada koneksi basis data atau skema basis data Neos belum dibuat. + Run the setup to configure your database. - Jalankan pengaturan untuk mengkonfigurasi basis data Anda. + Jalankan pengaturan untuk mengkonfigurasi basis data Anda. + Page Not Found - Halaman Tidak Ditemukan + Halaman Tidak Ditemukan + Sorry, the page you requested was not found. - Maaf, halaman yang Anda cari tidak ditemukan. + Maaf, halaman yang Anda cari tidak ditemukan. + Invalid NodeType - Tipe Node tidak valid + Tipe Node tidak valid + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - Konfigurasi NodeType yang seharusnya diberikan berikut ini tidak tersedia. Mungkin Anda telah mengganti nama dan itu hilang dalam perpindahan atau Anda hanya salah eja. + Konfigurasi NodeType yang seharusnya diberikan berikut ini tidak tersedia. Mungkin Anda telah mengganti nama dan itu hilang dalam perpindahan atau Anda hanya salah eja. + Unexpected error while creating node - Kesalahan yang tidak terduga saat membuat node + Kesalahan yang tidak terduga saat membuat node + Unexpected error while deleting node - Kesalahan yang tidak terduga saat menghapus node + Kesalahan yang tidak terduga saat menghapus node + Unexpected error while updating node - Kesalahan yang tidak terduga saat memperbarui node + Kesalahan yang tidak terduga saat memperbarui node + Unexpected error while moving node - Kesalahan yang tidak terduga saat memindahkan node + Kesalahan yang tidak terduga saat memindahkan node + Node Tree loading error. - Pemuatan Pohon Node eror. + Pemuatan Pohon Node eror. + - - The entered username or password was wrong - Username atau password yang dimasukkan salah "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" di halaman "{pageLabel}" + "{nodeTypeName}" di halaman "{pageLabel}" + Nodes - Node-node + Node-node + Show - Tampilkan + Tampilkan + This node cannot be accessed through a public URL - Node ini tidak dapat diakses melalui URL Umum + Node ini tidak dapat diakses melalui URL Umum + Node Properties - Properti Node + Properti Node + Copy {source} to {target} - Salin {source} ke {target} + Salin {source} ke {target} + Move {source} to {target} - Pindah {source} ke {target} + Pindah {source} ke {target} + Please select the position at which you want {source} inserted relative to {target}. - Pilihlah pada posisi mana anda ingin {source} dimasukkan, relatif terhadap {target}. + Pilihlah pada posisi mana anda ingin {source} dimasukkan, relatif terhadap {target}. + Insert - Sisipkan + Sisipkan + Insert mode - Sisipkan mode + Sisipkan mode + Choose an Aspect Ratio - Tentukan Perbandingan Segi + Tentukan Perbandingan Segi + Bold - Tebal + Tebal + Italic - Miring + Miring + Underline - Garis Bawah + Garis Bawah + Subscript - Tulisan di bawah + Tulisan di bawah + Superscript - Tulisan di atas + Tulisan di atas + Strikethrough - Coret + Coret + Link - Link / tautan + Link / tautan + Ordered list - Daftar Setelah Diurutkan + Daftar Setelah Diurutkan + Unordered list - Daftar Tanpa Diurutkan + Daftar Tanpa Diurutkan + Align left - Rata kiri + Rata kiri + Align right - Rata kanan + Rata kanan + Align center - Rata Tengah + Rata Tengah + Align justify - Rata Kanan-Kiri + Rata Kanan-Kiri + Table - Tabel + Tabel + Remove format - Hapus format + Hapus format + Outdent - Menjorok Keluar + Menjorok Keluar + Indent - Menjorok Masuk + Menjorok Masuk + Create new - Buat baru + Buat baru + No matches found - Tidak ada temuan yang cocok + Tidak ada temuan yang cocok + Please enter ###CHARACTERS### more character - Masukkan ## #CHARACTERS### karakter lain + Masukkan ## #CHARACTERS### karakter lain + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - Username atau password yang dimasukkan salah + Username atau password yang dimasukkan salah + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/id_ID/Modules.xlf b/Neos.Neos/Resources/Private/Translations/id_ID/Modules.xlf index 9ce46436820..f3f44591232 100644 --- a/Neos.Neos/Resources/Private/Translations/id_ID/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/id_ID/Modules.xlf @@ -257,70 +257,6 @@ All changes from workspace "{0}" have been discarded. Semua perubahan dari ruang kerja " {0} " telah dibuang. - - History - Sejarah - - - This module provides an overview of all relevant events affecting this Neos installation. - Modul ini memberikan gambaran umum tentang semua peristiwa yang relevan yang mempengaruhi pemasangan Neos ini. - - - Here's what happened recently in Neos - Inilah yang terjadi baru-baru ini di Neos - - - There have not been recorded any events yet which could be displayed in this history. - Belum ada rekaman acara yang bisa ditampilkan dalam sejarah ini. - - - {0} created the {1} "{2}". - {0} membuat {1} "{2}". - - - {0} removed the {1} "{2}". - {0} menghapus {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} membuat varian {1} dari {2} "{3}". - - - {0} modified the {1} "{2}". - {0} mengubah {1} "{2}". - - - {0} moved the {1} "{2}". - {0} memindah {1} "{2}". - - - {0} copied the {1} "{2}". - {0} menyalin {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} mengganti nama {1} "{2}" menjadi "{3}". - - - {0} modified content on the {1} "{2}". - {0} mengubah konten pada {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} membuat pengguna baru "{1}" untuk {2}. - - - {0} deleted the account "{1}" of {2}. - {0} dihapus account "{1}" dari {2}. - - - Load More - Muat lagi - - - This node has been removed in the meantime - Node ini telah dihapus sementara - Administration diff --git a/Neos.Neos/Resources/Private/Translations/it/Main.xlf b/Neos.Neos/Resources/Private/Translations/it/Main.xlf index 3c70d787f23..cdd7d381bfa 100644 --- a/Neos.Neos/Resources/Private/Translations/it/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/it/Main.xlf @@ -951,10 +951,6 @@ Errore di Caricamento dell'albero del Nodo. - - The entered username or password was wrong - Il nome utente o la password inseriti erano sbagliati - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/it/Modules.xlf b/Neos.Neos/Resources/Private/Translations/it/Modules.xlf index 873d0b1e42f..5f65ffd2d69 100644 --- a/Neos.Neos/Resources/Private/Translations/it/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/it/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Tutte le modifiche dallo spazio di lavoro "{0}" sono state scartate. - - History - Cronologia - - - This module provides an overview of all relevant events affecting this Neos installation. - Questo modulo fornisce una panoramica di tutti gli eventi rilevanti che riguardano questa installazione di Neos. - - - Here's what happened recently in Neos - Ecco cosa è successo recentemente in Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Non sono ancora stati registrati eventi che potrebbero essere visualizzati in questa cronologia. - - - {0} created the {1} "{2}". - {0} creato il {1} "{2}". - - - {0} removed the {1} "{2}". - {0} rimosso il {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} creata la variante {1} delle {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modificato il {1} "{2}". - - - {0} moved the {1} "{2}". - {0} spostato il {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copiato il {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} rinominati {1} "{2}" a "{3}". - - - {0} modified content on the {1} "{2}". - {0} modificato il contenuto su {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} ha creato un nuovo utente "{1}" per {2}. - - - {0} deleted the account "{1}" of {2}. - {0} ha eliminato l'account "{1}" di {2}. - - - Load More - Carica Altro - - - This node has been removed in the meantime - Questo nodo è stato rimosso nel mentre - Administration diff --git a/Neos.Neos/Resources/Private/Translations/ja/Main.xlf b/Neos.Neos/Resources/Private/Translations/ja/Main.xlf index 37b28c32356..101aab18a3a 100644 --- a/Neos.Neos/Resources/Private/Translations/ja/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/ja/Main.xlf @@ -951,10 +951,6 @@ ノードツリーに負荷エラーになります。 - - The entered username or password was wrong - 入力したユーザー名やパスワードが間違っていたの - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/ja/Modules.xlf b/Neos.Neos/Resources/Private/Translations/ja/Modules.xlf index 3007b437440..0580d4512a9 100644 --- a/Neos.Neos/Resources/Private/Translations/ja/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/ja/Modules.xlf @@ -257,70 +257,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - History - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/km/Main.xlf b/Neos.Neos/Resources/Private/Translations/km/Main.xlf index 4d7a9e8c822..228db7a09d6 100644 --- a/Neos.Neos/Resources/Private/Translations/km/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/km/Main.xlf @@ -5,830 +5,1097 @@ Auto-Publish - ចុះផ្សាយស្វ័យប្រវត្តិ + ចុះផ្សាយស្វ័យប្រវត្តិ + Auto-Publish to {0} - ដើម្បីបោះពុម្ពផ្សាយដោយស្វ័យប្រវត្តិ {0} + ដើម្បីបោះពុម្ពផ្សាយដោយស្វ័យប្រវត្តិ {0} + Review changes - ការផ្លាស់ប្តូរពិនិត្យឡើងវិញ + ការផ្លាស់ប្តូរពិនិត្យឡើងវិញ + Apply - អនុវត្ត + អនុវត្ត + Apply changes - អនុវត្តការផ្លាស់ប្តូរ + អនុវត្តការផ្លាស់ប្តូរ + Cancel - បោះបង់ + បោះបង់ + Back - ត្រលប់ក្រោយ + ត្រលប់ក្រោយ + Choose - ជ្រើសរើស + ជ្រើសរើស + Type to search - សូមវាយពាក្យទីនេះដើម្បីស្វែងរក + សូមវាយពាក្យទីនេះដើម្បីស្វែងរក + Content - អត្ថបទ + អត្ថបទ + Node - ថ្នាំង + ថ្នាំង + Content View - មើលអត្ថបទ + មើលអត្ថបទ + Create after - បង្កើតពេលបន្ទាប់ + បង្កើតពេលបន្ទាប់ + Create new - បង្កើតថ្មី + បង្កើតថ្មី + Close - បិទ + បិទ + Copy - ចម្លង + ចម្លង + Cut - កាត់ + កាត់ + Delete - លុប + លុប + Yes, delete the element - យល់ព្រម, លុបធាតុនោះ + យល់ព្រម, លុបធាតុនោះ + Delete the element - លុបធាតុនោះ + លុបធាតុនោះ + Discard - បោះបង់ + បោះបង់ + Discard changes - លះបង់​ការកែ + លះបង់​ការកែ + Edit title - កែ​ចំណង​ជើង + កែ​ចំណង​ជើង + Edit / Preview - កែ / ការមើលជាមុន + កែ / ការមើលជាមុន + Edit - កែប្រែ + កែប្រែ + Hide / Unhide - លាក់ / បង្ហាញ + លាក់ / បង្ហាញ + Hide - លាក់ + លាក់ + Unhide - កុំ​លាក់ + កុំ​លាក់ + into - ទៅក្នុង + ទៅក្នុង + before - មុន + មុន + after - បន្ទាប់ + បន្ទាប់ + Loading - កំពុងតម្លើង + កំពុងតម្លើង + New After - បង្កើតថ្មីបន្ទាប់ + បង្កើតថ្មីបន្ទាប់ + New Before - បង្កើតថ្មីមុន + បង្កើតថ្មីមុន + New Into - បង្កើតថ្មីទៅ + បង្កើតថ្មីទៅ + Navigate - រុករក + រុករក + OK - យល់ព្រម + យល់ព្រម + Page - ទំព័រ + ទំព័រ + Paste - បិទភ្ជាប់ + បិទភ្ជាប់ + Paste After - បិតភ្ជាប់បន្ទាប់ + បិតភ្ជាប់បន្ទាប់ + Paste Before - បិតភ្ជាប់មុន + បិតភ្ជាប់មុន + Paste Into - បិតភ្ជាប់ទៅ + បិតភ្ជាប់ទៅ + Password - ពាក្យ​សម្ងាត់ + ពាក្យ​សម្ងាត់ + Preview - មើលជាមុន + មើលជាមុន + Publish - ដាក់ផ្សាយ + ដាក់ផ្សាយ + Publish to {0} - បោះពុម្ពផ្សាយទៅ {0} + បោះពុម្ពផ្សាយទៅ {0} + Publish all changes for current page - ចុះផ្សាយរាល់ការផ្លាស់ប្ដូរសម្រាប់ទំព័រនេះ + ចុះផ្សាយរាល់ការផ្លាស់ប្ដូរសម្រាប់ទំព័រនេះ + Can't publish because the target workspace is read-only - មិនអាចផ្សាយបានទេព្រោះតំបន់ការងារគោលដៅត្រូវតែអាន + មិនអាចផ្សាយបានទេព្រោះតំបន់ការងារគោលដៅត្រូវតែអាន + Select target workspace - ជ្រើសតំបន់ការងារគោលដៅ + ជ្រើសតំបន់ការងារគោលដៅ + Publishing - កំពុងចុះផ្សាយ + កំពុងចុះផ្សាយ + Published - បានចុះផ្សាយ + បានចុះផ្សាយ + Toggle publish menu - បិទបើកម៉ឺនុយបោះពុម្ពផ្សាយ + បិទបើកម៉ឺនុយបោះពុម្ពផ្សាយ + Target workspace - ចូលទៅកាន់កន្លែងការងារ + ចូលទៅកាន់កន្លែងការងារ + Current workspace - ចន្លោះការងារបច្ចុប្បន្ន + ចន្លោះការងារបច្ចុប្បន្ន + Remove - លុបចេញ + លុបចេញ + Refresh - ធ្វើឱ្យស្រស់ + ធ្វើឱ្យស្រស់ + Save - សន្សំ រឺ រក្សាទុក + សន្សំ រឺ រក្សាទុក + Saving - កំពុង​រក្សា​ទុក + កំពុង​រក្សា​ទុក + Saved - បាន​រក្សា​ទុក + បាន​រក្សា​ទុក + Search - ស្វែងរក + ស្វែងរក + Toggle inspector - ត្រួតពិនិត្យបិទបើក + ត្រួតពិនិត្យបិទបើក + Username - ឈ្មោះ​គណនី + ឈ្មោះ​គណនី + You - អ្នក + អ្នក + [no title] - [គ្មានចំណងជើង] + [គ្មានចំណងជើង] + Label - ស្លាក + ស្លាក + Content Type - ប្រភេទនៃថ្នាំង + ប្រភេទនៃថ្នាំង + Path - ទីតាំង + ទីតាំង + Relative Path - ទីតាំងប្រែប្រួល + ទីតាំងប្រែប្រួល + Version - កំណែ + កំណែ + This operation cannot be undone. - ប្រតិបត្តិការនេះមិនអាចមិនធ្វើវិញ។ + ប្រតិបត្តិការនេះមិនអាចមិនធ្វើវិញ។ + Asset - កន្លែងដាក់អក្សរ + កន្លែងដាក់អក្សរ + Created - បានបង្កើត + បានបង្កើត + Last modification - ការកែប្រែចុងក្រោយនេះ + ការកែប្រែចុងក្រោយនេះ + Last publication - ការបោះពុម្ភលើកចុងក្រោយ + ការបោះពុម្ភលើកចុងក្រោយ + Identifier - អត្តសញ្ញាណ + អត្តសញ្ញាណ + Name - ឈ្មោះ + ឈ្មោះ + Workspace - កន្លែងផ្ទុកការងារ + កន្លែងផ្ទុកការងារ + Structure - រចនាសម្ព័ន្ធ + រចនាសម្ព័ន្ធ + Toggle context structure - បិទបើករចនាសម្ព័បរិបទ + បិទបើករចនាសម្ព័បរិបទ + Filter - តម្រង + តម្រង + Toggle menu - ម៉ឺនុយបិទបើក + ម៉ឺនុយបិទបើក + Load error! - ផ្ទុកកំហុស! + ផ្ទុកកំហុស! + You have to select a node - អ្នកត្រូវតែជ្រើសថ្នាំង + អ្នកត្រូវតែជ្រើសថ្នាំង + The Root node cannot be deleted. - ថ្នាំង root មិនអាចត្រូវបានលុប។ + ថ្នាំង root មិនអាចត្រូវបានលុប។ + You cannot copy this node - អ្នកមិនអាចចម្លងថ្នាំងនេះ + អ្នកមិនអាចចម្លងថ្នាំងនេះ + You cannot cut this node - អ្នកមិនអាចកាត់បន្ថយថ្នាំងនេះ + អ្នកមិនអាចកាត់បន្ថយថ្នាំងនេះ + Content Dimensions - វិមាត្រមាតិកា + វិមាត្រមាតិកា + Site - តំបន់បណ្តាញ + តំបន់បណ្តាញ + Document - ឯកសារ + ឯកសារ + Reference - ឯកសារយោង + ឯកសារយោង + Host - ម៉ាស៊ីន + ម៉ាស៊ីន + Scheme - គ្រោងការណ៍ + គ្រោងការណ៍ + Port - ផត + ផត + Primary - ចម្បង + ចម្បង + Package - Package + Package + Deactivated - ធ្វើឱ្យអសកម្ម + ធ្វើឱ្យអសកម្ម + Unavailable - Unavailable + Unavailable + Inactive - Inactive + Inactive + Click to edit - ចុចដើម្បីកែតម្រូវ + ចុចដើម្បីកែតម្រូវ + Click to deactivate - Click to deactivate + Click to deactivate + Click to activate - Click to activate + Click to activate + Click to delete - ចុចដើម្បីលុប + ចុចដើម្បីលុប + Click to create new - Click to create new + Click to create new + Status - Status + Status + Active - Active + Active + Domains - Domains + Domains + Domain - Domain + Domain + Yes, delete it! - Yes, delete it! + Yes, delete it! + Package Key - គន្លឹះកញ្ចប់ + គន្លឹះកញ្ចប់ + Description - ពិពណ៍នា + ពិពណ៍នា + Toggle content tree - Toggle content tree + Toggle content tree + Show publish options - Show publish options + Show publish options + Activate Fullscreen edit mode - Activate Fullscreen edit mode + Activate Fullscreen edit mode + Deactivate Fullscreen edit mode - Deactivate Fullscreen edit mode + Deactivate Fullscreen edit mode + Show preview - Show preview + Show preview + General - ជាទូទៅ + ជាទូទៅ + Structure - រចនាសម្ព័ន្ធ + រចនាសម្ព័ន្ធ + Plugins - ឧបករណ៍ + ឧបករណ៍ + Click {0} to continue to the page. - ចុចទីនេះដើម្បីបន្តទៅទំព័រ {0}។ + ចុចទីនេះដើម្បីបន្តទៅទំព័រ {0}។ + Click {0} to see the file. - ចុចទីនេះដើម្បីបន្តទៅឯកសារ {0}។ + ចុចទីនេះដើម្បីបន្តទៅឯកសារ {0}។ + Click {0} to open the link. - ចុចទីនេះដើម្បីបន្តទៅទំព័រមុន {0}។ + ចុចទីនេះដើម្បីបន្តទៅទំព័រមុន {0}។ + (no target has been selected) - (មិនទាន់បានជ្រើសរើសគោលដៅណាមួយទេ) + (មិនទាន់បានជ្រើសរើសគោលដៅណាមួយទេ) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - នេះគឺជាផ្លូវកាត់ទៅរកកូនទំព័រដំបូង។ <br /> សូមចុច {0} ដើម្បីបន្តទៅរកទំព័រនោះ។ + នេះគឺជាផ្លូវកាត់ទៅរកកូនទំព័រដំបូង។ <br /> សូមចុច {0} ដើម្បីបន្តទៅរកទំព័រនោះ។ + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - នេះគឺជាផ្លូវកាត់ទៅរកទំព័រមេ។ <br /> សូមចុច {0} ដើម្បីបន្តរទៅរកទំព័រនោះ។ + នេះគឺជាផ្លូវកាត់ទៅរកទំព័រមេ។ <br /> សូមចុច {0} ដើម្បីបន្តរទៅរកទំព័រនោះ។ + Full Screen - អេក្រង់ពេញ + អេក្រង់ពេញ + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - បើកពំព័រនៅក្នុងលំហរការងារផ្ទាល់ + បើកពំព័រនៅក្នុងលំហរការងារផ្ទាល់ + Open page in target workspace - បើកទំព័រក្នុងកន្លែការងាគោលដៅ + បើកទំព័រក្នុងកន្លែការងាគោលដៅ + Discard all - បេាះបង់ចោល + បេាះបង់ចោល + Discard all changes - បោះបង់ការផ្លាស់ប្តូរទាំងអស់ + បោះបង់ការផ្លាស់ប្តូរទាំងអស់ + Are you sure that you want to discard all changes in this workspace? - ត់អ្នកពិតជាចង់បោះបង់ការកែរទាំងអស់ក្នុងលំហរការងារនេះមែនទេ? + ត់អ្នកពិតជាចង់បោះបង់ការកែរទាំងអស់ក្នុងលំហរការងារនេះមែនទេ? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? + Publish all - ចុះផ្សាយទាំងអស់ + ចុះផ្សាយទាំងអស់ + Publish all changes - ផ្សាយរាល់ការផ្លាស់ប្តូរ + ផ្សាយរាល់ការផ្លាស់ប្តូរ + Are you sure that you want to publish all changes? - តើអ្នកពិតជាចង់ដាក់ផ្សាយការផ្លាស់ប្តូរទាំងអស់មែនឬទេ? + តើអ្នកពិតជាចង់ដាក់ផ្សាយការផ្លាស់ប្តូរទាំងអស់មែនឬទេ? + Pending changes - រង់ចាំផ្លាស់ប្តូរ + រង់ចាំផ្លាស់ប្តូរ + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - តំបន់ការរបស់អ្នកពេលនេះ មិនទាន់បានដាក់ផ្សាយ ការផ្លាស់ផ្ដូរទេ។ ដើម្បីធ្វើការផ្លាស់ផ្ដូរទៅកាន់តំបន់ការងារផ្សេង អ្នកត្រូវតែ ដាក់ផ្សាយ ឬ​ បេាះបង់ចោលការងារដែលបានផ្លាស់ផ្ដូរជាដំបូង + តំបន់ការរបស់អ្នកពេលនេះ មិនទាន់បានដាក់ផ្សាយ ការផ្លាស់ផ្ដូរទេ។ ដើម្បីធ្វើការផ្លាស់ផ្ដូរទៅកាន់តំបន់ការងារផ្សេង អ្នកត្រូវតែ ដាក់ផ្សាយ ឬ​ បេាះបង់ចោលការងារដែលបានផ្លាស់ផ្ដូរជាដំបូង + Please review your changes, publish or discard them, and then choose a new target workspace again. - សូមផ្ទៀងផ្ទាត់ការផ្លាស់ប្ដូររបស់អ្នក ដាក់ផ្សាយ ឬ បេាះបង់ ហើយបន្តាប់មកប្ដូរទៅកាន់តំបន់ការងារថ្មី​ម្ដងទៀត​ + សូមផ្ទៀងផ្ទាត់ការផ្លាស់ប្ដូររបស់អ្នក ដាក់ផ្សាយ ឬ បេាះបង់ ហើយបន្តាប់មកប្ដូរទៅកាន់តំបន់ការងារថ្មី​ម្ដងទៀត​ + Editing Modes - ពិធីការកែរ + ពិធីការកែរ + Preview Central - មណ្ឌលបុរេទសនា + មណ្ឌលបុរេទសនា + You still have changes. What do you want to do with them? - អ្នកនៅមានការផ្លាស់ប្តួរ។ តើអ្នកចង់ធ្វើអ្វីជាមួយពួកវា? + អ្នកនៅមានការផ្លាស់ប្តួរ។ តើអ្នកចង់ធ្វើអ្វីជាមួយពួកវា? + Selected element - រើសបានធាតុ + រើសបានធាតុ + There are fields that are not correctly filled in. - មានកន្លែងបំពេញ ដែលអ្នកបានបំពេញមិនត្រូវ។ + មានកន្លែងបំពេញ ដែលអ្នកបានបំពេញមិនត្រូវ។ + The fields marked with an error are not yet correctly filled in. Please complete them properly. - កន្លែងបំពេញនេះ បានចេញសញ្ញាដែលថាបំពេញមិនត្រឹមត្រូវមួយ។ សូមបំពេញវាអោយបានត្រឹមត្រូវ។ + កន្លែងបំពេញនេះ បានចេញសញ្ញាដែលថាបំពេញមិនត្រឹមត្រូវមួយ។ សូមបំពេញវាអោយបានត្រឹមត្រូវ។ + Continue editing - បន្តរកែរ + បន្តរកែរ + Throw away - បោះចោល + បោះចោល + Apply - អនុវត្ត + អនុវត្ត + Select a Plugin - ជ្រើសរើស កម្មវិធីជំនួយ + ជ្រើសរើស កម្មវិធីជំនួយ + No plugin configured - មិនមាន កម្មវិធីជំនួយបាន កំណត់ទម្រង់ + មិនមាន កម្មវិធីជំនួយបាន កំណត់ទម្រង់ + view is displayed on page - ទេសភាពបានបង្ហាញទៅទំព័រ + ទេសភាពបានបង្ហាញទៅទំព័រ + view is displayed on current page - ទេសភាពបានបង្ហាញទៅទំព័រនេះ + ទេសភាពបានបង្ហាញទៅទំព័រនេះ + No date set - គ្មានទិន្នន័យបានដាក់ + គ្មានទិន្នន័យបានដាក់ + Edit code - កែ​កូដ + កែ​កូដ + Paste a link, or type to search - បិទភ្ជាប់តំណភ្ជាប់ ឬក៍វាយបញ្ចូលដើម្បីស្វែងរក + បិទភ្ជាប់តំណភ្ជាប់ ឬក៍វាយបញ្ចូលដើម្បីស្វែងរក + Unable to load sub node types of: - មិនអាចផ្ទុក node types ថ្នាក់ក្រោមនៃ: + មិនអាចផ្ទុក node types ថ្នាក់ក្រោមនៃ: + Change type - ផ្លាស់ប្តូរប្រភេទ + ផ្លាស់ប្តូរប្រភេទ + Additional info - ព័ត៌មានបន្ថែម + ព័ត៌មានបន្ថែម + Visibility - -ដែលអាចមើលឃើញ + +ដែលអាចមើលឃើញ + Document options - ជម្រើសឯកសារ + ជម្រើសឯកសារ + The length of this text must be between {minimum} and {maximum} characters. - ប្រវែងនៃអត្ថបទនេះត្រូវតែនៅចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} តួអក្សរ។ + ប្រវែងនៃអត្ថបទនេះត្រូវតែនៅចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} តួអក្សរ។ + This field must contain at least {minimum} characters. - ជួរឈរនេះត្រូវតែមានយ៉ាងហោចណាស់ {{អប្បរមា}} តួអក្សរ។ + ជួរឈរនេះត្រូវតែមានយ៉ាងហោចណាស់ {{អប្បរមា}} តួអក្សរ។ + This text may not exceed {maximum} characters. - អត្ថបទនេះមិនអាចលើសពី {{អតិបរមា}} តួអក្សរ។ + អត្ថបទនេះមិនអាចលើសពី {{អតិបរមា}} តួអក្សរ។ + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - បានតែអក្សរឡាតាំង និងលេខតែប៉ុណ្ណោះ + បានតែអក្សរឡាតាំង និងលេខតែប៉ុណ្ណោះ + The given subject was not countable. - ប្រធានបទមិនត្រូវបានរាប់បញ្ជូល. + ប្រធានបទមិនត្រូវបានរាប់បញ្ជូល. + The count must be between {minimum} and {maximum}. - ការរាប់ចំនួនត្រូវតែនៅចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} ។ + ការរាប់ចំនួនត្រូវតែនៅចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} ។ + The given value was not a valid date. - តម្លៃដែលឲ្យមិនត្រឹមត្រូវថ្ងៃទេ + តម្លៃដែលឲ្យមិនត្រឹមត្រូវថ្ងៃទេ + The given date must be between {formatEarliestDate} and {formatLatestDate} - កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅចន្លោះ {{formatEarliestDate}} និង {{formatLatestDate}} + កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅចន្លោះ {{formatEarliestDate}} និង {{formatLatestDate}} + The given date must be after {formatEarliestDate} - កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅបន្ទាប់ពី {{formatEarliestDate}} + កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅបន្ទាប់ពី {{formatEarliestDate}} + The given date must be before {formatLatestDate} - កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅពីមុខ {{formatEarliestDate}} + កាលបរិច្ឆេទដែលបានផ្ដល់ឱ្យត្រូវតែនៅពីមុខ {{formatEarliestDate}} + Please specify a valid email address. - សូមបញ្ជាក់អាស័យដ្ឋានអ៊ីម៉ែលត្រឹមត្រូវមួយ។ + សូមបញ្ជាក់អាស័យដ្ឋានអ៊ីម៉ែលត្រឹមត្រូវមួយ។ + A valid float number is expected. - ត្រូវការជាចំនួនទសភាគ + ត្រូវការជាចំនួនទសភាគ + A valid integer number is expected. - ត្រូវការជាចំនួនលេខគត់ + ត្រូវការជាចំនួនលេខគត់ + Only letters, numbers, spaces and certain punctuation marks are expected. - ត្រឹមតែអក្សរ, លេខ, ចន្លោះនិងសញ្ញាវណ្ណយុត្តមួយចំនួនត្រូវបានគេរំពឹងទុក។ + ត្រឹមតែអក្សរ, លេខ, ចន្លោះនិងសញ្ញាវណ្ណយុត្តមួយចំនួនត្រូវបានគេរំពឹងទុក។ + This property is required. - អចលនទ្រព្យនេះត្រូវបានទាមទារ។ + អចលនទ្រព្យនេះត្រូវបានទាមទារ។ + A valid number is expected. - ត្រូវការជាចំនួនលេខ + ត្រូវការជាចំនួនលេខ + Please enter a valid number between {minimum} and {maximum} - សូមបញ្ចូលលេខដែលត្រឹមត្រូវរវាងចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} + សូមបញ្ចូលលេខដែលត្រឹមត្រូវរវាងចន្លោះ {{អប្បរមា}} និង {{អតិបរមា}} + The given subject did not match the pattern ({pattern}) - គាត់បានផ្តល់ឱ្យប្រធានបទនោះមិនជាផ្គូផ្គងលំនាំ ({{គំរូ}}) + គាត់បានផ្តល់ឱ្យប្រធានបទនោះមិនជាផ្គូផ្គងលំនាំ ({{គំរូ}}) + A valid string is expected. - អក្សរដែលត្រូវរំពឹងថានឹងមានសុពលភាព + អក្សរដែលត្រូវរំពឹងថានឹងមានសុពលភាព + Valid text without any XML tags is expected. - អត្ថបទដែលត្រឹមត្រូវដោយគ្មានស្លាក XML ណាមួយត្រូវបានរំពឹងទុក។ + អត្ថបទដែលត្រឹមត្រូវដោយគ្មានស្លាក XML ណាមួយត្រូវបានរំពឹងទុក។ + The given subject is not a valid UUID. - ការផ្ដល់ឲ្យនូវប្រធានបទគឺមិនមែនជាការ UUID ត្រឹមត្រូវ។ + ការផ្ដល់ឲ្យនូវប្រធានបទគឺមិនមែនជាការ UUID ត្រឹមត្រូវ។ + Toggle content dimensions selector - បិទបើកការជ្រើសវិមាត្រមាតិកា + បិទបើកការជ្រើសវិមាត្រមាតិកា + Start with an empty or pre-filled document? - ការចាប់ផ្តើមជាមួយនឹងឯកសារទទេឬមុនដែលពោរពេញទៅមួយ? + ការចាប់ផ្តើមជាមួយនឹងឯកសារទទេឬមុនដែលពោរពេញទៅមួយ? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - នេះ {nodeTypeLabel} មិនមាននៅឡើយទេនៅក្នុងជម្រើសទំហំ​​ ​​​{currentDimensionChoiceText} + នេះ {nodeTypeLabel} មិនមាននៅឡើយទេនៅក្នុងជម្រើសទំហំ​​ ​​​{currentDimensionChoiceText} + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - អ្នកអាចបង្កើតវាឥឡូវនេះបានចាប់ផ្តើមជាមួយនឹងការទទេទាំង {nodeTypeLabel} ឬចម្លងទាំងអស់ពេលមើលឃើញបច្ចុប្បន្ន {nodeTypeLabel}​ ក្នុង {currentDocumentDimensionChoiceText} + អ្នកអាចបង្កើតវាឥឡូវនេះបានចាប់ផ្តើមជាមួយនឹងការទទេទាំង {nodeTypeLabel} ឬចម្លងទាំងអស់ពេលមើលឃើញបច្ចុប្បន្ន {nodeTypeLabel}​ ក្នុង {currentDocumentDimensionChoiceText} + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - លើសពីនេះទៀតវាមាន {numberOfNodesMissingInRootline}​ ចំនួនឯកសារដែលសល់ចាស់ៗមិនមានការខុសប្លែកគ្នាទាំងនៅលើអ្នករើសតាំង នឹងត្រូវបានបង្កើតផងដែរ + លើសពីនេះទៀតវាមាន {numberOfNodesMissingInRootline}​ ចំនួនឯកសារដែលសល់ចាស់ៗមិនមានការខុសប្លែកគ្នាទាំងនៅលើអ្នករើសតាំង នឹងត្រូវបានបង្កើតផងដែរ + Create empty - បង្កើតទទេ + បង្កើតទទេ + Create and copy - បង្កើតនិងចម្លង + បង្កើតនិងចម្លង + Content - អត្ថបទ + អត្ថបទ + Toggle menu group - បិទបើកម៉ឺនុយ + បិទបើកម៉ឺនុយ + Toggle sticky menu mode - ម៉ឺនុយបិទបើកជាប់តាមរបៀប + ម៉ឺនុយបិទបើកជាប់តាមរបៀប + Do you really want to delete - តើអ្នកពិតជាចង់លុបមែនហ៎ + តើអ្នកពិតជាចង់លុបមែនហ៎ + This will delete the element - មួយនេះនឹងលុបធាតុចោល + មួយនេះនឹងលុបធាតុចោល + and it's children - និងកូនៗរបស់វា + និងកូនៗរបស់វា + This action can be undone in the workspace management. - នៅក្នុង ការគ្រប់គ្រងលំហរការងារ សកម្មភាពនេះមិនអាចថយក្រោយបានទេ។ + នៅក្នុង ការគ្រប់គ្រងលំហរការងារ សកម្មភាពនេះមិនអាចថយក្រោយបានទេ។ + Height - កម្ពស់ + កម្ពស់ + Do you really want to delete - តើអ្នកពិតជាចង់លុបមែនហ៎ + តើអ្នកពិតជាចង់លុបមែនហ៎ + this element - ធាតុនេះ + ធាតុនេះ + This will delete the element. - មួយនេះនឹងលុបធាតុចោល. + មួយនេះនឹងលុបធាតុចោល. + This action can be undone in the workspace management. - នៅក្នុង ការគ្រប់គ្រងលំហរការងារ សកម្មភាពនេះមិនអាចថយក្រោយបានទេ។ + នៅក្នុង ការគ្រប់គ្រងលំហរការងារ សកម្មភាពនេះមិនអាចថយក្រោយបានទេ។ + Media - ប្រព័ន្ធផ្សព្វផ្សាយ + ប្រព័ន្ធផ្សព្វផ្សាយ + Crop - កាត់ + កាត់ + Width - បណ្ដោយ + បណ្ដោយ + Missing required property: - បាត់លក្ខណៈសម្បត្តិដែលត្រូវការ + បាត់លក្ខណៈសម្បត្តិដែលត្រូវការ + Workspace - កន្លែងផ្ទុកការងារ + កន្លែងផ្ទុកការងារ + Workspaces - លំហរការងារ + លំហរការងារ + An error occurred during saving - មានបញ្ហារកើតឡើងនៅពេលរក្សាទុក + មានបញ្ហារកើតឡើងនៅពេលរក្សាទុក + Reload the page to attempt to fix the problem. - បើកទំព័រឡើងវិញដើម្បីព្យាយាម ជួសជុលបញ្ហារ + បើកទំព័រឡើងវិញដើម្បីព្យាយាម ជួសជុលបញ្ហារ + Reload the backend - បើកផ្នែកក្រោយឡើងវិញ + បើកផ្នែកក្រោយឡើងវិញ + Reload - បើកឡើង​វិញ + បើកឡើង​វិញ + In-Place - នៅក្នុងទីកន្លែង + នៅក្នុងទីកន្លែង + Raw Content - អត្ថបទជួរដេក + អត្ថបទជួរដេក + Raw Content Mode - របៀបមាតិកា + របៀបមាតិកា + Desktop - -ផ្ទៃតុ + +ផ្ទៃតុ + Login to - TYPO3 Neos ចុះឈ្មោះចូល + TYPO3 Neos ចុះឈ្មោះចូល + Authenticating - កំពង់ផ្តល់សិទ្ធ + កំពង់ផ្តល់សិទ្ធ + Logout - ចាកចេញ + ចាកចេញ + The entered username or password was wrong - ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់បានបញ្ចូលគឺខុស + ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់បានបញ្ចូលគឺខុស + Your login has expired. Please log in again. - ការចូលរបស់អ្នកបានផុតកំណត់សូមចូលម្តងទៀត + ការចូលរបស់អ្នកបានផុតកំណត់សូមចូលម្តងទៀត + Welcome to Neos - Welcome to Neos + Welcome to Neos + Go to setup - ទៅតំឡើង + ទៅតំឡើង + Technical Information - Technical Information + Technical Information + Missing Homepage - បាត់ទំព័រដើម + បាត់ទំព័រដើម + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - គ្មានគេហទំព័រណាបានបង្កើតទេ គេហទំព័រអត់មានទំព័រដើម ឬ អត់បានប្តេជ្ញា។ + គ្មានគេហទំព័រណាបានបង្កើតទេ គេហទំព័រអត់មានទំព័រដើម ឬ អត់បានប្តេជ្ញា។ + You might want to set the site's domain or import a new site in the setup. - អ្នកប្រហែលជាចង់ ដាក់ដូមេន ឬ ទាញយកចូលគេហទំព័រថ្មី នៅក្នុងការតំឡើងនេះ។ + អ្នកប្រហែលជាចង់ ដាក់ដូមេន ឬ ទាញយកចូលគេហទំព័រថ្មី នៅក្នុងការតំឡើងនេះ។ + Database Error - ដាតាបេស មានបញ្ហារ + ដាតាបេស មានបញ្ហារ + There is no database connection yet or the Neos database schema has not been created. - There is no database connection yet or the Neos database schema has not been created. + There is no database connection yet or the Neos database schema has not been created. + Run the setup to configure your database. - Run the setup to configure your database. + Run the setup to configure your database. + Page Not Found - បាត់ទំព័រ + បាត់ទំព័រ + Sorry, the page you requested was not found. - សុំទោស ទំព័រអ្នកស្នើរ រកមិនឃើញទេ។ + សុំទោស ទំព័រអ្នកស្នើរ រកមិនឃើញទេ។ + Invalid NodeType - NodeType មិនត្រឹមត្រូវ + NodeType មិនត្រឹមត្រូវ + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - ការកំណត់រចនាសម្ព័ន្ធត្រូវបានសន្មត់ថា NodeType ត្រូវបានបង្ហាញនៅទីនេះមិនអាចរកបាន។ ប្រហែលជាអ្នកបានប្ដូរឈ្មោះ NodeType និងត្រូវបានខកខាន migration ឬអ្នកសរសេរមិនបានត្រឹមត្រូវ។ + ការកំណត់រចនាសម្ព័ន្ធត្រូវបានសន្មត់ថា NodeType ត្រូវបានបង្ហាញនៅទីនេះមិនអាចរកបាន។ ប្រហែលជាអ្នកបានប្ដូរឈ្មោះ NodeType និងត្រូវបានខកខាន migration ឬអ្នកសរសេរមិនបានត្រឹមត្រូវ។ + Unexpected error while creating node - កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការបង្កើតអក្សរ + កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការបង្កើតអក្សរ + Unexpected error while deleting node - កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការលុបអក្សរ + កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការលុបអក្សរ + Unexpected error while updating node - កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការបង្កើតអក្សរជាថ្មី + កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការបង្កើតអក្សរជាថ្មី + Unexpected error while moving node - កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការផ្លាស់ប្ដូរអក្សរ + កំហុសដែលមិនរំពឹងទុកខណៈពេលដែលការផ្លាស់ប្ដូរអក្សរ + Node Tree loading error. - កំហុសអក្សរពេលកំពុងលេាត + កំហុសអក្សរពេលកំពុងលេាត + - - The entered username or password was wrong - ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់បានបញ្ចូលគឺខុស "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" នៅលើទំព័រ "{pageLabel}" + "{nodeTypeName}" នៅលើទំព័រ "{pageLabel}" + Nodes - អក្សរ + អក្សរ + Show - បង្ហាញ + បង្ហាញ + This node cannot be accessed through a public URL - អក្សរនេះមិនអាចត្រូវបានចូលដំណើរការបានតាមរយៈ URL ដែលជាសាធារណៈ + អក្សរនេះមិនអាចត្រូវបានចូលដំណើរការបានតាមរយៈ URL ដែលជាសាធារណៈ + Node Properties - លក្ខណរបស់អក្សរ + លក្ខណរបស់អក្សរ + Copy {source} to {target} - Copy {source} to {target} + Copy {source} to {target} + Move {source} to {target} - Move {source} to {target} + Move {source} to {target} + Please select the position at which you want {source} inserted relative to {target}. - Please select the position at which you want {source} inserted relative to {target}. + Please select the position at which you want {source} inserted relative to {target}. + Insert - Insert + Insert + Insert mode - Insert mode + Insert mode + Choose an Aspect Ratio - Choose an Aspect Ratio + Choose an Aspect Ratio + Bold - Bold + Bold + Italic - Italic + Italic + Underline - Underline + Underline + Subscript - Subscript + Subscript + Superscript - Superscript + Superscript + Strikethrough - Strikethrough + Strikethrough + Link - តំណភ្ជាប់ + តំណភ្ជាប់ + Ordered list - Ordered list + Ordered list + Unordered list - Unordered list + Unordered list + Align left - Align left + Align left + Align right - Align right + Align right + Align center - Align center + Align center + Align justify - Align justify + Align justify + Table - Table + Table + Remove format - Remove format + Remove format + Outdent - Outdent + Outdent + Indent - Indent + Indent + Create new - បង្កើតថ្មី + បង្កើតថ្មី + No matches found - No matches found + No matches found + Please enter ###CHARACTERS### more character - Please enter ###CHARACTERS### more character + Please enter ###CHARACTERS### more character + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់បានបញ្ចូលគឺខុស + ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់បានបញ្ចូលគឺខុស + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/km/Modules.xlf b/Neos.Neos/Resources/Private/Translations/km/Modules.xlf index 9720515c350..067bd8763ab 100644 --- a/Neos.Neos/Resources/Private/Translations/km/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/km/Modules.xlf @@ -258,70 +258,6 @@ All changes from workspace "{0}" have been discarded. ការផ្លាស់ប្តូរទាំងអស់ពីតំបន់ធ្វើការ "{0}" ត្រូវបានបោះបង់។ - - History - ប្រវត្តិ - - - This module provides an overview of all relevant events affecting this Neos installation. - ម៉ូឌុលមួយនេះ ផ្តល់នូវទិដ្ឋភាពទូទៅនៃព្រឹត្តិការណ៍ពាក់ព័ន្ធទាំងអស់ប៉ះពាល់ពីការដំឡើង Neos។ - - - Here's what happened recently in Neos - នេះ​គឺ​ជា​អ្វី​ដែល​កើត​ឡើង​ថ្មីៗ​អំពី​ Neos - - - There have not been recorded any events yet which could be displayed in this history. - មិនត្រូវបានកត់ត្រាព្រឹត្តិការណ៍​​​​​​​ដែលអាចត្រូវបានបង្ហាញនៅក្នុងប្រវត្តិសាស្រ្តនេះនៅឡើយទេ។ - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} បាន​បង្កើត​អ្នក​ប្រើ​ប្រាស់​ថ្មី "{1}" ដើម្បី {2}។ - - - {0} deleted the account "{1}" of {2}. - {0} បាន​លុប​គណនី "{1}" នៃ {2}។ - - - Load More - ទាញយកបន្ថែមទៀត - - - This node has been removed in the meantime - ថ្នាំងនេះត្រូវបានយកចេញនៅក្នុងពេលតំណាលគ្នានេះ - Administration diff --git a/Neos.Neos/Resources/Private/Translations/lv/Main.xlf b/Neos.Neos/Resources/Private/Translations/lv/Main.xlf index 03867c9254d..8cf2c4f6c64 100644 --- a/Neos.Neos/Resources/Private/Translations/lv/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/lv/Main.xlf @@ -951,10 +951,6 @@ Mezglu struktūras ielādes kļūda. - - The entered username or password was wrong - Ievadītais lietotājvārds vai parole ir nepareiza - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/lv/Modules.xlf b/Neos.Neos/Resources/Private/Translations/lv/Modules.xlf index 45ca75c3b56..158f9996f23 100644 --- a/Neos.Neos/Resources/Private/Translations/lv/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/lv/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Visas izmaiņas no darba virsmas "{0}" ir atceltas. - - History - Vēsture - - - This module provides an overview of all relevant events affecting this Neos installation. - Šis modulis sniedz apskatu par visām darbībām, kas ietekmē šo Neos instalāciju. - - - Here's what happened recently in Neos - Lūk, kas nesen notika Neos - - - There have not been recorded any events yet which could be displayed in this history. - Nav reģistrētu notikumu, ko varētu parādīt šajā vēsturē. - - - {0} created the {1} "{2}". - {0} izveidoja {1} {2}. - - - {0} removed the {1} "{2}". - {0} izdzēsa {1} {2}. - - - {0} created the variant {1} of the {2} "{3}". - {0} izveidoja versiju {1} no {2} {3}. - - - {0} modified the {1} "{2}". - {0} modificēja {1} "{2}". - - - {0} moved the {1} "{2}". - {0} pārvietoja {1} {2}. - - - {0} copied the {1} "{2}". - {0} nokopēja {1} {2}. - - - {0} renamed the {1} "{2}" to "{3}". - {0} pārdēvēja {1} "{2}" uz "{3}". - - - {0} modified content on the {1} "{2}". - {0} izmainīja saturu {1} {2}. - - - {0} created a new user "{1}" for {2}. - {0} izveidoja jaunu lietotāju "{1}" {2}. - - - {0} deleted the account "{1}" of {2}. - {0} izdzēsa kontu "{1}" {2}. - - - Load More - Ielādēt vairāk - - - This node has been removed in the meantime - Šis mezgls šobrīd tiek izņemts - Administration diff --git a/Neos.Neos/Resources/Private/Translations/nl/Main.xlf b/Neos.Neos/Resources/Private/Translations/nl/Main.xlf index 145dcd5d717..b256ae2ccb4 100644 --- a/Neos.Neos/Resources/Private/Translations/nl/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/nl/Main.xlf @@ -951,10 +951,6 @@ Node boomstructuur laad fout. - - The entered username or password was wrong - De gebruikersnaam of het wachtwoord is onjuist - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/nl/Modules.xlf b/Neos.Neos/Resources/Private/Translations/nl/Modules.xlf index 6b1e54d89d4..6dca8302eda 100644 --- a/Neos.Neos/Resources/Private/Translations/nl/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/nl/Modules.xlf @@ -259,70 +259,6 @@ All changes from workspace "{0}" have been discarded. Alle wijzigingen van workspace "{0}" zijn ongedaan gemaakt. - - History - Geschiedenis - - - This module provides an overview of all relevant events affecting this Neos installation. - Deze module biedt een overzicht van alle relevante gebeurtenissen op het gebied van deze Neos-installatie. - - - Here's what happened recently in Neos - Hier is wat er onlangs is gebeurd in Neos - - - There have not been recorded any events yet which could be displayed in this history. - Er zijn nog geen gebeurtenissen die kunnen worden weergegeven in deze geschiedenis. - - - {0} created the {1} "{2}". - {0} heeft de {1} "{2} " gemaakt. - - - {0} removed the {1} "{2}". - {0} verwijderde de {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} heeft de variant {1} van de {2} "{3} " gemaakt. - - - {0} modified the {1} "{2}". - {0} wijzigde de {1} "{2}". - - - {0} moved the {1} "{2}". - {0} verplaatste de {1} "{2}". - - - {0} copied the {1} "{2}". - {0} kopieerde de {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} heeft de naam {1} "{2}" gewijzigd naar "{3}". - - - {0} modified content on the {1} "{2}". - {0} heeft de inhoud van de {1} "{2} " gewijzigd. - - - {0} created a new user "{1}" for {2}. - {0} heeft een nieuwe gebruiker "{1}" gemaakt voor {2}. - - - {0} deleted the account "{1}" of {2}. - {0} heeft het account "{1}" verwijderd van {2}. - - - Load More - Meer laden - - - This node has been removed in the meantime - Intussen werd deze node verwijders - Administration diff --git a/Neos.Neos/Resources/Private/Translations/no/Main.xlf b/Neos.Neos/Resources/Private/Translations/no/Main.xlf index 0b29a351e4a..795c765afae 100644 --- a/Neos.Neos/Resources/Private/Translations/no/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/no/Main.xlf @@ -951,10 +951,6 @@ Feil under lasting av nodetre - - The entered username or password was wrong - Det inntastede brukernavnet eller passordet er feil - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/no/Modules.xlf b/Neos.Neos/Resources/Private/Translations/no/Modules.xlf index 09eef96229b..82cbb61d3e6 100644 --- a/Neos.Neos/Resources/Private/Translations/no/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/no/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Alle endringer fra arbeidsområdet "{0}" er forkastet. - - History - Historikk - - - This module provides an overview of all relevant events affecting this Neos installation. - Denne modulen gir en oversikt over alle relevante hendelser som påvirker Neos-installasjonen. - - - Here's what happened recently in Neos - Her er det som nylig skjedde i Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Det er ikke ennå registrert noen hendelser som kan vises i denne historikken. - - - {0} created the {1} "{2}". - {0} opprettet {1} "{2}". - - - {0} removed the {1} "{2}". - {0} fjernet {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} opprettet variant {1} av {2} "{3}". - - - {0} modified the {1} "{2}". - {0} endret {1} "{2}". - - - {0} moved the {1} "{2}". - {0} flyttet {1} "{2}". - - - {0} copied the {1} "{2}". - {0} kopierte {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} opprettet en ny bruker "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} slettet kontoen "{1}" av {2}. - - - Load More - Last inn mer - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/pl/Main.xlf b/Neos.Neos/Resources/Private/Translations/pl/Main.xlf index a79537fd656..a4fe15cd508 100644 --- a/Neos.Neos/Resources/Private/Translations/pl/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/pl/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Auto-publikacja + Auto-publikacja + Auto-Publish to {0} - Automatyczna publikacja do {0} + Automatyczna publikacja do {0} + Review changes - Przejrzyj zmiany + Przejrzyj zmiany + Apply - Zastosuj + Zastosuj + Apply changes - Zastosuj zmiany + Zastosuj zmiany + Cancel - Anuluj + Anuluj + Back - Wstecz + Wstecz + Choose - Wybierz + Wybierz + Type to search - Pisz, aby szukać + Pisz, aby szukać + Content - Treść + Treść + Node - Węzeł + Węzeł + Content View - Widok treści + Widok treści + Create after - Utwórz po + Utwórz po + Create new - Utwórz nowy + Utwórz nowy + Close - Zamknij + Zamknij + Copy - Kopiuj + Kopiuj + Cut - Wytnij + Wytnij + Delete - Usuń + Usuń + Yes, delete the element - Tak, usuń element + Tak, usuń element + Delete the element - Usuń element + Usuń element + Discard - Odrzuć + Odrzuć + Discard changes - Odrzuć zmiany + Odrzuć zmiany + Edit title - Edytuj tytuł + Edytuj tytuł + Edit / Preview - Edycja / Podgląd + Edycja / Podgląd + Edit - Edytuj + Edytuj + Hide / Unhide - Ukryj / Pokaż + Ukryj / Pokaż + Hide - Ukryj + Ukryj + Unhide - Odkryj + Odkryj + into - do + do + before - przed + przed + after - po + po + Loading - Ładowanie + Ładowanie + New After - Nowy po + Nowy po + New Before - Nowy przed + Nowy przed + New Into - Nowy w + Nowy w + Navigate - Nawiguj + Nawiguj + OK - OK + OK + Page - Strona + Strona + Paste - Wklej + Wklej + Paste After - Wklej po + Wklej po + Paste Before - Wklej przed + Wklej przed + Paste Into - Wklej do + Wklej do + Password - Hasło + Hasło + Preview - Pogdląd + Pogdląd + Publish - Publikuj + Publikuj + Publish to {0} - Publikuj do {0} + Publikuj do {0} + Publish all changes for current page - Publikuj wszystkie zmiany dla bieżącej strony + Publikuj wszystkie zmiany dla bieżącej strony + Can't publish because the target workspace is read-only - Nie można opublikować, ponieważ docelowy obszar roboczy jest tylko do odczytu + Nie można opublikować, ponieważ docelowy obszar roboczy jest tylko do odczytu + Select target workspace - Wybierz docelowy obszar roboczy + Wybierz docelowy obszar roboczy + Publishing - Publikowanie + Publikowanie + Published - Opublikowano + Opublikowano + Toggle publish menu - Przełącz menu publikacji + Przełącz menu publikacji + Target workspace - Docelowy obszar roboczy + Docelowy obszar roboczy + Current workspace - Bieżący obszar roboczy + Bieżący obszar roboczy + Remove - Usuń + Usuń + Refresh - Odśwież + Odśwież + Save - Zapisz + Zapisz + Saving - Zapisywanie... + Zapisywanie... + Saved - Zapisano + Zapisano + Search - Szukaj + Szukaj + Toggle inspector - Pokaż/schowaj inspektor + Pokaż/schowaj inspektor + Username - Użytkownik + Użytkownik + You - Ty + Ty + [no title] - [bez tytułu] + [bez tytułu] + Label - Etykieta + Etykieta + Content Type - Typ zawartości + Typ zawartości + Path - Ścieżka + Ścieżka + Relative Path - Ścieżka względna + Ścieżka względna + Version - Wersja + Wersja + This operation cannot be undone. - Tej operacji nie można cofnąć. + Tej operacji nie można cofnąć. + Asset - Zasób + Zasób + Created - Utworzony + Utworzony + Last modification - Ostatnia modyfikacja + Ostatnia modyfikacja + Last publication - Ostatnia publikacja + Ostatnia publikacja + Identifier - Identyfikator + Identyfikator + Name - Nazwa + Nazwa + Workspace - Obszar roboczy + Obszar roboczy + Structure - Struktura + Struktura + Toggle context structure - Przełącz strukturę kontekstu + Przełącz strukturę kontekstu + Filter - Filtr + Filtr + Toggle menu - Przełącz menu + Przełącz menu + Load error! - Błąd ładowania! + Błąd ładowania! + You have to select a node - Musisz wybrać węzeł + Musisz wybrać węzeł + The Root node cannot be deleted. - Węzeł nadrzędny nie może być usunięty. + Węzeł nadrzędny nie może być usunięty. + You cannot copy this node - Nie można skopiować tego węzła + Nie można skopiować tego węzła + You cannot cut this node - Nie można wyciąć tego węzła + Nie można wyciąć tego węzła + Content Dimensions - Wymiary zawartości + Wymiary zawartości + Site - Strona + Strona + Document - Dokument + Dokument + Reference - Odniesienie + Odniesienie + Host - Host + Host + Scheme - Schemat + Schemat + Port - Port + Port + Primary - Główny + Główny + Package - Pakiet + Pakiet + Deactivated - Nieaktywny + Nieaktywny + Unavailable - Niedostępny + Niedostępny + Inactive - Nieaktywny + Nieaktywny + Click to edit - Kliknij, aby edytować + Kliknij, aby edytować + Click to deactivate - Kliknij, aby deaktywować + Kliknij, aby deaktywować + Click to activate - Kliknij, aby aktywować + Kliknij, aby aktywować + Click to delete - Kliknij, aby usunąć + Kliknij, aby usunąć + Click to create new - Kliknij, aby utworzyć nowy + Kliknij, aby utworzyć nowy + Status - Status + Status + Active - Aktywny + Aktywny + Domains - Domeny + Domeny + Domain - Domena + Domena + Yes, delete it! - Tak, usuń! + Tak, usuń! + Package Key - Klucz pakietu + Klucz pakietu + Description - Opis + Opis + Toggle content tree - Przełącz drzewo zawartości + Przełącz drzewo zawartości + Show publish options - Pokaż opcje publikowania + Pokaż opcje publikowania + Activate Fullscreen edit mode - Aktywuj edycję w trybie pełnoekranowym + Aktywuj edycję w trybie pełnoekranowym + Deactivate Fullscreen edit mode - Dezaktywuj edycję w trybie pełnoekranowym + Dezaktywuj edycję w trybie pełnoekranowym + Show preview - Pokaż podgląd + Pokaż podgląd + General - Ogólny + Ogólny + Structure - Struktura + Struktura + Plugins - Wtyczki + Wtyczki + Click {0} to continue to the page. - Kliknij {0}, aby przejść do strony. + Kliknij {0}, aby przejść do strony. + Click {0} to see the file. - Kliknij {0} aby zobaczyć plik. + Kliknij {0} aby zobaczyć plik. + Click {0} to open the link. - Kliknij {0}, aby otworzyć odnośnik. + Kliknij {0}, aby otworzyć odnośnik. + (no target has been selected) - (cel nie został wybrany) + (cel nie został wybrany) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - To jest skrót do pierwszej podstrony. <br />Kliknij {0}, aby do niej przejść. + To jest skrót do pierwszej podstrony. <br />Kliknij {0}, aby do niej przejść. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - To jest skrót do strony nadrzędnej. <br />Kliknij {0}, aby przejść do strony. + To jest skrót do strony nadrzędnej. <br />Kliknij {0}, aby przejść do strony. + Full Screen - Pełny ekran + Pełny ekran + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Otwórz stronę w przestrzeni roboczej live + Otwórz stronę w przestrzeni roboczej live + Open page in target workspace - Otwórz stronę w docelowej przestrzeni roboczej + Otwórz stronę w docelowej przestrzeni roboczej + Discard all - Odrzuć wszystko + Odrzuć wszystko + Discard all changes - Odrzuć wszystkie zmiany + Odrzuć wszystkie zmiany + Are you sure that you want to discard all changes in this workspace? - Czy na pewno chcesz odrzucić wszystkie zmiany w tym obszarze roboczym? + Czy na pewno chcesz odrzucić wszystkie zmiany w tym obszarze roboczym? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Czy jesteś pewien, że chcesz odrzucić {numberOfChanges} zmianę(y) w tym obszarze roboczym? + Czy jesteś pewien, że chcesz odrzucić {numberOfChanges} zmianę(y) w tym obszarze roboczym? + Publish all - Publikuj wszystko + Publikuj wszystko + Publish all changes - Publikuj wszystkie zmiany + Publikuj wszystkie zmiany + Are you sure that you want to publish all changes? - Czy jesteś pewien, że chcesz opublikować wszystkie zmiany? + Czy jesteś pewien, że chcesz opublikować wszystkie zmiany? + Pending changes - Oczekujące zmiany + Oczekujące zmiany + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Twoja osobista przestrzeń robocza zawiera obecnie nieopublikowane zmiany. W celu przełączenia się na inny obszar roboczy musisz opublikować wprowadzone zmiany lub je odrzucić. + Twoja osobista przestrzeń robocza zawiera obecnie nieopublikowane zmiany. W celu przełączenia się na inny obszar roboczy musisz opublikować wprowadzone zmiany lub je odrzucić. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Przejrzyj swoje zmiany, opublikuj je lub odrzuć, a następnie wybierz nową docelową przestrzeń roboczą. + Przejrzyj swoje zmiany, opublikuj je lub odrzuć, a następnie wybierz nową docelową przestrzeń roboczą. + Editing Modes - Tryby edycji + Tryby edycji + Preview Central - Centrum podglądu + Centrum podglądu + You still have changes. What do you want to do with them? - Masz niezachowane zmiany. Co chcesz z nimi zrobić? + Masz niezachowane zmiany. Co chcesz z nimi zrobić? + Selected element - Wybrany element + Wybrany element + There are fields that are not correctly filled in. - Niektóre pola nie zostały poprawnie wypełnione. + Niektóre pola nie zostały poprawnie wypełnione. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Pola oznaczone jako błędne nie są jeszcze prawidłowo wypełnione. Uzupełnij je poprawnie. + Pola oznaczone jako błędne nie są jeszcze prawidłowo wypełnione. Uzupełnij je poprawnie. + Continue editing - Kontynuuj edycję + Kontynuuj edycję + Throw away - Porzuć zmiany + Porzuć zmiany + Apply - Zastosuj + Zastosuj + Select a Plugin - Wybierz wtyczkę + Wybierz wtyczkę + No plugin configured - Brak skonfigurowanych wtyczek + Brak skonfigurowanych wtyczek + view is displayed on page - Widok jest wyświetlany na stronie + Widok jest wyświetlany na stronie + view is displayed on current page - Widok jest wyświetlany na bieżącej stronie + Widok jest wyświetlany na bieżącej stronie + No date set - Nie wybrano daty + Nie wybrano daty + Edit code - Edytuj kod + Edytuj kod + Paste a link, or type to search - Wklej link, lub pisz aby wyszukać + Wklej link, lub pisz aby wyszukać + Unable to load sub node types of: - Niemożna załadować pod-wezłów dla typów: + Niemożna załadować pod-wezłów dla typów: + Change type - Zmień typ + Zmień typ + Additional info - Dodatkowe Informacje + Dodatkowe Informacje + Visibility - Widoczność + Widoczność + Document options - Opcje dokumentu + Opcje dokumentu + The length of this text must be between {minimum} and {maximum} characters. - Długość tego tekstu musi zawierać się między {minimum} i {maximum} znakami. + Długość tego tekstu musi zawierać się między {minimum} i {maximum} znakami. + This field must contain at least {minimum} characters. - To pole musi zawierać co najmniej {{minimum}} znaków. + To pole musi zawierać co najmniej {{minimum}} znaków. + This text may not exceed {maximum} characters. - Tekst nie może przekraczać {{maximum}} znaków. + Tekst nie może przekraczać {{maximum}} znaków. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Dozwolone są tylko znaki od a do z i cyfry + Dozwolone są tylko znaki od a do z i cyfry + The given subject was not countable. - Podany element nie jest policzalny. + Podany element nie jest policzalny. + The count must be between {minimum} and {maximum}. - Wartość licznika musi zawierać się pomiędzy {{minimum}} a {{maximum}}. + Wartość licznika musi zawierać się pomiędzy {{minimum}} a {{maximum}}. + The given value was not a valid date. - Podana wartość nie jest poprawną datą. + Podana wartość nie jest poprawną datą. + The given date must be between {formatEarliestDate} and {formatLatestDate} - Podana data musi zawierać się między {{formatEarliestDate}} i {{formatLatestDate}} + Podana data musi zawierać się między {{formatEarliestDate}} i {{formatLatestDate}} + The given date must be after {formatEarliestDate} - Podana data musi być po {{formatEarliestDate}} + Podana data musi być po {{formatEarliestDate}} + The given date must be before {formatLatestDate} - Podana data musi być przed {{formatLatestDate}} + Podana data musi być przed {{formatLatestDate}} + Please specify a valid email address. - Proszę podać poprawny adres email. + Proszę podać poprawny adres email. + A valid float number is expected. - Oczekiwana jest poprawna liczba zmiennoprzecinkowa. + Oczekiwana jest poprawna liczba zmiennoprzecinkowa. + A valid integer number is expected. - Oczekiwana jest poprawna liczba całkowita. + Oczekiwana jest poprawna liczba całkowita. + Only letters, numbers, spaces and certain punctuation marks are expected. - Oczekiwane są tylko litery, cyfry, spacje i wybrane znaki interpunkcyjne. + Oczekiwane są tylko litery, cyfry, spacje i wybrane znaki interpunkcyjne. + This property is required. - Ta właściwość jest wymagana. + Ta właściwość jest wymagana. + A valid number is expected. - Oczekiwana jest poprawna liczba. + Oczekiwana jest poprawna liczba. + Please enter a valid number between {minimum} and {maximum} - Proszę podać poprawną liczbę pomiędzy {{minimum}} a {{maximum}} + Proszę podać poprawną liczbę pomiędzy {{minimum}} a {{maximum}} + The given subject did not match the pattern ({pattern}) - Podany ciąg znaków nie odpowiada wzorcowi ({pattern}) + Podany ciąg znaków nie odpowiada wzorcowi ({pattern}) + A valid string is expected. - Oczekiwany jest poprawny ciąg znaków. + Oczekiwany jest poprawny ciąg znaków. + Valid text without any XML tags is expected. - Oczekiwany jest poprawny tekst bez żadnych znaczników XML. + Oczekiwany jest poprawny tekst bez żadnych znaczników XML. + The given subject is not a valid UUID. - Podana wartość posiada niepoprawny identyfikator. + Podana wartość posiada niepoprawny identyfikator. + Toggle content dimensions selector - Przełącz selektor wymiarów zawartości + Przełącz selektor wymiarów zawartości + Start with an empty or pre-filled document? - Rozpocząć z pustym czy wstępnie wypełnionym dokumentem? + Rozpocząć z pustym czy wstępnie wypełnionym dokumentem? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Ten {nodeTypeLabel} nie istnieje jeszcze w {currentDimensionChoiceText}. + Ten {nodeTypeLabel} nie istnieje jeszcze w {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Możesz utworzyć go teraz, rozpoczynając z pustym {nodeTypeLabel} lub skopiować całą zawartość z obecnie widocznego {nodeTypeLabel}, który znajduje się w {currentDocumentDimensionChoiceText}. + Możesz utworzyć go teraz, rozpoczynając z pustym {nodeTypeLabel} lub skopiować całą zawartość z obecnie widocznego {nodeTypeLabel}, który znajduje się w {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Dodatkowo, są {numberOfNodesMissingInRootline} dokumenty przodkowie, które również nie istnieją w wybranym wariancie i które także zostaną utworzone. + Dodatkowo, są {numberOfNodesMissingInRootline} dokumenty przodkowie, które również nie istnieją w wybranym wariancie i które także zostaną utworzone. + Create empty - Utwórz pusty + Utwórz pusty + Create and copy - Utwórz i kopiuj + Utwórz i kopiuj + Content - Treść + Treść + Toggle menu group - Przełącz grupę menu + Przełącz grupę menu + Toggle sticky menu mode - Przełącz tryb menu przyczepionego + Przełącz tryb menu przyczepionego + Do you really want to delete - Czy na pewno chcesz usunąć + Czy na pewno chcesz usunąć + This will delete the element - Spowoduje to usunięcie elementu + Spowoduje to usunięcie elementu + and it's children - wraz z jego dziećmi + wraz z jego dziećmi + This action can be undone in the workspace management. - Tę operację można cofnąć w panelu zarządzania obszarem roboczym. + Tę operację można cofnąć w panelu zarządzania obszarem roboczym. + Height - Wysokość + Wysokość + Do you really want to delete - Czy na pewno chcesz usunąć + Czy na pewno chcesz usunąć + this element - ten element + ten element + This will delete the element. - To spowoduje usunięcie elementu. + To spowoduje usunięcie elementu. + This action can be undone in the workspace management. - Tę operację można cofnąć w panelu zarządzania obszarem roboczym. + Tę operację można cofnąć w panelu zarządzania obszarem roboczym. + Media - Pliki + Pliki + Crop - Kadruj + Kadruj + Width - Szerokość + Szerokość + Missing required property: - Brak wymaganej właściwości: + Brak wymaganej właściwości: + Workspace - Obszar roboczy + Obszar roboczy + Workspaces - Obszary robocze + Obszary robocze + An error occurred during saving - Wystąpił błąd podczas zapisywania + Wystąpił błąd podczas zapisywania + Reload the page to attempt to fix the problem. - Przeładuj stronę aby spróbować rozwiązać ten problem. + Przeładuj stronę aby spróbować rozwiązać ten problem. + Reload the backend - Przeładuj backend + Przeładuj backend + Reload - Przeładuj + Przeładuj + In-Place - W miejscu + W miejscu + Raw Content - Sama treść + Sama treść + Raw Content Mode - Tryb treści nieprzetworzonej + Tryb treści nieprzetworzonej + Desktop - Komputer + Komputer + Login to - Logowanie do + Logowanie do + Authenticating - Uwierzytelnianie + Uwierzytelnianie + Logout - Wyloguj + Wyloguj + The entered username or password was wrong - Wprowadzona nazwa użytkownika lub hasło było nieprawidłowe + Wprowadzona nazwa użytkownika lub hasło było nieprawidłowe + Your login has expired. Please log in again. - Twoja sesja wygasła. Zaloguj się ponownie. + Twoja sesja wygasła. Zaloguj się ponownie. + Welcome to Neos - Welcome to Neos + Welcome to Neos + Go to setup - Przejdź do konfiguracji + Przejdź do konfiguracji + Technical Information - Technical Information + Technical Information + Missing Homepage - Brak strony głównej + Brak strony głównej + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Prawdopodobnie żadna strona nie została zdefiniowana, witryna nie zawiera strony głównej, bądź nie można określić aktywnej strony. + Prawdopodobnie żadna strona nie została zdefiniowana, witryna nie zawiera strony głównej, bądź nie można określić aktywnej strony. + You might want to set the site's domain or import a new site in the setup. - Powinieneś ustawić domenę strony lub zaimportować nową stronę w ustawieniach. + Powinieneś ustawić domenę strony lub zaimportować nową stronę w ustawieniach. + Database Error - Błąd bazy danych + Błąd bazy danych + There is no database connection yet or the Neos database schema has not been created. - Nie ma jeszcze połączenia z bazą danych lub nie został utworzony schemat bazy danych Neosa. + Nie ma jeszcze połączenia z bazą danych lub nie został utworzony schemat bazy danych Neosa. + Run the setup to configure your database. - Uruchom instalator, aby skonfigurować bazę danych. + Uruchom instalator, aby skonfigurować bazę danych. + Page Not Found - Nie znaleziono strony + Nie znaleziono strony + Sorry, the page you requested was not found. - Niestety, żądana strona nie została odnaleziona. + Niestety, żądana strona nie została odnaleziona. + Invalid NodeType - Niepoprawny węzeł + Niepoprawny węzeł + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - Konfiguracja węzła (NodeType), który miał być w tym miejscu wyświetlony nie jest dostępna. Prawdopodobnie zmieniłeś nazwę węzła i nie wykonałeś migracji lub po prostu zrobiłeś literówkę. + Konfiguracja węzła (NodeType), który miał być w tym miejscu wyświetlony nie jest dostępna. Prawdopodobnie zmieniłeś nazwę węzła i nie wykonałeś migracji lub po prostu zrobiłeś literówkę. + Unexpected error while creating node - Wystąpił nieoczekiwany błąd podczas tworzenia węzła + Wystąpił nieoczekiwany błąd podczas tworzenia węzła + Unexpected error while deleting node - Wystąpił nieoczekiwany błąd podczas usuwania węzła + Wystąpił nieoczekiwany błąd podczas usuwania węzła + Unexpected error while updating node - Wystąpił nieoczekiwany błąd podczas aktualizowania węzła + Wystąpił nieoczekiwany błąd podczas aktualizowania węzła + Unexpected error while moving node - Wystąpił nieoczekiwany błąd podczas przenoszenia węzła + Wystąpił nieoczekiwany błąd podczas przenoszenia węzła + Node Tree loading error. - Błąd ładowania drzewa węzłów. + Błąd ładowania drzewa węzłów. + - - The entered username or password was wrong - Wprowadzona nazwa użytkownika lub hasło było nieprawidłowe "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" na stronie "{pageLabel}" + "{nodeTypeName}" na stronie "{pageLabel}" + Nodes - Węzły + Węzły + Show - Pokaż + Pokaż + This node cannot be accessed through a public URL - Ten węzeł nie może być udostępniiony za pośrednictwem publicznego adresu URL + Ten węzeł nie może być udostępniiony za pośrednictwem publicznego adresu URL + Node Properties - Właściwości węzła + Właściwości węzła + Copy {source} to {target} - Skopiuj {source} do {target} + Skopiuj {source} do {target} + Move {source} to {target} - Przenieś {source} do {target} + Przenieś {source} do {target} + Please select the position at which you want {source} inserted relative to {target}. - Wybierz pozycję na jakiej chcesz wstawić {source} względem {target}. + Wybierz pozycję na jakiej chcesz wstawić {source} względem {target}. + Insert - Wstaw + Wstaw + Insert mode - Tryb wstawiania + Tryb wstawiania + Choose an Aspect Ratio - Wybierz współczynnik proporcji + Wybierz współczynnik proporcji + Bold - Pogrubienie + Pogrubienie + Italic - Kursywa + Kursywa + Underline - Podkreślenie + Podkreślenie + Subscript - Indeks dolny + Indeks dolny + Superscript - Indeks górny + Indeks górny + Strikethrough - Przekreślenie + Przekreślenie + Link - Odnośnik + Odnośnik + Ordered list - Lista uporządkowana + Lista uporządkowana + Unordered list - Lista nieuporządkowana + Lista nieuporządkowana + Align left - Wyrównaj do lewej + Wyrównaj do lewej + Align right - Wyrównaj do prawej + Wyrównaj do prawej + Align center - Wyrównaj do środka + Wyrównaj do środka + Align justify - Wyjustuj + Wyjustuj + Table - Tabela + Tabela + Remove format - Usuń formatowanie + Usuń formatowanie + Outdent - Zmniejsz wcięcie + Zmniejsz wcięcie + Indent - Wcięcie + Wcięcie + Create new - Utwórz nowy + Utwórz nowy + No matches found - Nie znaleziono dopasowań + Nie znaleziono dopasowań + Please enter ###CHARACTERS### more character - Wprowadź ###CHARACTERS### znaków więcej + Wprowadź ###CHARACTERS### znaków więcej + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - Wprowadzona nazwa użytkownika lub hasło było nieprawidłowe + Wprowadzona nazwa użytkownika lub hasło było nieprawidłowe + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/pl/Modules.xlf b/Neos.Neos/Resources/Private/Translations/pl/Modules.xlf index 60e33a6a719..21edd2516aa 100644 --- a/Neos.Neos/Resources/Private/Translations/pl/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/pl/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Wszystkie zmiany z obszaru roboczego "{0}" zostały odrzucone. - - History - Historia - - - This module provides an overview of all relevant events affecting this Neos installation. - Ten moduł zawiera przegląd wszystkich istotnych zdarzeń wpływających na działanie tej instalacji Neos. - - - Here's what happened recently in Neos - Oto co wydarzyło się ostatnio w Neos - - - There have not been recorded any events yet which could be displayed in this history. - Nie zarejestrowano żadnych zdarzeń, które mogłyby być wyświetlone w tej historii. - - - {0} created the {1} "{2}". - {0} utworzył {1} "{2}". - - - {0} removed the {1} "{2}". - {0} usunął {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} utworzył wariant {1} z {2} "{3}". - - - {0} modified the {1} "{2}". - {0} zmodyfikował {1} "{2}". - - - {0} moved the {1} "{2}". - {0} przeniósł {1} "{2}". - - - {0} copied the {1} "{2}". - {0} skopiował {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} zmienił nazwę {1} "{2}" na "{3}". - - - {0} modified content on the {1} "{2}". - {0} zmodyfikował zawartość na {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} utworzył nowego użytkownika "{1}" dla {2}. - - - {0} deleted the account "{1}" of {2}. - {0} usunął konto "{1}" z {2}. - - - Load More - Załaduj więcej - - - This node has been removed in the meantime - Ten węzeł został usunięty w międzyczasie - Administration diff --git a/Neos.Neos/Resources/Private/Translations/pt/Main.xlf b/Neos.Neos/Resources/Private/Translations/pt/Main.xlf index b535f8346a5..39fe986fb4e 100644 --- a/Neos.Neos/Resources/Private/Translations/pt/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/pt/Main.xlf @@ -952,10 +952,6 @@ Apenas caracteres regulares (a a z, tremas, ...) e números são permitidos.Erro ao carregar a árvore de nós. - - The entered username or password was wrong - O nome de utilizador ou a palavra-passe estão incorretos - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/pt/Modules.xlf b/Neos.Neos/Resources/Private/Translations/pt/Modules.xlf index 4f4f1bf2894..f7625c747e3 100644 --- a/Neos.Neos/Resources/Private/Translations/pt/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/pt/Modules.xlf @@ -259,70 +259,6 @@ All changes from workspace "{0}" have been discarded. Todas as alterações do espaço de trabalho "{0}" foram descartadas. - - History - Histórico - - - This module provides an overview of all relevant events affecting this Neos installation. - Este módulo fornece uma visão geral de todos os eventos relevantes que afetam esta instalação do Neos. - - - Here's what happened recently in Neos - Aqui está o que aconteceu recentemente no Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Não foram registrados quaisquer eventos que poderiam ser exibido neste histórico ainda. - - - {0} created the {1} "{2}". - {0} criou o {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removido o {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} criada a variante {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modificado o {1} "{2}". - - - {0} moved the {1} "{2}". - {0} movido o {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copiado o {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renomeado o {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modificado o conteúdo no {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} criou um novo usuário "{1}" para {2}. - - - {0} deleted the account "{1}" of {2}. - {0} excluiu a conta "{1}" de {2}. - - - Load More - Carregar mais - - - This node has been removed in the meantime - Este nó já foi removido - Administration diff --git a/Neos.Neos/Resources/Private/Translations/pt_BR/Main.xlf b/Neos.Neos/Resources/Private/Translations/pt_BR/Main.xlf index 1a0fae45b9f..08fcf1196cd 100644 --- a/Neos.Neos/Resources/Private/Translations/pt_BR/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/pt_BR/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Auto-publicar + Auto-publicar + Auto-Publish to {0} - Auto-publicar em {0} + Auto-publicar em {0} + Review changes - Revisar alterações + Revisar alterações + Apply - Aplicar + Aplicar + Apply changes - Aplicar alterações + Aplicar alterações + Cancel - Cancelar + Cancelar + Back - Voltar + Voltar + Choose - Escolher + Escolher + Type to search - Escreva pra procurar + Escreva pra procurar + Content - Conteúdo + Conteúdo + Node - + + Content View - Exibição de Conteúdo + Exibição de Conteúdo + Create after - Criar depois + Criar depois + Create new - Criar novo + Criar novo + Close - Fechar + Fechar + Copy - Copiar + Copiar + Cut - Recortar + Recortar + Delete - Excluir + Excluir + Yes, delete the element - Sim, excluir o elemento + Sim, excluir o elemento + Delete the element - Excluir o elemento + Excluir o elemento + Discard - Descartar + Descartar + Discard changes - Descartar alterações + Descartar alterações + Edit title - Editar título + Editar título + Edit / Preview - Editar / Visualizar + Editar / Visualizar + Edit - Editar + Editar + Hide / Unhide - Ocultar / Exibir + Ocultar / Exibir + Hide - Esconder + Esconder + Unhide - Exibir + Exibir + into - dentro + dentro + before - antes + antes + after - depois + depois + Loading - Carregando + Carregando + New After - Novo Depois + Novo Depois + New Before - Novo Antes + Novo Antes + New Into - Novo Em + Novo Em + Navigate - Navegar + Navegar + OK - ok + ok + Page - Página + Página + Paste - Colar + Colar + Paste After - Colar Depois + Colar Depois + Paste Before - Colar Antes + Colar Antes + Paste Into - Colar Em + Colar Em + Password - Senha + Senha + Preview - Visualizar + Visualizar + Publish - Publicar + Publicar + Publish to {0} - Publicar em {0} + Publicar em {0} + Publish all changes for current page - Publicar todas as alterações da página atual + Publicar todas as alterações da página atual + Can't publish because the target workspace is read-only - Não foi possível publicar porque o espaço de trabalho de destino tem acesso somente leitura + Não foi possível publicar porque o espaço de trabalho de destino tem acesso somente leitura + Select target workspace - Selecione o espaço de trabalho de destino + Selecione o espaço de trabalho de destino + Publishing - Publicando + Publicando + Published - Publicado + Publicado + Toggle publish menu - Abrir/Fechar menu de publicação + Abrir/Fechar menu de publicação + Target workspace - Espaço de trabalho de destino + Espaço de trabalho de destino + Current workspace - Espaço de trabalho atual + Espaço de trabalho atual + Remove - Remover + Remover + Refresh - Atualizar + Atualizar + Save - Salvar + Salvar + Saving - Salvando + Salvando + Saved - Salvo + Salvo + Search - Procura + Procura + Toggle inspector - Ativar/Desativar inspetor + Ativar/Desativar inspetor + Username - Nome de Usuário + Nome de Usuário + You - Você + Você + [no title] - [sem título] + [sem título] + Label - Rótulo + Rótulo + Content Type - Tipo de nó + Tipo de nó + Path - Caminho + Caminho + Relative Path - Caminho relativo + Caminho relativo + Version - Versão + Versão + This operation cannot be undone. - Esta operação não pode ser desfeita. + Esta operação não pode ser desfeita. + Asset - Ítem + Ítem + Created - Criado + Criado + Last modification - Última modificação + Última modificação + Last publication - Última publicação + Última publicação + Identifier - Identificador + Identificador + Name - Nome + Nome + Workspace - Espaço de Trabalho + Espaço de Trabalho + Structure - Estrutura + Estrutura + Toggle context structure - Abrir/Fechar estrutura do contexto + Abrir/Fechar estrutura do contexto + Filter - Filtro + Filtro + Toggle menu - Abrir/fechar o menu + Abrir/fechar o menu + Load error! - Erro ao carregar! + Erro ao carregar! + You have to select a node - Selecione um nó + Selecione um nó + The Root node cannot be deleted. - O nó raíz não pode ser removido. + O nó raíz não pode ser removido. + You cannot copy this node - Você não pode copiar este nó + Você não pode copiar este nó + You cannot cut this node - Você não pode cortar este nó + Você não pode cortar este nó + Content Dimensions - Dimensões de conteúdo + Dimensões de conteúdo + Site - Site + Site + Document - Documento + Documento + Reference - Referência + Referência + Host - Host + Host + Scheme - Esquema + Esquema + Port - Porta + Porta + Primary - Primário + Primário + Package - Pacote + Pacote + Deactivated - Desativado + Desativado + Unavailable - Indisponível + Indisponível + Inactive - Inativo + Inativo + Click to edit - Clique para editar + Clique para editar + Click to deactivate - Clique para desativar + Clique para desativar + Click to activate - Clique para ativar + Clique para ativar + Click to delete - Clique para apagar + Clique para apagar + Click to create new - Clique para criar um novo + Clique para criar um novo + Status - Status + Status + Active - Ativo + Ativo + Domains - Domínios + Domínios + Domain - Domínio + Domínio + Yes, delete it! - Sim, excluí-lo! + Sim, excluí-lo! + Package Key - Chave de pacote + Chave de pacote + Description - Descrição + Descrição + Toggle content tree - Alternar painel de conteúdo + Alternar painel de conteúdo + Show publish options - Mostrar opções de publicação + Mostrar opções de publicação + Activate Fullscreen edit mode - Ativar modo de edição de tela cheia + Ativar modo de edição de tela cheia + Deactivate Fullscreen edit mode - Desativar modo de edição de tela cheia + Desativar modo de edição de tela cheia + Show preview - Mostrar pré-visualização + Mostrar pré-visualização + General - Geral + Geral + Structure - Estrutura + Estrutura + Plugins - Plugins + Plugins + Click {0} to continue to the page. - Clique aqui para continuar para a página {0}. + Clique aqui para continuar para a página {0}. + Click {0} to see the file. - Clique aqui para continuar o recurso {0}. + Clique aqui para continuar o recurso {0}. + Click {0} to open the link. - Clique aqui para continuar para a página de ext {0}. + Clique aqui para continuar para a página de ext {0}. + (no target has been selected) - (nenhum alvo foi selecionado) + (nenhum alvo foi selecionado) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Isto é um atalho para a primeira página filha. <br />Clique em {0} para continuar para a página. + Isto é um atalho para a primeira página filha. <br />Clique em {0} para continuar para a página. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Este é um atalho para a página pai.<br />Clique em {0} para continuar para a página. + Este é um atalho para a página pai.<br />Clique em {0} para continuar para a página. + Full Screen - Tela Cheia + Tela Cheia + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Página aberta em espaço de trabalho ao vivo + Página aberta em espaço de trabalho ao vivo + Open page in target workspace - Abrir página em espaço de trabalho de destino + Abrir página em espaço de trabalho de destino + Discard all - Descartar todos + Descartar todos + Discard all changes - Descartar todas as alterações + Descartar todas as alterações + Are you sure that you want to discard all changes in this workspace? - Tem certeza que deseja descartar todas as alterações neste espaço de trabalho? + Tem certeza que deseja descartar todas as alterações neste espaço de trabalho? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Você tem certeza de que você deseja descartar {numberOfChanges} mudança(s) neste espaço de trabalho? + Você tem certeza de que você deseja descartar {numberOfChanges} mudança(s) neste espaço de trabalho? + Publish all - Publicar todos + Publicar todos + Publish all changes - Publicar todas as alterações + Publicar todas as alterações + Are you sure that you want to publish all changes? - Tem certeza que deseja publicar todas as alterações? + Tem certeza que deseja publicar todas as alterações? + Pending changes - Alterações pendentes + Alterações pendentes + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Seu espaço de trabalho pessoal atualmente contém alterações inéditas. Para alternar para uma área de destino diferente, você precisa publicar ou descartar as alterações pendentes primeiro. + Seu espaço de trabalho pessoal atualmente contém alterações inéditas. Para alternar para uma área de destino diferente, você precisa publicar ou descartar as alterações pendentes primeiro. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Por favor reveja suas alterações, publique ou descarte-as, e em seguida escolha um novo espaço de trabalho de destino. + Por favor reveja suas alterações, publique ou descarte-as, e em seguida escolha um novo espaço de trabalho de destino. + Editing Modes - Modos de Edição + Modos de Edição + Preview Central - Central de Visualização + Central de Visualização + You still have changes. What do you want to do with them? - Você ainda tem mudanças. O que quer fazer com eles? + Você ainda tem mudanças. O que quer fazer com eles? + Selected element - Elemento selecionado + Elemento selecionado + There are fields that are not correctly filled in. - Existem campos que não estão corretamente preenchidos. + Existem campos que não estão corretamente preenchidos. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Os campos marcados com um erro ainda não estão corretamente preenchidos. Por favor preencha-os corretamente. + Os campos marcados com um erro ainda não estão corretamente preenchidos. Por favor preencha-os corretamente. + Continue editing - Continuar editando + Continuar editando + Throw away - Jogar fora + Jogar fora + Apply - Aplicar + Aplicar + Select a Plugin - Selecione um plugin + Selecione um plugin + No plugin configured - Nenhum plugin configurado + Nenhum plugin configurado + view is displayed on page - modo de exibição é exibido na página + modo de exibição é exibido na página + view is displayed on current page - modo de exibição é exibido na página atual + modo de exibição é exibido na página atual + No date set - Sem data definida + Sem data definida + Edit code - Editar código + Editar código + Paste a link, or type to search - Cole um Link, ou digite pra procurar + Cole um Link, ou digite pra procurar + Unable to load sub node types of: - Não é possível carregar tipos de sub node: + Não é possível carregar tipos de sub node: + Change type - Mudar escrita + Mudar escrita + Additional info - Informação adicional + Informação adicional + Visibility - Visibilidade + Visibilidade + Document options - Opções do documento + Opções do documento + The length of this text must be between {minimum} and {maximum} characters. - O comprimento deste texto deve estar entre {{minimum}} e {{maximum}} caracteres. + O comprimento deste texto deve estar entre {{minimum}} e {{maximum}} caracteres. + This field must contain at least {minimum} characters. - Este campo deve conter pelo menos {{minimum}} caracteres. + Este campo deve conter pelo menos {{minimum}} caracteres. + This text may not exceed {maximum} characters. - Este texto não pode exceder {{maximum}} caracteres. + Este texto não pode exceder {{maximum}} caracteres. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Somente letras baixas (a a z , tremas, ... ) e números são permitidos. + Somente letras baixas (a a z , tremas, ... ) e números são permitidos. + The given subject was not countable. - O assunto fornecido não é contável. + O assunto fornecido não é contável. + The count must be between {minimum} and {maximum}. - A contagem deve estar entre {{minimum}} e {{maximum}}. + A contagem deve estar entre {{minimum}} e {{maximum}}. + The given value was not a valid date. - O valor fornecido não é uma data válida. + O valor fornecido não é uma data válida. + The given date must be between {formatEarliestDate} and {formatLatestDate} - A data deve estar entre {{formatEarliestDate}} e {{formatLatestDate}} + A data deve estar entre {{formatEarliestDate}} e {{formatLatestDate}} + The given date must be after {formatEarliestDate} - A data deve ser depois de {{formatEarliestDate}} + A data deve ser depois de {{formatEarliestDate}} + The given date must be before {formatLatestDate} - A data deve ser antes de {{formatLatestDate}} + A data deve ser antes de {{formatLatestDate}} + Please specify a valid email address. - Por favor, especifique um endereço de email válido. + Por favor, especifique um endereço de email válido. + A valid float number is expected. - É esperado um número flutuador válido. + É esperado um número flutuador válido. + A valid integer number is expected. - É esperado um número inteiro válido. + É esperado um número inteiro válido. + Only letters, numbers, spaces and certain punctuation marks are expected. - É esperado apenas letras, números, espaços e certas marcas de pontuação. + É esperado apenas letras, números, espaços e certas marcas de pontuação. + This property is required. - Esta propriedade é necessária. + Esta propriedade é necessária. + A valid number is expected. - É esperado um número válido. + É esperado um número válido. + Please enter a valid number between {minimum} and {maximum} - Por favor, digite um número válido entre {{minimum}} e {{maximum}} + Por favor, digite um número válido entre {{minimum}} e {{maximum}} + The given subject did not match the pattern ({pattern}) - O determinado assunto não corresponde ao padrão ({{pattern}}) + O determinado assunto não corresponde ao padrão ({{pattern}}) + A valid string is expected. - Espera-se caracteres válidos. + Espera-se caracteres válidos. + Valid text without any XML tags is expected. - Texto válido sem quaisquer tags XML é esperado. + Texto válido sem quaisquer tags XML é esperado. + The given subject is not a valid UUID. - O determinado assunto não é um válido UUID. + O determinado assunto não é um válido UUID. + Toggle content dimensions selector - Abrir/Fechar selecionador das dimensões de conteúdo + Abrir/Fechar selecionador das dimensões de conteúdo + Start with an empty or pre-filled document? - Começar com um documento vazio ou já preenchido? + Começar com um documento vazio ou já preenchido? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Este {nodeTypeLabel} ainda não existe no {currentDimensionChoiceText}. + Este {nodeTypeLabel} ainda não existe no {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Você pode criá-lo agora, começando com um {nodeTypeLabel} vazio ou copiar todo o conteúdo do {nodeTypeLabel} atualmente visível no {currentDocumentDimensionChoiceText}. + Você pode criá-lo agora, começando com um {nodeTypeLabel} vazio ou copiar todo o conteúdo do {nodeTypeLabel} atualmente visível no {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Além disso, há {numberOfNodesMissingInRootline} documentos ancestrais que também não existem na variante escolhida, e que serão igualmente criados. + Além disso, há {numberOfNodesMissingInRootline} documentos ancestrais que também não existem na variante escolhida, e que serão igualmente criados. + Create empty - Criar vazio + Criar vazio + Create and copy - Criar e copiar + Criar e copiar + Content - Conteúdo + Conteúdo + Toggle menu group - Abrir/Fechar grupo de menus + Abrir/Fechar grupo de menus + Toggle sticky menu mode - Ativar/Desativar modo de menú colado + Ativar/Desativar modo de menú colado + Do you really want to delete - Deseja realmente excluir + Deseja realmente excluir + This will delete the element - Isto irá excluir o elemento + Isto irá excluir o elemento + and it's children - e seus filhos + e seus filhos + This action can be undone in the workspace management. - Esta ação pode ser desfeita no gerenciamento do espaço de trabalho. + Esta ação pode ser desfeita no gerenciamento do espaço de trabalho. + Height - Altura + Altura + Do you really want to delete - Deseja realmente excluir + Deseja realmente excluir + this element - este elemento + este elemento + This will delete the element. - Isto irá excluir o elemento. + Isto irá excluir o elemento. + This action can be undone in the workspace management. - Esta ação pode ser desfeita no gerenciamento do espaço de trabalho. + Esta ação pode ser desfeita no gerenciamento do espaço de trabalho. + Media - Mídia + Mídia + Crop - Corte + Corte + Width - Largura + Largura + Missing required property: - Faltando propriedade necessária: + Faltando propriedade necessária: + Workspace - Espaço de Trabalho + Espaço de Trabalho + Workspaces - Espaços de Trabalho + Espaços de Trabalho + An error occurred during saving - Ocorreu um erro durante o salvamento + Ocorreu um erro durante o salvamento + Reload the page to attempt to fix the problem. - Recarregue a página para tentar corrigir o problema. + Recarregue a página para tentar corrigir o problema. + Reload the backend - Recarregar o backend + Recarregar o backend + Reload - Recarregar + Recarregar + In-Place - No local + No local + Raw Content - Conteúdo bruto + Conteúdo bruto + Raw Content Mode - Modo de conteúdo nú + Modo de conteúdo nú + Desktop - Área de Trabalho + Área de Trabalho + Login to - Typo3 Neos Login + Typo3 Neos Login + Authenticating - Autenticando + Autenticando + Logout - Sair + Sair + The entered username or password was wrong - O nome de usuário ou a senha estão incorretos + O nome de usuário ou a senha estão incorretos + Your login has expired. Please log in again. - O login expirou. Por favor faça um novo login. + O login expirou. Por favor faça um novo login. + Welcome to Neos - Bem-vindo(a) ao Neos + Bem-vindo(a) ao Neos + Go to setup - Ir para instalação + Ir para instalação + Technical Information - Informação Técnica + Informação Técnica + Missing Homepage - Faltando Homepage + Faltando Homepage + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - O site não foi definido, o site não contém uma página inicial ou o site ativo não pôde ser determinado. + O site não foi definido, o site não contém uma página inicial ou o site ativo não pôde ser determinado. + You might want to set the site's domain or import a new site in the setup. - Você pode querer definir o domínio do site, ou importar um novo site na configuração. + Você pode querer definir o domínio do site, ou importar um novo site na configuração. + Database Error - Erro no banco de dados + Erro no banco de dados + There is no database connection yet or the Neos database schema has not been created. - Ainda não existe uma conexão de banco de dados ou o esquema de banco de dados Neos não foi criado. + Ainda não existe uma conexão de banco de dados ou o esquema de banco de dados Neos não foi criado. + Run the setup to configure your database. - Execute a configuração para configurar seu banco de dados. + Execute a configuração para configurar seu banco de dados. + Page Not Found - Página Não Encontrada + Página Não Encontrada + Sorry, the page you requested was not found. - Desculpe, a página que você solicitou não foi encontrada. + Desculpe, a página que você solicitou não foi encontrada. + Invalid NodeType - NodeType inválido + NodeType inválido + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - A configuração do NodeType que é suposto ser processado aqui não está disponível. Provavelmente você renomeou o NodeType e está faltando uma migração, ou você simplesmente escreveu errado. + A configuração do NodeType que é suposto ser processado aqui não está disponível. Provavelmente você renomeou o NodeType e está faltando uma migração, ou você simplesmente escreveu errado. + Unexpected error while creating node - Erro não esperado ao criar o nó + Erro não esperado ao criar o nó + Unexpected error while deleting node - Erro não esperado ao apagar o nó + Erro não esperado ao apagar o nó + Unexpected error while updating node - Erro não esperado ao atualizar o nó + Erro não esperado ao atualizar o nó + Unexpected error while moving node - Erro não esperado ao mover o nó + Erro não esperado ao mover o nó + Node Tree loading error. - Erro ao carregar a árvore de nós. + Erro ao carregar a árvore de nós. + - - The entered username or password was wrong - O nome de usuário ou a senha estão incorretos "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" na página "{pageLabel}" + "{nodeTypeName}" na página "{pageLabel}" + Nodes - Nós + Nós + Show - Mostrar + Mostrar + This node cannot be accessed through a public URL - Este nó não pode ser acessado através de uma URL pública + Este nó não pode ser acessado através de uma URL pública + Node Properties - Propriedades do nó + Propriedades do nó + Copy {source} to {target} - Copiar {source} para {target} + Copiar {source} para {target} + Move {source} to {target} - Mover {source} para {target} + Mover {source} para {target} + Please select the position at which you want {source} inserted relative to {target}. - Por favor selecione a posição na qual você quer {source} inserido relativo a {target}. + Por favor selecione a posição na qual você quer {source} inserido relativo a {target}. + Insert - Inserir + Inserir + Insert mode - Modo de inserção + Modo de inserção + Choose an Aspect Ratio - Escolha uma proporção + Escolha uma proporção + Bold - Negrito + Negrito + Italic - Itálico + Itálico + Underline - Sublinhado + Sublinhado + Subscript - Subscrito + Subscrito + Superscript - Sobrescrito + Sobrescrito + Strikethrough - Tachado + Tachado + Link - Link + Link + Ordered list - Lista ordenada + Lista ordenada + Unordered list - Lista desordenada + Lista desordenada + Align left - Alinhar à esquerda + Alinhar à esquerda + Align right - Alinhar à direita + Alinhar à direita + Align center - Alinhar ao centro + Alinhar ao centro + Align justify - Alinhar justificado + Alinhar justificado + Table - Tabela + Tabela + Remove format - Remover formatação + Remover formatação + Outdent - Desindentar + Desindentar + Indent - Indentar + Indentar + Create new - Criar novo + Criar novo + No matches found - Nenhuma correspondência encontrada + Nenhuma correspondência encontrada + Please enter ###CHARACTERS### more character - Por favor, insira ###CHARACTERS### caracteres a mais + Por favor, insira ###CHARACTERS### caracteres a mais + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - O nome de usuário ou a senha estão incorretos + O nome de usuário ou a senha estão incorretos + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/pt_BR/Modules.xlf b/Neos.Neos/Resources/Private/Translations/pt_BR/Modules.xlf index 437debac006..57b5e6628e6 100644 --- a/Neos.Neos/Resources/Private/Translations/pt_BR/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/pt_BR/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Todas as alterações do espaço de trabalho "{0}" foram descartadas. - - History - Histórico - - - This module provides an overview of all relevant events affecting this Neos installation. - Este módulo fornece uma visão geral de todos os eventos relevantes que afetam esta instalação do Neos. - - - Here's what happened recently in Neos - Aqui está o que aconteceu recentemente no Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Não foram registrados quaisquer eventos que poderiam ser exibido neste histórico ainda. - - - {0} created the {1} "{2}". - {0} criou o {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removeu o {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} criou a variante {1} do {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modificou o {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moveu o {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copiou o {1} {2}. - - - {0} renamed the {1} "{2}" to "{3}". - {0} renomeou o {1} "{2}" para "{3}". - - - {0} modified content on the {1} "{2}". - {0} modificou o conteúdo no {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} criou um novo usuário "{1}" para {2}. - - - {0} deleted the account "{1}" of {2}. - {0} excluiu a conta "{1}" de {2}. - - - Load More - Carregar mais - - - This node has been removed in the meantime - Este nó já foi removido - Administration diff --git a/Neos.Neos/Resources/Private/Translations/ru/Main.xlf b/Neos.Neos/Resources/Private/Translations/ru/Main.xlf index 87474792f89..801c8b8c6c3 100644 --- a/Neos.Neos/Resources/Private/Translations/ru/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/ru/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - Автоматическая публикация + Автоматическая публикация + Auto-Publish to {0} - Автоматическая публикация в {0} + Автоматическая публикация в {0} + Review changes - Обзор изменений + Обзор изменений + Apply - Применить + Применить + Apply changes - Применить изменения + Применить изменения + Cancel - Отмена + Отмена + Back - Назад + Назад + Choose - Выбрать + Выбрать + Type to search - Введите для поиска + Введите для поиска + Content - Содержимое + Содержимое + Node - Элемент + Элемент + Content View - Просмотр содержимого + Просмотр содержимого + Create after - Создать после + Создать после + Create new - Создать новый + Создать новый + Close - Закрыть + Закрыть + Copy - Копировать + Копировать + Cut - Вырезать + Вырезать + Delete - Удалить + Удалить + Yes, delete the element - Да, удалить элемент + Да, удалить элемент + Delete the element - Удалить элемент + Удалить элемент + Discard - Сбросить + Сбросить + Discard changes - Сбросить изменения + Сбросить изменения + Edit title - Редактировать название + Редактировать название + Edit / Preview - Правка / просмотр + Правка / просмотр + Edit - Редактировать + Редактировать + Hide / Unhide - Скрыть / Показать + Скрыть / Показать + Hide - Скрыть + Скрыть + Unhide - Показать + Показать + into - в + в + before - до + до + after - после + после + Loading - Загрузка + Загрузка + New After - Добавить после + Добавить после + New Before - Добавить перед + Добавить перед + New Into - Добавить в + Добавить в + Navigate - Навигировать + Навигировать + OK - ОК + ОК + Page - Страница + Страница + Paste - Вставить + Вставить + Paste After - Вставить после + Вставить после + Paste Before - Вставить перед + Вставить перед + Paste Into - Вставить в + Вставить в + Password - Пароль + Пароль + Preview - Предпросмотр + Предпросмотр + Publish - Опубликовать + Опубликовать + Publish to {0} - Опубликовать в {0} + Опубликовать в {0} + Publish all changes for current page - Опубликовать все изменения на текущей странице + Опубликовать все изменения на текущей странице + Can't publish because the target workspace is read-only - Не удается опубликовать, потому что целевая рабочая область доступна только для чтения + Не удается опубликовать, потому что целевая рабочая область доступна только для чтения + Select target workspace - Выбрать рабочую область + Выбрать рабочую область + Publishing - Публикация + Публикация + Published - Опубликовано + Опубликовано + Toggle publish menu - Переключить меню публикаций + Переключить меню публикаций + Target workspace - Целевая рабочая область + Целевая рабочая область + Current workspace - Текущая рабочая область + Текущая рабочая область + Remove - Удалить + Удалить + Refresh - Обновить + Обновить + Save - Сохранить + Сохранить + Saving - Сохранение + Сохранение + Saved - Сохранено + Сохранено + Search - Поиск + Поиск + Toggle inspector - Переключить инспектор + Переключить инспектор + Username - Имя пользователя + Имя пользователя + You - Вы + Вы + [no title] - [без названия] + [без названия] + Label - Обозначение + Обозначение + Content Type - Тип содержимого + Тип содержимого + Path - Путь + Путь + Relative Path - Относительный путь + Относительный путь + Version - Версия + Версия + This operation cannot be undone. - Эта операция не может быть отменена. + Эта операция не может быть отменена. + Asset - Медиа-ресурс + Медиа-ресурс + Created - создано + создано + Last modification - Последнее изменение + Последнее изменение + Last publication - Последняя публикация + Последняя публикация + Identifier - Идентификатор + Идентификатор + Name - Имя + Имя + Workspace - Рабочая область + Рабочая область + Structure - Структура + Структура + Toggle context structure - Переключить структуру контекста + Переключить структуру контекста + Filter - Фильтр + Фильтр + Toggle menu - Переключить меню + Переключить меню + Load error! - Ошибка загрузки! + Ошибка загрузки! + You have to select a node - Вы должны выбрать элемент + Вы должны выбрать элемент + The Root node cannot be deleted. - Корневой элемент не может быть удален. + Корневой элемент не может быть удален. + You cannot copy this node - Нельзя скопировать этот элемент + Нельзя скопировать этот элемент + You cannot cut this node - Нельзя вырезать этот элемент + Нельзя вырезать этот элемент + Content Dimensions - Пространства содержимого + Пространства содержимого + Site - Сайт + Сайт + Document - Документ + Документ + Reference - Ссылка + Ссылка + Host - Хост + Хост + Scheme - Схема + Схема + Port - Порт + Порт + Primary - Основной + Основной + Package - Пакет + Пакет + Deactivated - Деактивирован + Деактивирован + Unavailable - Недоступно + Недоступно + Inactive - Откл. + Откл. + Click to edit - Нажмите для редактирования + Нажмите для редактирования + Click to deactivate - Нажмите, чтобы отключить + Нажмите, чтобы отключить + Click to activate - Нажмите, чтобы включить + Нажмите, чтобы включить + Click to delete - Нажмите, чтобы удалить + Нажмите, чтобы удалить + Click to create new - Нажмите, чтобы создать + Нажмите, чтобы создать + Status - Статус + Статус + Active - Вкл. + Вкл. + Domains - Домены + Домены + Domain - Домен + Домен + Yes, delete it! - Да, удалить! + Да, удалить! + Package Key - Ключ пакета + Ключ пакета + Description - Описание + Описание + Toggle content tree - Переключить дерево контента + Переключить дерево контента + Show publish options - Показать параметры публикации + Показать параметры публикации + Activate Fullscreen edit mode - Включить полноэкранный режим редактирования + Включить полноэкранный режим редактирования + Deactivate Fullscreen edit mode - Отключить полноэкранный режим редактирования + Отключить полноэкранный режим редактирования + Show preview - Предварительный просмотр + Предварительный просмотр + General - Общие + Общие + Structure - Структура + Структура + Plugins - Плагины + Плагины + Click {0} to continue to the page. - Нажмите {0}, чтобы перейти на страницу. + Нажмите {0}, чтобы перейти на страницу. + Click {0} to see the file. - Нажмите {0} для просмотра файла. + Нажмите {0} для просмотра файла. + Click {0} to open the link. - Нажмите {0}, чтобы перейти на внешнюю страницу. + Нажмите {0}, чтобы перейти на внешнюю страницу. + (no target has been selected) - (цель не была выбрана) + (цель не была выбрана) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - Это ярлык для первой дочерней страницы.<br />Нажмите {0}, для перехода на эту страницу. + Это ярлык для первой дочерней страницы.<br />Нажмите {0}, для перехода на эту страницу. + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - Это ярлык для родительской страницы.<br />Нажмите {0}, для перехода на эту страницу. + Это ярлык для родительской страницы.<br />Нажмите {0}, для перехода на эту страницу. + Full Screen - Во весь экран + Во весь экран + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - Открыть страницу в публичной рабочей области + Открыть страницу в публичной рабочей области + Open page in target workspace - Открыть страницу в целевой рабочей области + Открыть страницу в целевой рабочей области + Discard all - Отменить все + Отменить все + Discard all changes - Отменить все изменения + Отменить все изменения + Are you sure that you want to discard all changes in this workspace? - Вы уверены, что хотите отменить все изменения в этой рабочей области? + Вы уверены, что хотите отменить все изменения в этой рабочей области? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - Вы уверены, что хотите отменить правки в количестве {numberOfChanges} шт. в этой рабочей области? + Вы уверены, что хотите отменить правки в количестве {numberOfChanges} шт. в этой рабочей области? + Publish all - Опубликовать все + Опубликовать все + Publish all changes - Опубликовать все изменения + Опубликовать все изменения + Are you sure that you want to publish all changes? - Вы уверены, что хотите опубликовать все изменения? + Вы уверены, что хотите опубликовать все изменения? + Pending changes - Невыполненные изменения + Невыполненные изменения + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - Ваша личная рабочай область в настоящее время содержит неопубликованные изменения. Чтобы переключиться на другое целевое рабоче пространство необходимо сначала опубликовать или отменить неопубликованные изменения. + Ваша личная рабочай область в настоящее время содержит неопубликованные изменения. Чтобы переключиться на другое целевое рабоче пространство необходимо сначала опубликовать или отменить неопубликованные изменения. + Please review your changes, publish or discard them, and then choose a new target workspace again. - Пожалуйста просмотрите ваши изменения, опубликуйте или отмените их, а затем снова выбирите целевую рабочую область. + Пожалуйста просмотрите ваши изменения, опубликуйте или отмените их, а затем снова выбирите целевую рабочую область. + Editing Modes - Режимы редактирования + Режимы редактирования + Preview Central - Центр предпросмотра + Центр предпросмотра + You still have changes. What do you want to do with them? - Имеются несохраненные изменения. Что с ними делать? + Имеются несохраненные изменения. Что с ними делать? + Selected element - Выбранный элемент + Выбранный элемент + There are fields that are not correctly filled in. - Есть поля, которые заполнены неправильно. + Есть поля, которые заполнены неправильно. + The fields marked with an error are not yet correctly filled in. Please complete them properly. - Отмеченные ошибкой поля всё еще заполнены не верно. Пожалуйста, заполните их должным образом. + Отмеченные ошибкой поля всё еще заполнены не верно. Пожалуйста, заполните их должным образом. + Continue editing - Продолжить правку + Продолжить правку + Throw away - Отклонить + Отклонить + Apply - Применить + Применить + Select a Plugin - Выберите плагин + Выберите плагин + No plugin configured - Ни один плагин не настроен + Ни один плагин не настроен + view is displayed on page - представление отображается на странице + представление отображается на странице + view is displayed on current page - представление отображается на текущей странице + представление отображается на текущей странице + No date set - Дата не установлена + Дата не установлена + Edit code - Редактировать код + Редактировать код + Paste a link, or type to search - Вставьте ссылку или введите для поиска + Вставьте ссылку или введите для поиска + Unable to load sub node types of: - Не удается загрузить подтипы элементов: + Не удается загрузить подтипы элементов: + Change type - Изменить тип + Изменить тип + Additional info - Дополнительная информация + Дополнительная информация + Visibility - Видимость + Видимость + Document options - Параметры документа + Параметры документа + The length of this text must be between {minimum} and {maximum} characters. - Длина этого текста должна быть между {minimum} и {maximum} символами. + Длина этого текста должна быть между {minimum} и {maximum} символами. + This field must contain at least {minimum} characters. - Это поле должно содержать по крайней мере {minimum} символов. + Это поле должно содержать по крайней мере {minimum} символов. + This text may not exceed {maximum} characters. - Этот текст не может превышать {maximum} символов. + Этот текст не может превышать {maximum} символов. + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - Разрешены только латинские(a до z, умлауты, ...) малые буквы и цифры. + Разрешены только латинские(a до z, умлауты, ...) малые буквы и цифры. + The given subject was not countable. - Содержимое не является исчислимым. + Содержимое не является исчислимым. + The count must be between {minimum} and {maximum}. - Количество должно быть между {minimum} и {maximum}. + Количество должно быть между {minimum} и {maximum}. + The given value was not a valid date. - Данное значение не является допустимой датой. + Данное значение не является допустимой датой. + The given date must be between {formatEarliestDate} and {formatLatestDate} - Данная дата должна быть между {formatEarliestDate} и {formatLatestDate} + Данная дата должна быть между {formatEarliestDate} и {formatLatestDate} + The given date must be after {formatEarliestDate} - Данная дата должна быть позже чем {formatEarliestDate} + Данная дата должна быть позже чем {formatEarliestDate} + The given date must be before {formatLatestDate} - Данная дата должна быть раньше {formatLatestDate} + Данная дата должна быть раньше {formatLatestDate} + Please specify a valid email address. - Пожалуйста укажите верный адрес электронной почты. + Пожалуйста укажите верный адрес электронной почты. + A valid float number is expected. - Ожидается вещественное число. + Ожидается вещественное число. + A valid integer number is expected. - Ожидается целое число. + Ожидается целое число. + Only letters, numbers, spaces and certain punctuation marks are expected. - Ожидаются только буквы, цифры, пробелы и определенные знаки пунктуации. + Ожидаются только буквы, цифры, пробелы и определенные знаки пунктуации. + This property is required. - Это свойство является обязательным. + Это свойство является обязательным. + A valid number is expected. - Ожидается число. + Ожидается число. + Please enter a valid number between {minimum} and {maximum} - Пожалуйста, введите число от {minimum} до {maximum} + Пожалуйста, введите число от {minimum} до {maximum} + The given subject did not match the pattern ({pattern}) - Данное поле не соответствует шаблону ({pattern}) + Данное поле не соответствует шаблону ({pattern}) + A valid string is expected. - Ожидается строковый тип. + Ожидается строковый тип. + Valid text without any XML tags is expected. - Ожидается текст без XML-тэгов. + Ожидается текст без XML-тэгов. + The given subject is not a valid UUID. - Значение не является допустимым UUID. + Значение не является допустимым UUID. + Toggle content dimensions selector - Переключить выбор пространств содержимого + Переключить выбор пространств содержимого + Start with an empty or pre-filled document? - Начинать с чистиго листа или с пред-заполненного документа? + Начинать с чистиго листа или с пред-заполненного документа? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - Этот элемент ({nodeTypeLabel}) еще не существует в пространстве содержимого "{currentDimensionChoiceText}". + Этот элемент ({nodeTypeLabel}) еще не существует в пространстве содержимого "{currentDimensionChoiceText}". + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - Можно создать сейчас, начиная с пустого элемента {nodeTypeLabel} или путём копирования всего содержимого из открытого в данный момент элемента {nodeTypeLabel} в {currentDocumentDimensionChoiceText}. + Можно создать сейчас, начиная с пустого элемента {nodeTypeLabel} или путём копирования всего содержимого из открытого в данный момент элемента {nodeTypeLabel} в {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - В выбранном варианте содержится {numberOfNodesMissingInRootline} не существующих родительских элементов, которые также будут созданы. + В выбранном варианте содержится {numberOfNodesMissingInRootline} не существующих родительских элементов, которые также будут созданы. + Create empty - Создать пустой + Создать пустой + Create and copy - Создать и скопировать + Создать и скопировать + Content - Содержимое + Содержимое + Toggle menu group - Скрыть/отобразить группу меню + Скрыть/отобразить группу меню + Toggle sticky menu mode - Переключить режим залипающего меню + Переключить режим залипающего меню + Do you really want to delete - Вы действительно хотите удалить + Вы действительно хотите удалить + This will delete the element - Это приведёт к удалению элемента + Это приведёт к удалению элемента + and it's children - и его дочерних элементов + и его дочерних элементов + This action can be undone in the workspace management. - Операцию можно отменить в меню управления рабочими областями. + Операцию можно отменить в меню управления рабочими областями. + Height - Высота + Высота + Do you really want to delete - Вы действительно хотите удалить + Вы действительно хотите удалить + this element - этот элемент + этот элемент + This will delete the element. - Это приведет к удалению элемента. + Это приведет к удалению элемента. + This action can be undone in the workspace management. - Операцию можно отменить в меню управления рабочими областями. + Операцию можно отменить в меню управления рабочими областями. + Media - Медиатека + Медиатека + Crop - Обрезать + Обрезать + Width - Ширина + Ширина + Missing required property: - Отсутствует обязательное свойство: + Отсутствует обязательное свойство: + Workspace - Рабочая область + Рабочая область + Workspaces - Рабочие области + Рабочие области + An error occurred during saving - Произошла ошибка при сохранении + Произошла ошибка при сохранении + Reload the page to attempt to fix the problem. - Обновите страницу, чтобы попытаться исправить эту проблему. + Обновите страницу, чтобы попытаться исправить эту проблему. + Reload the backend - Перезагрузить Neos + Перезагрузить Neos + Reload - Обновить + Обновить + In-Place - Правка напрямую + Правка напрямую + Raw Content - Необработанное содержимое + Необработанное содержимое + Raw Content Mode - Режим необработанного содержимого + Режим необработанного содержимого + Desktop - Настольный компьютер + Настольный компьютер + Login to - Войти в + Войти в + Authenticating - Аутентификация + Аутентификация + Logout - Выйти из системы + Выйти из системы + The entered username or password was wrong - Введенные имя пользователя или пароль неверные + Введенные имя пользователя или пароль неверные + Your login has expired. Please log in again. - Ваша сессия истекла. Пожалуйста, войдите снова. + Ваша сессия истекла. Пожалуйста, войдите снова. + Welcome to Neos - Добро пожаловать в Neos + Добро пожаловать в Neos + Go to setup - Перейти к установке + Перейти к установке + Technical Information - Техническая информация + Техническая информация + Missing Homepage - Домашняя страница отсутствует + Домашняя страница отсутствует + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Сайт не был задан, либо сайт не содержит стартовую страницу, либо невозможно определить активный сайт. + Сайт не был задан, либо сайт не содержит стартовую страницу, либо невозможно определить активный сайт. + You might want to set the site's domain or import a new site in the setup. - Попробуйте задать домен сайта или импортировать новый сайт в программе установки. + Попробуйте задать домен сайта или импортировать новый сайт в программе установки. + Database Error - Ошибка базы данных + Ошибка базы данных + There is no database connection yet or the Neos database schema has not been created. - Пока нет соединения с базой данных или схема базы данных Neos не была создана. + Пока нет соединения с базой данных или схема базы данных Neos не была создана. + Run the setup to configure your database. - Запустите установку для конфигурации базы данных. + Запустите установку для конфигурации базы данных. + Page Not Found - Страница не найдена + Страница не найдена + Sorry, the page you requested was not found. - К сожалению, запрашиваемая вами страница не найдена. + К сожалению, запрашиваемая вами страница не найдена. + Invalid NodeType - Недопустимый тип элемента + Недопустимый тип элемента + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - Настройка типа элемента, который должен отображаться здесь не доступен. Вероятно вы переименовали тип элемента и не выполнили миграцию или просто допустили опечатку. + Настройка типа элемента, который должен отображаться здесь не доступен. Вероятно вы переименовали тип элемента и не выполнили миграцию или просто допустили опечатку. + Unexpected error while creating node - Непредвиденная ошибка при создании элемента + Непредвиденная ошибка при создании элемента + Unexpected error while deleting node - Непредвиденная ошибка при удалении элемента + Непредвиденная ошибка при удалении элемента + Unexpected error while updating node - Непредвиденная ошибка при обновлении элемента + Непредвиденная ошибка при обновлении элемента + Unexpected error while moving node - Непредвиденная ошибка при перемещении элемента + Непредвиденная ошибка при перемещении элемента + Node Tree loading error. - Ошибка при загрузке дерева элементов. + Ошибка при загрузке дерева элементов. + - - The entered username or password was wrong - Введенные имя пользователя или пароль неверные "{nodeTypeName}" on page "{pageLabel}" - "{nodeTypeName}" на странице "{pageLabel}" + "{nodeTypeName}" на странице "{pageLabel}" + Nodes - Элементы + Элементы + Show - Показать + Показать + This node cannot be accessed through a public URL - Этот элемент не может быть доступным через общедоступный URL-адрес + Этот элемент не может быть доступным через общедоступный URL-адрес + Node Properties - Свойства элемента + Свойства элемента + Copy {source} to {target} - Скопировать {source} в {target} + Скопировать {source} в {target} + Move {source} to {target} - Переместить {source} на {target} + Переместить {source} на {target} + Please select the position at which you want {source} inserted relative to {target}. - Пожалуйста, выберите позицию вставки {source} относительно к {target}. + Пожалуйста, выберите позицию вставки {source} относительно к {target}. + Insert - Вставить + Вставить + Insert mode - Режим вставки + Режим вставки + Choose an Aspect Ratio - Выберите соотношение сторон + Выберите соотношение сторон + Bold - Жирный + Жирный + Italic - Курсив + Курсив + Underline - Подчёркнутый + Подчёркнутый + Subscript - Подстрочный + Подстрочный + Superscript - Верхний индекс + Верхний индекс + Strikethrough - Зачеркнутый + Зачеркнутый + Link - Ссылка + Ссылка + Ordered list - Нумерованный список + Нумерованный список + Unordered list - Ненумерованный список + Ненумерованный список + Align left - По левому краю + По левому краю + Align right - По правому краю + По правому краю + Align center - По центру + По центру + Align justify - По всей ширине + По всей ширине + Table - Таблица + Таблица + Remove format - Удалить форматирование + Удалить форматирование + Outdent - Уменьшить выступ + Уменьшить выступ + Indent - Увеличить выступ + Увеличить выступ + Create new - Создать новый + Создать новый + No matches found - Совпадений не найдено + Совпадений не найдено + Please enter ###CHARACTERS### more character - Пожалуйста, введите больше символов ## #CHARACTERS### + Пожалуйста, введите больше символов ## #CHARACTERS### + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - Введенные имя пользователя или пароль неверные + Введенные имя пользователя или пароль неверные + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/ru/Modules.xlf b/Neos.Neos/Resources/Private/Translations/ru/Modules.xlf index 0590cbc1e79..6add673b808 100644 --- a/Neos.Neos/Resources/Private/Translations/ru/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/ru/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Все изменения из рабочей области "{0}" были отменены. - - History - История изменений - - - This module provides an overview of all relevant events affecting this Neos installation. - Этот модуль предоставляет обзор всех событий, имеющих отношение к данной инсталяции Neos. - - - Here's what happened recently in Neos - Вот что недавно произошло в Neos: - - - There have not been recorded any events yet which could be displayed in this history. - Не было событий, которые могли бы быть отображены в данном журнале изменений. - - - {0} created the {1} "{2}". - {0} создал {1} "{2}". - - - {0} removed the {1} "{2}". - {0} удалил {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} создал вариант {1} из {2} "{3}". - - - {0} modified the {1} "{2}". - {0} изменил {1} "{2}". - - - {0} moved the {1} "{2}". - {0} переместил {1} "{2}". - - - {0} copied the {1} "{2}". - {0} скопировал {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} переименовал {1} "{2}" в "{3}". - - - {0} modified content on the {1} "{2}". - {0} изменил контент на {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} создал нового пользователя "{1}" для {2}. - - - {0} deleted the account "{1}" of {2}. - {0} удалил учётную запись "{1}" из {2}. - - - Load More - Загрузить ещё - - - This node has been removed in the meantime - За прошедшее время элемент был удален - Administration diff --git a/Neos.Neos/Resources/Private/Translations/sr/Main.xlf b/Neos.Neos/Resources/Private/Translations/sr/Main.xlf index cb09a0b7baa..781ab0aed04 100644 --- a/Neos.Neos/Resources/Private/Translations/sr/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/sr/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/sr/Modules.xlf b/Neos.Neos/Resources/Private/Translations/sr/Modules.xlf index e9cb4e3ec73..e6303a70574 100644 --- a/Neos.Neos/Resources/Private/Translations/sr/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/sr/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - History - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/sv/Main.xlf b/Neos.Neos/Resources/Private/Translations/sv/Main.xlf index ab97f8eeb09..e454de545f8 100644 --- a/Neos.Neos/Resources/Private/Translations/sv/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/sv/Main.xlf @@ -951,10 +951,6 @@ Fel när nodträd laddas. - - The entered username or password was wrong - Det angivna användarnamnet eller lösenordet var felaktigt - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/sv/Modules.xlf b/Neos.Neos/Resources/Private/Translations/sv/Modules.xlf index 24d7ac01f72..0157e0bbdf2 100644 --- a/Neos.Neos/Resources/Private/Translations/sv/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/sv/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Alla ändringar från arbetsytan "{0}" har ignorerats. - - History - Historik - - - This module provides an overview of all relevant events affecting this Neos installation. - Denna modul ger en översikt över alla relevanta händelser som påverkar denna Neos-installation. - - - Here's what happened recently in Neos - Här är vad som nyligen hänt i Neos - - - There have not been recorded any events yet which could be displayed in this history. - Det har ännu ej registrerats någon händelse i denna historik. - - - {0} created the {1} "{2}". - {0} skapade {1} "{2}". - - - {0} removed the {1} "{2}". - {0} raderade {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} skapade en variant {1} av {2} "{3}". - - - {0} modified the {1} "{2}". - {0} förändrade {1} "{2}". - - - {0} moved the {1} "{2}". - {0} flyttade {1} "{2}". - - - {0} copied the {1} "{2}". - {0} kopierade {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} döpte om {1} "{2}" till "{3}". - - - {0} modified content on the {1} "{2}". - {0} förändrade innehållet på {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} skapade en ny användare "{1}" för {2}. - - - {0} deleted the account "{1}" of {2}. - {0} raderade kontot "{1}" av {2}. - - - Load More - Ladda mer - - - This node has been removed in the meantime - Den här noden har tagits bort under tiden - Administration diff --git a/Neos.Neos/Resources/Private/Translations/tl_PH/Main.xlf b/Neos.Neos/Resources/Private/Translations/tl_PH/Main.xlf index 5fbb685d119..2a0032c2cf4 100644 --- a/Neos.Neos/Resources/Private/Translations/tl_PH/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/tl_PH/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - Ang na-enter na username o password ay mali - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/tl_PH/Modules.xlf b/Neos.Neos/Resources/Private/Translations/tl_PH/Modules.xlf index 80fefd4d86d..7ae4c39ff2a 100644 --- a/Neos.Neos/Resources/Private/Translations/tl_PH/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/tl_PH/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - History - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} ang gumawa ng {1} "{2}". - - - {0} removed the {1} "{2}". - {0} ay tinanggal ang {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} ay gumawa ng iba't-ibang {1} ng mga {2} "{3}". - - - {0} modified the {1} "{2}". - {0} ay binago ang {1} "{2}". - - - {0} moved the {1} "{2}". - {0} ay inilipat ang {1} "{2}". - - - {0} copied the {1} "{2}". - {0} ay kinopya ang {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} ay pinalitan ang pangalan ng {1} "{2}" sa "{3}". - - - {0} modified content on the {1} "{2}". - {0} ay binago ang nilalaman sa {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/tr/Main.xlf b/Neos.Neos/Resources/Private/Translations/tr/Main.xlf index 46efbc72a68..791c55df5f6 100644 --- a/Neos.Neos/Resources/Private/Translations/tr/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/tr/Main.xlf @@ -951,10 +951,6 @@ Düğüm Ağacı yükleme hatası. - - The entered username or password was wrong - Girilen kullanıcı adı veya parola yanlıştı - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/tr/Modules.xlf b/Neos.Neos/Resources/Private/Translations/tr/Modules.xlf index 1153da2b223..7986141defc 100644 --- a/Neos.Neos/Resources/Private/Translations/tr/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/tr/Modules.xlf @@ -259,70 +259,6 @@ All changes from workspace "{0}" have been discarded. "{0}" çalışma alanındaki tüm değişiklikler iptal edildi. - - History - Geçmiş - - - This module provides an overview of all relevant events affecting this Neos installation. - Bu modül bu Neos kurulumunu etkileyen tüm ilgili olaylara genel bir bakış sağlar. - - - Here's what happened recently in Neos - İşte son zamanlarda Neos'da olanlar - - - There have not been recorded any events yet which could be displayed in this history. - Henüz bu geçmişte gösterilebilecek herhangi bir olay kaydedildi. - - - {0} created the {1} "{2}". - {0}, {1} "{2}" oluşturdu. - - - {0} removed the {1} "{2}". - {0}, {1} "{2}" 'yi kaldırdı. - - - {0} created the variant {1} of the {2} "{3}". - {0}, {2} "{3}" varyantını {1} oluşturdu. - - - {0} modified the {1} "{2}". - {0}, {1} "{2}" değiştirdi. - - - {0} moved the {1} "{2}". - {0}, {1} "{2}" taşıdı. - - - {0} copied the {1} "{2}". - {0}, {1} "{2}" kopyaladı. - - - {0} renamed the {1} "{2}" to "{3}". - {0}, {1} "{2}" dan "{3}" olarak yeniden adlandırıldı. - - - {0} modified content on the {1} "{2}". - {0}, {1} "{2}" içeriği değiştirdi. - - - {0} created a new user "{1}" for {2}. - {0}, {2} için "{1}" adlı yeni bir kullanıcı oluşturdu. - - - {0} deleted the account "{1}" of {2}. - {0}, {2} hesabının "{1}" hesabını sildi. - - - Load More - Daha Fazla Yükle - - - This node has been removed in the meantime - Bu düğüm bu arada kaldırıldı - Administration diff --git a/Neos.Neos/Resources/Private/Translations/uk/Main.xlf b/Neos.Neos/Resources/Private/Translations/uk/Main.xlf index 118ddd1ca30..99295cb9770 100644 --- a/Neos.Neos/Resources/Private/Translations/uk/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/uk/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/uk/Modules.xlf b/Neos.Neos/Resources/Private/Translations/uk/Modules.xlf index 0cdcd281130..da91e27fe35 100644 --- a/Neos.Neos/Resources/Private/Translations/uk/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/uk/Modules.xlf @@ -261,70 +261,6 @@ All changes from workspace "{0}" have been discarded. Всі зміни з робочого середовища "{0}" були скасовані. - - History - Історія - - - This module provides an overview of all relevant events affecting this Neos installation. - Цей модуль забезпечує огляд всіх відповідних подій, маючих вплив до встановлення Neos. - - - Here's what happened recently in Neos - Останні події в Neos - - - There have not been recorded any events yet which could be displayed in this history. - Відсутні записи подій, які можуть відображатися в історії. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} створити нового користувача "{1}" для {2}. - - - {0} deleted the account "{1}" of {2}. - {0} видалив обліковий запис "{1}" {2}. - - - Load More - Завантажити ще - - - This node has been removed in the meantime - Цей вузол буде видалено в той же час - Administration diff --git a/Neos.Neos/Resources/Private/Translations/vi/Main.xlf b/Neos.Neos/Resources/Private/Translations/vi/Main.xlf index dac64adc97b..63d8ecd038f 100644 --- a/Neos.Neos/Resources/Private/Translations/vi/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/vi/Main.xlf @@ -951,10 +951,6 @@ Node Tree loading error. - - The entered username or password was wrong - The entered username or password was wrong - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/vi/Modules.xlf b/Neos.Neos/Resources/Private/Translations/vi/Modules.xlf index 13d2d5d3a5f..8f4f96bc070 100644 --- a/Neos.Neos/Resources/Private/Translations/vi/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/vi/Modules.xlf @@ -257,70 +257,6 @@ All changes from workspace "{0}" have been discarded. Tất cả thay đổi từ không gian làm việc "{0}" đã bị hủy bỏ. - - History - Lịch sử - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Hiển thị Thêm - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Private/Translations/zh/Main.xlf b/Neos.Neos/Resources/Private/Translations/zh/Main.xlf index de2a5fe8767..f49dadf721b 100644 --- a/Neos.Neos/Resources/Private/Translations/zh/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/zh/Main.xlf @@ -951,10 +951,6 @@ 节点树加载错误。 - - The entered username or password was wrong - 输入的用户名或密码错误 - "{nodeTypeName}" on page "{pageLabel}" diff --git a/Neos.Neos/Resources/Private/Translations/zh/Modules.xlf b/Neos.Neos/Resources/Private/Translations/zh/Modules.xlf index 1c34134849b..7d0604cad97 100644 --- a/Neos.Neos/Resources/Private/Translations/zh/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/zh/Modules.xlf @@ -257,70 +257,6 @@ All changes from workspace "{0}" have been discarded. 工作区 "{0}" 中的所有更改已丢弃。 - - History - 历史 - - - This module provides an overview of all relevant events affecting this Neos installation. - 该模块概述了影响此Neos安装的所有相关事件。 - - - Here's what happened recently in Neos - 最近发生的事件/操作: - - - There have not been recorded any events yet which could be displayed in this history. - 没有可以显示的记录。 - - - {0} created the {1} "{2}". - {0} 创建了 {1} {2}。 - - - {0} removed the {1} "{2}". - {0} 删除了 {1} {2}。 - - - {0} created the variant {1} of the {2} "{3}". - {0} 创建了 {2} 的变体 {1} "{3}"。 - - - {0} modified the {1} "{2}". - {0} 修改了 {1} "{2}"。 - - - {0} moved the {1} "{2}". - {0} 移动了 {1} {2}。 - - - {0} copied the {1} "{2}". - {0} 复制了 {1} "{2}"。 - - - {0} renamed the {1} "{2}" to "{3}". - {0} 将 {1} "{2}" 重命名为 "{3}"。 - - - {0} modified content on the {1} "{2}". - {0} 修改了 {1} "{2}" 上的内容。 - - - {0} created a new user "{1}" for {2}. - {0} 为 {2} 创建一个新用户"{1}"。 - - - {0} deleted the account "{1}" of {2}. - {0} 删除了 {2} 的帐户"{1}"。 - - - Load More - 载入更多 - - - This node has been removed in the meantime - 在此期间此节点已删除 - Administration diff --git a/Neos.Neos/Resources/Private/Translations/zh_TW/Main.xlf b/Neos.Neos/Resources/Private/Translations/zh_TW/Main.xlf index 7a3a5d201ff..eadc099f83e 100644 --- a/Neos.Neos/Resources/Private/Translations/zh_TW/Main.xlf +++ b/Neos.Neos/Resources/Private/Translations/zh_TW/Main.xlf @@ -5,828 +5,1095 @@ Auto-Publish - 自動發布 + 自動發布 + Auto-Publish to {0} - 自動發布至 {0} + 自動發布至 {0} + Review changes - 審閱變更 + 審閱變更 + Apply - 套用 + 套用 + Apply changes - 套用變更 + 套用變更 + Cancel - 取消 + 取消 + Back - 返回 + 返回 + Choose - 選擇 + 選擇 + Type to search - 類型以搜尋 + 類型以搜尋 + Content - 內容 + 內容 + Node - 節點 + 節點 + Content View - 內容檢視 + 內容檢視 + Create after - 之後建立 + 之後建立 + Create new - 新增 + 新增 + Close - 關閉 + 關閉 + Copy - 複製 + 複製 + Cut - 剪下 + 剪下 + Delete - 刪除 + 刪除 + Yes, delete the element - 是的,刪除元素 + 是的,刪除元素 + Delete the element - 刪除元素 + 刪除元素 + Discard - 捨棄 + 捨棄 + Discard changes - 捨棄變更 + 捨棄變更 + Edit title - 編輯標題 + 編輯標題 + Edit / Preview - 標期 / 預覽 + 標期 / 預覽 + Edit - 編輯 + 編輯 + Hide / Unhide - 隱藏 / 顯示 + 隱藏 / 顯示 + Hide - 隱藏 + 隱藏 + Unhide - 顯示 + 顯示 + into - + + before - 之前 + 之前 + after - 之後 + 之後 + Loading - 讀取中 + 讀取中 + New After - 新增之後 + 新增之後 + New Before - 新增之前 + 新增之前 + New Into - 新增至 + 新增至 + Navigate - 導航 + 導航 + OK - 確定 + 確定 + Page - 頁面 + 頁面 + Paste - 貼上 + 貼上 + Paste After - 貼於之後 + 貼於之後 + Paste Before - 貼於之前 + 貼於之前 + Paste Into - 貼至 + 貼至 + Password - 密碼 + 密碼 + Preview - 預覽 + 預覽 + Publish - 發布 + 發布 + Publish to {0} - 發布至 {0} + 發布至 {0} + Publish all changes for current page - 發布所有變更至目前頁面 + 發布所有變更至目前頁面 + Can't publish because the target workspace is read-only - 由於目標工作區唯讀因此無法發布 + 由於目標工作區唯讀因此無法發布 + Select target workspace - 選擇目標工作區 + 選擇目標工作區 + Publishing - 發布中 + 發布中 + Published - 已發布 + 已發布 + Toggle publish menu - 切換發布選單 + 切換發布選單 + Target workspace - 目標工作區 + 目標工作區 + Current workspace - 目前工作區 + 目前工作區 + Remove - 移除 + 移除 + Refresh - 重新整理 + 重新整理 + Save - 儲存 + 儲存 + Saving - 儲存中 + 儲存中 + Saved - 已儲存 + 已儲存 + Search - 搜尋 + 搜尋 + Toggle inspector - 切換檢測器 + 切換檢測器 + Username - 使用者名稱 + 使用者名稱 + You - + + [no title] - [無標題] + [無標題] + Label - 標籤 + 標籤 + Content Type - 內容類型 + 內容類型 + Path - 路徑 + 路徑 + Relative Path - 相對路徑 + 相對路徑 + Version - 版本 + 版本 + This operation cannot be undone. - This operation cannot be undone. + This operation cannot be undone. + Asset - 素材 + 素材 + Created - 已建立 + 已建立 + Last modification - 上次修改 + 上次修改 + Last publication - 上次發布 + 上次發布 + Identifier - Identifier + Identifier + Name - 名稱 + 名稱 + Workspace - 工作區 + 工作區 + Structure - 結構 + 結構 + Toggle context structure - 切換前後文結構 + 切換前後文結構 + Filter - 篩選器 + 篩選器 + Toggle menu - 切換選單 + 切換選單 + Load error! - 讀取錯誤! + 讀取錯誤! + You have to select a node - 您必須選擇一個節點 + 您必須選擇一個節點 + The Root node cannot be deleted. - 根節點無法被刪除。 + 根節點無法被刪除。 + You cannot copy this node - 您不能複製此節點 + 您不能複製此節點 + You cannot cut this node - 您不能剪下此節點 + 您不能剪下此節點 + Content Dimensions - 內容尺寸 + 內容尺寸 + Site - 網站 + 網站 + Document - 文件 + 文件 + Reference - 參考 + 參考 + Host - 主機 + 主機 + Scheme - 方案 + 方案 + Port - 通訊埠 + 通訊埠 + Primary - 主要的 + 主要的 + Package - 套件 + 套件 + Deactivated - 已停用 + 已停用 + Unavailable - 無法使用 + 無法使用 + Inactive - 停用 + 停用 + Click to edit - 點此編輯 + 點此編輯 + Click to deactivate - 點此停用 + 點此停用 + Click to activate - 點此啟用 + 點此啟用 + Click to delete - Click to delete + Click to delete + Click to create new - 點此新增 + 點此新增 + Status - 狀態 + 狀態 + Active - 啟用 + 啟用 + Domains - 網域名稱 + 網域名稱 + Domain - 網域名稱 + 網域名稱 + Yes, delete it! - 是的,刪除它! + 是的,刪除它! + Package Key - 套件金鑰 + 套件金鑰 + Description - 描述 + 描述 + Toggle content tree - Toggle content tree + Toggle content tree + Show publish options - Show publish options + Show publish options + Activate Fullscreen edit mode - Activate Fullscreen edit mode + Activate Fullscreen edit mode + Deactivate Fullscreen edit mode - Deactivate Fullscreen edit mode + Deactivate Fullscreen edit mode + Show preview - Show preview + Show preview + General - 一般 + 一般 + Structure - 結構 + 結構 + Plugins - 外掛 + 外掛 + Click {0} to continue to the page. - 點選 {0} 繼續頁面。 + 點選 {0} 繼續頁面。 + Click {0} to see the file. - 點選 {0} 檢視檔案。 + 點選 {0} 檢視檔案。 + Click {0} to open the link. - 點選 {0} 開啟連結。 + 點選 {0} 開啟連結。 + (no target has been selected) - (未選擇目標) + (未選擇目標) + This is a shortcut to the first child page.<br />Click {0} to continue to the page. - 這是前往第一個子頁面的捷徑。<br />點選{0}繼續前往頁面。 + 這是前往第一個子頁面的捷徑。<br />點選{0}繼續前往頁面。 + This is a shortcut to the parent page.<br />Click {0} to continue to the page. - 這是前往父頁面的捷徑。<br />點選{0}繼續前往頁面。 + 這是前往父頁面的捷徑。<br />點選{0}繼續前往頁面。 + Full Screen - 全螢幕 + 全螢幕 + Open page in live workspace Deprecated, replaced by previewShortcutButton.title - 在現有工作區開啟頁面 + 在現有工作區開啟頁面 + Open page in target workspace - 在目標工作區開啟頁面 + 在目標工作區開啟頁面 + Discard all - 捨棄全部 + 捨棄全部 + Discard all changes - 捨棄全部變更 + 捨棄全部變更 + Are you sure that you want to discard all changes in this workspace? - 你確定要放棄所有在此工作區的變更? + 你確定要放棄所有在此工作區的變更? + Are you sure that you want to discard {numberOfChanges} change(s) in this workspace? - 您確定要放棄 {numberOfChanges} 筆在此工作區所做的修改? + 您確定要放棄 {numberOfChanges} 筆在此工作區所做的修改? + Publish all - 發布全部 + 發布全部 + Publish all changes - 發布全部變更 + 發布全部變更 + Are you sure that you want to publish all changes? - 您確定要發布所有變更? + 您確定要發布所有變更? + Pending changes - 變更擱置中 + 變更擱置中 + Your personal workspace currently contains unpublished changes. In order to switch to a different target workspace you need to either publish or discard pending changes first. - 你的個人工作區目前包含未發布的變更,為了切換至不同的目標工作區,你需要先發布或放棄這些變更。 + 你的個人工作區目前包含未發布的變更,為了切換至不同的目標工作區,你需要先發布或放棄這些變更。 + Please review your changes, publish or discard them, and then choose a new target workspace again. - 請檢視你的變更,選擇要發布或放棄,最後再選擇一個新的目標工作區。 + 請檢視你的變更,選擇要發布或放棄,最後再選擇一個新的目標工作區。 + Editing Modes - 編輯模式 + 編輯模式 + Preview Central - 預覽中心 + 預覽中心 + You still have changes. What do you want to do with them? - 你還有變更,你想要如何處理它們? + 你還有變更,你想要如何處理它們? + Selected element - 選擇元素 + 選擇元素 + There are fields that are not correctly filled in. - 有部分欄位尚未正確填入。 + 有部分欄位尚未正確填入。 + The fields marked with an error are not yet correctly filled in. Please complete them properly. - 有標記為錯誤的欄位尚未正確填入,請正確填寫。 + 有標記為錯誤的欄位尚未正確填入,請正確填寫。 + Continue editing - 繼續編輯 + 繼續編輯 + Throw away - 捨棄 + 捨棄 + Apply - 套用 + 套用 + Select a Plugin - 選擇外掛 + 選擇外掛 + No plugin configured - 沒有設定的外掛 + 沒有設定的外掛 + view is displayed on page - view is displayed on page + view is displayed on page + view is displayed on current page - view is displayed on current page + view is displayed on current page + No date set - 沒有設定日期 + 沒有設定日期 + Edit code - 編輯代碼 + 編輯代碼 + Paste a link, or type to search - 貼上連結,或輸入以搜尋 + 貼上連結,或輸入以搜尋 + Unable to load sub node types of: - 無法讀取子節點類型: + 無法讀取子節點類型: + Change type - 變更類型 + 變更類型 + Additional info - 額外資訊 + 額外資訊 + Visibility - 能見度 + 能見度 + Document options - 文件選項 + 文件選項 + The length of this text must be between {minimum} and {maximum} characters. - 此文字長度必須介於 {minimum} 和 {maximum} 個字元。 + 此文字長度必須介於 {minimum} 和 {maximum} 個字元。 + This field must contain at least {minimum} characters. - 此欄位必須包含至少 {minimum} 個字元。 + 此欄位必須包含至少 {minimum} 個字元。 + This text may not exceed {maximum} characters. - 此文字可能不超過 {maximum} 個字元。 + 此文字可能不超過 {maximum} 個字元。 + Only regular characters (a to z, umlauts, ...) and numbers are allowed. - 只允許使用一般字元 (a 至 z, 變音, ...) 和數字。 + 只允許使用一般字元 (a 至 z, 變音, ...) 和數字。 + The given subject was not countable. - 給予的主題不可數。 + 給予的主題不可數。 + The count must be between {minimum} and {maximum}. - 計數必須在 {minimum} 和 {maximum} 之間。 + 計數必須在 {minimum} 和 {maximum} 之間。 + The given value was not a valid date. - 給予的值不是有效日期。 + 給予的值不是有效日期。 + The given date must be between {formatEarliestDate} and {formatLatestDate} - 有效日期必須在 {formatEarliestDate} 和 {formatLatestDate} 之間。 + 有效日期必須在 {formatEarliestDate} 和 {formatLatestDate} 之間。 + The given date must be after {formatEarliestDate} - 有效日期必須在 {formatEarliestDate} 之後 + 有效日期必須在 {formatEarliestDate} 之後 + The given date must be before {formatLatestDate} - 有效日期必須在 {formatLatestDate} 之前 + 有效日期必須在 {formatLatestDate} 之前 + Please specify a valid email address. - 請指定一個有效的電子郵件。 + 請指定一個有效的電子郵件。 + A valid float number is expected. - 預期為有效的浮點數字。 + 預期為有效的浮點數字。 + A valid integer number is expected. - 預期為有效的整數。 + 預期為有效的整數。 + Only letters, numbers, spaces and certain punctuation marks are expected. - 預期只有文字、數字、空格和部份標點符號。 + 預期只有文字、數字、空格和部份標點符號。 + This property is required. - 此為必要屬性。 + 此為必要屬性。 + A valid number is expected. - 預期為有效的數字。 + 預期為有效的數字。 + Please enter a valid number between {minimum} and {maximum} - 請輸入一個介於 {minimum} 和 {maximum} 之間的有效數字 + 請輸入一個介於 {minimum} 和 {maximum} 之間的有效數字 + The given subject did not match the pattern ({pattern}) - The given subject did not match the pattern ({pattern}) + The given subject did not match the pattern ({pattern}) + A valid string is expected. - 預期為有效的字串。 + 預期為有效的字串。 + Valid text without any XML tags is expected. - Valid text without any XML tags is expected. + Valid text without any XML tags is expected. + The given subject is not a valid UUID. - The given subject is not a valid UUID. + The given subject is not a valid UUID. + Toggle content dimensions selector - Toggle content dimensions selector + Toggle content dimensions selector + Start with an empty or pre-filled document? - Start with an empty or pre-filled document? + Start with an empty or pre-filled document? + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. - This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. + This {nodeTypeLabel} does not exist yet in {currentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. - You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. + You can create it now, either starting with an empty {nodeTypeLabel} or copying all content from the currently visible {nodeTypeLabel} in {currentDocumentDimensionChoiceText}. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. - Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. + Additionally, there are {numberOfNodesMissingInRootline} ancestor documents which do not exist in the chosen variant either, and which will be created as well. + Create empty - 建立空白 + 建立空白 + Create and copy - 建立並複製 + 建立並複製 + Content - 內容 + 內容 + Toggle menu group - 切換選單群組 + 切換選單群組 + Toggle sticky menu mode - 切換固定選單模式 + 切換固定選單模式 + Do you really want to delete - 您確定想要刪除 + 您確定想要刪除 + This will delete the element - 這將會刪除元素 + 這將會刪除元素 + and it's children - 和它的子項 + 和它的子項 + This action can be undone in the workspace management. - 此動作無法在工作區管理中被還原。 + 此動作無法在工作區管理中被還原。 + Height - 高度 + 高度 + Do you really want to delete - 您確定想要刪除 + 您確定想要刪除 + this element - 此元素 + 此元素 + This will delete the element. - 這將會刪除此元素。 + 這將會刪除此元素。 + This action can be undone in the workspace management. - 此動作無法在工作區管理中被還原。 + 此動作無法在工作區管理中被還原。 + Media - 媒體 + 媒體 + Crop - 裁切 + 裁切 + Width - 寬度 + 寬度 + Missing required property: - 遺失必要屬性: + 遺失必要屬性: + Workspace - 工作區 + 工作區 + Workspaces - 工作區 + 工作區 + An error occurred during saving - 儲存時發生錯誤 + 儲存時發生錯誤 + Reload the page to attempt to fix the problem. - 重新載入頁面以嘗試修復問題。 + 重新載入頁面以嘗試修復問題。 + Reload the backend - 在背景重新載入 + 在背景重新載入 + Reload - 重新載入 + 重新載入 + In-Place - 就地 + 就地 + Raw Content - 原始內容 + 原始內容 + Raw Content Mode - 原始內容模式 + 原始內容模式 + Desktop - 桌面 + 桌面 + Login to - 登入 + 登入 + Authenticating - 驗證中 + 驗證中 + Logout - 登出 + 登出 + The entered username or password was wrong - 使用者名稱或密碼錯誤 + 使用者名稱或密碼錯誤 + Your login has expired. Please log in again. - 登入逾期,請再次登入。 + 登入逾期,請再次登入。 + Welcome to Neos - Welcome to Neos + Welcome to Neos + Go to setup - 前往設定 + 前往設定 + Technical Information - Technical Information + Technical Information + Missing Homepage - 遺失首頁 + 遺失首頁 + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. - Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. + Either no site has been defined, the site does not contain a homepage or the active site couldn't be determined. + You might want to set the site's domain or import a new site in the setup. - You might want to set the site's domain or import a new site in the setup. + You might want to set the site's domain or import a new site in the setup. + Database Error - 資料庫錯誤 + 資料庫錯誤 + There is no database connection yet or the Neos database schema has not been created. - There is no database connection yet or the Neos database schema has not been created. + There is no database connection yet or the Neos database schema has not been created. + Run the setup to configure your database. - Run the setup to configure your database. + Run the setup to configure your database. + Page Not Found - 無法找到網頁 + 無法找到網頁 + Sorry, the page you requested was not found. - 很抱歉,找不到您要求的頁面。 + 很抱歉,找不到您要求的頁面。 + Invalid NodeType - 無效節點類型 + 無效節點類型 + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. - The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. + The configuration of the NodeType that is supposed to be rendered here is not available. Probably you renamed the NodeType and are missing a migration or you simply misspelled it. + Unexpected error while creating node - 建立節點時發生非預期錯誤 + 建立節點時發生非預期錯誤 + Unexpected error while deleting node - 刪除節點時發生非預期錯誤 + 刪除節點時發生非預期錯誤 + Unexpected error while updating node - 更新節點時發生非預期錯誤 + 更新節點時發生非預期錯誤 + Unexpected error while moving node - 移動節點時發生非預期錯誤 + 移動節點時發生非預期錯誤 + Node Tree loading error. - 節點樹讀取錯誤。 + 節點樹讀取錯誤。 + - - The entered username or password was wrong - 使用者名稱或密碼錯誤 "{nodeTypeName}" on page "{pageLabel}" - 「{nodeTypeName}」在頁面「{pageLabel}」 + 「{nodeTypeName}」在頁面「{pageLabel}」 + Nodes - 節點 + 節點 + Show - 顯示 + 顯示 + This node cannot be accessed through a public URL - 此節點無法被公開網址連結 + 此節點無法被公開網址連結 + Node Properties - 節點屬性 + 節點屬性 + Copy {source} to {target} - 複製 {source} 到 {target} + 複製 {source} 到 {target} + Move {source} to {target} - 移動 {source} 到 {target} + 移動 {source} 到 {target} + Please select the position at which you want {source} inserted relative to {target}. - 請選擇想要 {source} 插入 {target} 的相對位置。 + 請選擇想要 {source} 插入 {target} 的相對位置。 + Insert - 插入 + 插入 + Insert mode - 插入模式 + 插入模式 + Choose an Aspect Ratio - 選擇長寬比 + 選擇長寬比 + Bold - 粗體 + 粗體 + Italic - 斜體 + 斜體 + Underline - 底線 + 底線 + Subscript - 下標線 + 下標線 + Superscript - 上標線 + 上標線 + Strikethrough - 刪除線 + 刪除線 + Link - 連結 + 連結 + Ordered list - 項目清單 + 項目清單 + Unordered list - 無排序清單 + 無排序清單 + Align left - 靠左對齊 + 靠左對齊 + Align right - 靠右對齊 + 靠右對齊 + Align center - 置中 + 置中 + Align justify - 分散對齊 + 分散對齊 + Table - 表格 + 表格 + Remove format - 移除格式 + 移除格式 + Outdent - 減少縮排 + 減少縮排 + Indent - 增加縮排 + 增加縮排 + Create new - 新增 + 新增 + No matches found - 未找到相符項目 + 未找到相符項目 + Please enter ###CHARACTERS### more character - 請輸入 ###CHARACTERS### 更多字元 + 請輸入 ###CHARACTERS### 更多字元 + Wrong Credentials - Wrong Credentials + Wrong Credentials + The entered username or password was wrong - 使用者名稱或密碼錯誤 + 使用者名稱或密碼錯誤 + Logged Out - Logged Out + Logged Out + Successfully logged out - Successfully logged out + Successfully logged out + diff --git a/Neos.Neos/Resources/Private/Translations/zh_TW/Modules.xlf b/Neos.Neos/Resources/Private/Translations/zh_TW/Modules.xlf index 7914735d1d6..ed00dcedf7c 100644 --- a/Neos.Neos/Resources/Private/Translations/zh_TW/Modules.xlf +++ b/Neos.Neos/Resources/Private/Translations/zh_TW/Modules.xlf @@ -257,70 +257,6 @@ All changes from workspace "{0}" have been discarded. All changes from workspace "{0}" have been discarded. - - History - History - - - This module provides an overview of all relevant events affecting this Neos installation. - This module provides an overview of all relevant events affecting this Neos installation. - - - Here's what happened recently in Neos - Here's what happened recently in Neos - - - There have not been recorded any events yet which could be displayed in this history. - There have not been recorded any events yet which could be displayed in this history. - - - {0} created the {1} "{2}". - {0} created the {1} "{2}". - - - {0} removed the {1} "{2}". - {0} removed the {1} "{2}". - - - {0} created the variant {1} of the {2} "{3}". - {0} created the variant {1} of the {2} "{3}". - - - {0} modified the {1} "{2}". - {0} modified the {1} "{2}". - - - {0} moved the {1} "{2}". - {0} moved the {1} "{2}". - - - {0} copied the {1} "{2}". - {0} copied the {1} "{2}". - - - {0} renamed the {1} "{2}" to "{3}". - {0} renamed the {1} "{2}" to "{3}". - - - {0} modified content on the {1} "{2}". - {0} modified content on the {1} "{2}". - - - {0} created a new user "{1}" for {2}. - {0} created a new user "{1}" for {2}. - - - {0} deleted the account "{1}" of {2}. - {0} deleted the account "{1}" of {2}. - - - Load More - Load More - - - This node has been removed in the meantime - This node has been removed in the meantime - Administration diff --git a/Neos.Neos/Resources/Public/JavaScript/LastVisitedNode.js b/Neos.Neos/Resources/Public/JavaScript/LastVisitedNode.js deleted file mode 100644 index 2a00c8f7fa2..00000000000 --- a/Neos.Neos/Resources/Public/JavaScript/LastVisitedNode.js +++ /dev/null @@ -1,8 +0,0 @@ -try { - sessionStorage.setItem( - "Neos.Neos.lastVisitedNode", - document - .querySelector("script[data-neos-node]") - .getAttribute("data-neos-node") - ); -} catch (e) {} diff --git a/Neos.Neos/Resources/Public/JavaScript/Main.min.js.map b/Neos.Neos/Resources/Public/JavaScript/Main.min.js.map index bec0e8b2aca..afefdb26e1e 100644 --- a/Neos.Neos/Resources/Public/JavaScript/Main.min.js.map +++ b/Neos.Neos/Resources/Public/JavaScript/Main.min.js.map @@ -1 +1 @@ -{"version":3,"file":"Main.min.js","mappings":";6BAGiEA,EAAOC,QAGhE,WAAc,aAEpB,SAASC,mBAAmBC,GAAO,GAAIC,MAAMC,QAAQF,GAAM,CAAE,IAAK,IAAIG,EAAI,EAAGC,EAAOH,MAAMD,EAAIK,QAASF,EAAIH,EAAIK,OAAQF,IAAOC,EAAKD,GAAKH,EAAIG,GAAM,OAAOC,CAAM,CAAS,OAAOH,MAAMK,KAAKN,EAAQ,CAElM,IAAIO,EAAiBC,OAAOD,eACxBE,EAAiBD,OAAOC,eACxBC,EAAWF,OAAOE,SAClBC,EAAiBH,OAAOG,eACxBC,EAA2BJ,OAAOI,yBAClCC,EAASL,OAAOK,OAChBC,EAAON,OAAOM,KACdC,EAASP,OAAOO,OAEhBC,EAA0B,oBAAZC,SAA2BA,QACzCC,EAAQF,EAAKE,MACbC,EAAYH,EAAKG,UAEhBD,IACHA,EAAQ,SAASA,MAAME,EAAKC,EAAWC,GACrC,OAAOF,EAAIF,MAAMG,EAAWC,EAC9B,GAGGT,IACHA,EAAS,SAASA,OAAOU,GACvB,OAAOA,CACT,GAGGT,IACHA,EAAO,SAASA,KAAKS,GACnB,OAAOA,CACT,GAGGJ,IACHA,EAAY,SAASA,UAAUK,EAAMF,GACnC,OAAO,IAAKG,SAASC,UAAUC,KAAKT,MAAMM,EAAM,CAAC,MAAMI,OAAO7B,mBAAmBuB,KACnF,GAGF,IAAIO,EAAeC,QAAQ7B,MAAMyB,UAAUK,SACvCC,EAAWF,QAAQ7B,MAAMyB,UAAUO,KACnCC,EAAYJ,QAAQ7B,MAAMyB,UAAUS,MAEpCC,EAAoBN,QAAQO,OAAOX,UAAUY,aAC7CC,EAAcT,QAAQO,OAAOX,UAAUc,OACvCC,EAAgBX,QAAQO,OAAOX,UAAUgB,SACzCC,EAAgBb,QAAQO,OAAOX,UAAUkB,SACzCC,EAAaf,QAAQO,OAAOX,UAAUoB,MAEtCC,EAAajB,QAAQkB,OAAOtB,UAAUuB,MAEtCC,EAAkBC,YAAYC,WAElC,SAAStB,QAAQuB,GACf,OAAO,SAAUC,GACf,IAAK,IAAIC,EAAOC,UAAUnD,OAAQiB,EAAOrB,MAAMsD,EAAO,EAAIA,EAAO,EAAI,GAAIE,EAAO,EAAGA,EAAOF,EAAME,IAC9FnC,EAAKmC,EAAO,GAAKD,UAAUC,GAG7B,OAAOvC,EAAMmC,EAAMC,EAAShC,EAC9B,CACF,CAEA,SAAS6B,YAAYE,GACnB,OAAO,WACL,IAAK,IAAIK,EAAQF,UAAUnD,OAAQiB,EAAOrB,MAAMyD,GAAQC,EAAQ,EAAGA,EAAQD,EAAOC,IAChFrC,EAAKqC,GAASH,UAAUG,GAG1B,OAAOxC,EAAUkC,EAAM/B,EACzB,CACF,CAGA,SAASsC,SAASC,EAAKC,GACjBrD,GAIFA,EAAeoD,EAAK,MAItB,IADA,IAAIE,EAAID,EAAMzD,OACP0D,KAAK,CACV,IAAIC,EAAUF,EAAMC,GACpB,GAAuB,iBAAZC,EAAsB,CAC/B,IAAIC,EAAY7B,EAAkB4B,GAC9BC,IAAcD,IAEXtD,EAASoD,KACZA,EAAMC,GAAKE,GAGbD,EAAUC,EAEd,CAEAJ,EAAIG,IAAW,CACjB,CAEA,OAAOH,CACT,CAGA,SAASK,MAAMC,GACb,IAAIC,EAAYrD,EAAO,MAEnBsD,OAAW,EACf,IAAKA,KAAYF,EACXjD,EAAMX,EAAgB4D,EAAQ,CAACE,MACjCD,EAAUC,GAAYF,EAAOE,IAIjC,OAAOD,CACT,CAMA,SAASE,aAAaH,EAAQI,GAC5B,KAAkB,OAAXJ,GAAiB,CACtB,IAAIK,EAAO5D,EAAyBuD,EAAQI,GAC5C,GAAIC,EAAM,CACR,GAAIA,EAAKC,IACP,OAAO3C,QAAQ0C,EAAKC,KAGtB,GAA0B,mBAAfD,EAAKE,MACd,OAAO5C,QAAQ0C,EAAKE,MAExB,CAEAP,EAASxD,EAAewD,EAC1B,CAEA,OAAO,IACT,CAEA,IAAIQ,EAAO9D,EAAO,CAAC,IAAK,OAAQ,UAAW,UAAW,OAAQ,UAAW,QAAS,QAAS,IAAK,MAAO,MAAO,MAAO,QAAS,aAAc,OAAQ,KAAM,SAAU,SAAU,UAAW,SAAU,OAAQ,OAAQ,MAAO,WAAY,UAAW,OAAQ,WAAY,KAAM,YAAa,MAAO,UAAW,MAAO,SAAU,MAAO,MAAO,KAAM,KAAM,UAAW,KAAM,WAAY,aAAc,SAAU,OAAQ,SAAU,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,OAAQ,SAAU,SAAU,KAAM,OAAQ,IAAK,MAAO,QAAS,MAAO,MAAO,QAAS,SAAU,KAAM,OAAQ,MAAO,OAAQ,UAAW,OAAQ,WAAY,QAAS,MAAO,OAAQ,KAAM,WAAY,SAAU,SAAU,IAAK,UAAW,MAAO,WAAY,IAAK,KAAM,KAAM,OAAQ,IAAK,OAAQ,UAAW,SAAU,SAAU,QAAS,SAAU,SAAU,OAAQ,SAAU,SAAU,QAAS,MAAO,UAAW,MAAO,QAAS,QAAS,KAAM,WAAY,WAAY,QAAS,KAAM,QAAS,OAAQ,KAAM,QAAS,KAAM,IAAK,KAAM,MAAO,QAAS,QAGj+B+D,EAAM/D,EAAO,CAAC,MAAO,IAAK,WAAY,cAAe,eAAgB,eAAgB,gBAAiB,mBAAoB,SAAU,WAAY,OAAQ,OAAQ,UAAW,SAAU,OAAQ,IAAK,QAAS,WAAY,QAAS,QAAS,OAAQ,iBAAkB,SAAU,OAAQ,WAAY,QAAS,OAAQ,UAAW,UAAW,WAAY,iBAAkB,OAAQ,OAAQ,QAAS,SAAU,SAAU,OAAQ,WAAY,QAAS,OAAQ,QAAS,OAAQ,UAEzcgE,EAAahE,EAAO,CAAC,UAAW,gBAAiB,sBAAuB,cAAe,mBAAoB,oBAAqB,oBAAqB,iBAAkB,UAAW,UAAW,UAAW,UAAW,UAAW,iBAAkB,UAAW,cAAe,eAAgB,WAAY,eAAgB,qBAAsB,cAAe,SAAU,iBAMrWiE,EAAgBjE,EAAO,CAAC,UAAW,gBAAiB,SAAU,UAAW,eAAgB,UAAW,YAAa,mBAAoB,iBAAkB,gBAAiB,gBAAiB,gBAAiB,QAAS,YAAa,OAAQ,eAAgB,YAAa,UAAW,gBAAiB,SAAU,MAAO,aAAc,UAAW,QAE3UkE,EAASlE,EAAO,CAAC,OAAQ,WAAY,SAAU,UAAW,QAAS,SAAU,KAAM,aAAc,gBAAiB,KAAM,KAAM,QAAS,UAAW,WAAY,QAAS,OAAQ,KAAM,SAAU,QAAS,SAAU,OAAQ,OAAQ,UAAW,SAAU,MAAO,QAAS,MAAO,SAAU,eAIxRmE,EAAmBnE,EAAO,CAAC,UAAW,cAAe,aAAc,WAAY,YAAa,UAAW,UAAW,SAAU,SAAU,QAAS,YAAa,aAAc,iBAAkB,cAAe,SAE3MoE,EAAOpE,EAAO,CAAC,UAEfqE,EAASrE,EAAO,CAAC,SAAU,SAAU,QAAS,MAAO,iBAAkB,eAAgB,uBAAwB,WAAY,aAAc,UAAW,SAAU,UAAW,cAAe,cAAe,UAAW,OAAQ,QAAS,QAAS,QAAS,OAAQ,UAAW,WAAY,eAAgB,SAAU,cAAe,WAAY,WAAY,UAAW,MAAO,WAAY,0BAA2B,wBAAyB,WAAY,YAAa,UAAW,eAAgB,OAAQ,MAAO,UAAW,SAAU,SAAU,OAAQ,OAAQ,WAAY,KAAM,YAAa,YAAa,QAAS,OAAQ,QAAS,OAAQ,OAAQ,UAAW,OAAQ,MAAO,MAAO,YAAa,QAAS,SAAU,MAAO,YAAa,WAAY,QAAS,OAAQ,UAAW,aAAc,SAAU,OAAQ,UAAW,UAAW,cAAe,cAAe,SAAU,UAAW,UAAW,aAAc,WAAY,MAAO,WAAY,MAAO,WAAY,OAAQ,OAAQ,UAAW,aAAc,QAAS,WAAY,QAAS,OAAQ,QAAS,OAAQ,UAAW,QAAS,MAAO,SAAU,OAAQ,QAAS,UAAW,WAAY,QAAS,YAAa,OAAQ,SAAU,SAAU,QAAS,QAAS,UAEjpCsE,EAAQtE,EAAO,CAAC,gBAAiB,aAAc,WAAY,qBAAsB,SAAU,gBAAiB,gBAAiB,UAAW,gBAAiB,iBAAkB,QAAS,OAAQ,KAAM,QAAS,OAAQ,gBAAiB,YAAa,YAAa,QAAS,sBAAuB,8BAA+B,gBAAiB,kBAAmB,KAAM,KAAM,IAAK,KAAM,KAAM,kBAAmB,YAAa,UAAW,UAAW,MAAO,WAAY,YAAa,MAAO,OAAQ,eAAgB,YAAa,SAAU,cAAe,cAAe,gBAAiB,cAAe,YAAa,mBAAoB,eAAgB,aAAc,eAAgB,cAAe,KAAM,KAAM,KAAM,KAAM,aAAc,WAAY,gBAAiB,oBAAqB,SAAU,OAAQ,KAAM,kBAAmB,KAAM,MAAO,IAAK,KAAM,KAAM,KAAM,KAAM,UAAW,YAAa,aAAc,WAAY,OAAQ,eAAgB,iBAAkB,eAAgB,mBAAoB,iBAAkB,QAAS,aAAc,aAAc,eAAgB,eAAgB,cAAe,cAAe,mBAAoB,YAAa,MAAO,OAAQ,QAAS,SAAU,OAAQ,MAAO,OAAQ,aAAc,SAAU,WAAY,UAAW,QAAS,SAAU,cAAe,SAAU,WAAY,cAAe,OAAQ,aAAc,sBAAuB,mBAAoB,eAAgB,SAAU,gBAAiB,sBAAuB,iBAAkB,IAAK,KAAM,KAAM,SAAU,OAAQ,OAAQ,cAAe,YAAa,UAAW,SAAU,SAAU,QAAS,OAAQ,kBAAmB,mBAAoB,mBAAoB,eAAgB,cAAe,eAAgB,cAAe,aAAc,eAAgB,mBAAoB,oBAAqB,iBAAkB,kBAAmB,oBAAqB,iBAAkB,SAAU,eAAgB,QAAS,eAAgB,iBAAkB,WAAY,UAAW,UAAW,YAAa,cAAe,kBAAmB,iBAAkB,aAAc,OAAQ,KAAM,KAAM,UAAW,SAAU,UAAW,aAAc,UAAW,aAAc,gBAAiB,gBAAiB,QAAS,eAAgB,OAAQ,eAAgB,mBAAoB,mBAAoB,IAAK,KAAM,KAAM,QAAS,IAAK,KAAM,KAAM,IAAK,eAE5uEuE,EAAWvE,EAAO,CAAC,SAAU,cAAe,QAAS,WAAY,QAAS,eAAgB,cAAe,aAAc,aAAc,QAAS,MAAO,UAAW,eAAgB,WAAY,QAAS,QAAS,SAAU,OAAQ,KAAM,UAAW,SAAU,gBAAiB,SAAU,SAAU,iBAAkB,YAAa,WAAY,cAAe,UAAW,UAAW,gBAAiB,WAAY,WAAY,OAAQ,WAAY,WAAY,aAAc,UAAW,SAAU,SAAU,cAAe,gBAAiB,uBAAwB,YAAa,YAAa,aAAc,WAAY,iBAAkB,iBAAkB,YAAa,UAAW,QAAS,UAEvpBwE,EAAMxE,EAAO,CAAC,aAAc,SAAU,cAAe,YAAa,gBAGlEyE,EAAgBxE,EAAK,6BACrByE,EAAWzE,EAAK,yBAChB0E,EAAY1E,EAAK,8BACjB2E,EAAY3E,EAAK,kBACjB4E,EAAiB5E,EAAK,yFAEtB6E,EAAoB7E,EAAK,yBACzB8E,EAAkB9E,EAAK,+DAGvB+E,EAA4B,mBAAXC,QAAoD,iBAApBA,OAAOC,SAAwB,SAAUC,GAAO,cAAcA,CAAK,EAAI,SAAUA,GAAO,OAAOA,GAAyB,mBAAXF,QAAyBE,EAAIC,cAAgBH,QAAUE,IAAQF,OAAOpE,UAAY,gBAAkBsE,CAAK,EAE3Q,SAASE,qBAAqBlG,GAAO,GAAIC,MAAMC,QAAQF,GAAM,CAAE,IAAK,IAAIG,EAAI,EAAGC,EAAOH,MAAMD,EAAIK,QAASF,EAAIH,EAAIK,OAAQF,IAAOC,EAAKD,GAAKH,EAAIG,GAAM,OAAOC,CAAM,CAAS,OAAOH,MAAMK,KAAKN,EAAQ,CAEpM,IAAImG,EAAY,SAASA,YACvB,MAAyB,oBAAXC,OAAyB,KAAOA,MAChD,EAUIC,EAA4B,SAASA,0BAA0BC,EAAcC,GAC/E,GAAoF,iBAAvD,IAAjBD,EAA+B,YAAcT,EAAQS,KAAoE,mBAA9BA,EAAaE,aAClH,OAAO,KAMT,IAAIC,EAAS,KACTC,EAAY,wBACZH,EAASI,eAAiBJ,EAASI,cAAcC,aAAaF,KAChED,EAASF,EAASI,cAAcE,aAAaH,IAG/C,IAAII,EAAa,aAAeL,EAAS,IAAMA,EAAS,IAExD,IACE,OAAOH,EAAaE,aAAaM,EAAY,CAC3CC,WAAY,SAASA,WAAWC,GAC9B,OAAOA,CACT,GAEJ,CAAE,MAAOC,GAKP,OADAC,QAAQC,KAAK,uBAAyBL,EAAa,0BAC5C,IACT,CACF,EAEA,SAASM,kBACP,IAAIhB,EAAS5C,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK2C,IAE7EmB,EAAY,SAASA,UAAUC,GACjC,OAAOH,gBAAgBG,EACzB,EAcA,GARAD,EAAUE,QAAU,QAMpBF,EAAUG,QAAU,IAEfrB,IAAWA,EAAOG,UAAyC,IAA7BH,EAAOG,SAASmB,SAKjD,OAFAJ,EAAUK,aAAc,EAEjBL,EAGT,IAAIM,EAAmBxB,EAAOG,SAE1BA,EAAWH,EAAOG,SAClBsB,EAAmBzB,EAAOyB,iBAC1BC,EAAsB1B,EAAO0B,oBAC7BC,EAAO3B,EAAO2B,KACdC,EAAU5B,EAAO4B,QACjBC,EAAa7B,EAAO6B,WACpBC,EAAuB9B,EAAO+B,aAC9BA,OAAwCd,IAAzBa,EAAqC9B,EAAO+B,cAAgB/B,EAAOgC,gBAAkBF,EACpGG,EAAOjC,EAAOiC,KACdC,EAAUlC,EAAOkC,QACjBC,EAAYnC,EAAOmC,UACnBjC,EAAeF,EAAOE,aAGtBkC,EAAmBR,EAAQtG,UAE3B+G,EAAYnE,aAAakE,EAAkB,aAC3CE,EAAiBpE,aAAakE,EAAkB,eAChDG,EAAgBrE,aAAakE,EAAkB,cAC/CI,EAAgBtE,aAAakE,EAAkB,cAQnD,GAAmC,mBAAxBV,EAAoC,CAC7C,IAAIe,GAAWtC,EAASuC,cAAc,YAClCD,GAASE,SAAWF,GAASE,QAAQC,gBACvCzC,EAAWsC,GAASE,QAAQC,cAEhC,CAEA,IAAIC,GAAqB5C,EAA0BC,EAAcsB,GAC7DsB,GAAYD,IAAsBE,GAAsBF,GAAmBlC,WAAW,IAAM,GAE5FqC,GAAY7C,EACZ8C,GAAiBD,GAAUC,eAC3BC,GAAqBF,GAAUE,mBAC/BC,GAAuBH,GAAUG,qBACjCC,GAAyBJ,GAAUI,uBACnCC,GAAa7B,EAAiB6B,WAG9BC,GAAe,CAAC,EACpB,IACEA,GAAexF,MAAMqC,GAAUmD,aAAenD,EAASmD,aAAe,CAAC,CACzE,CAAE,MAAOzC,GAAI,CAEb,IAAI0C,GAAQ,CAAC,EAKbrC,EAAUK,YAAc0B,SAA+D,IAAtCA,GAAeO,oBAAuD,IAAjBF,GAEtG,IAAIG,GAAmBvE,EACnBwE,GAAcvE,EACdwE,GAAevE,EACfwE,GAAevE,EACfwE,GAAuBtE,EACvBuE,GAAqBtE,EACrBuE,GAAoBzE,EASpB0E,GAAe,KACfC,GAAuBzG,SAAS,CAAC,EAAG,GAAGhC,OAAOsE,qBAAqBvB,GAAOuB,qBAAqBtB,GAAMsB,qBAAqBrB,GAAaqB,qBAAqBnB,GAASmB,qBAAqBjB,KAG1LqF,GAAe,KACfC,GAAuB3G,SAAS,CAAC,EAAG,GAAGhC,OAAOsE,qBAAqBhB,GAASgB,qBAAqBf,GAAQe,qBAAqBd,GAAWc,qBAAqBb,KAG9JmF,GAAc,KAGdC,GAAc,KAGdC,IAAkB,EAGlBC,IAAkB,EAGlBC,IAA0B,EAK1BC,IAAqB,EAGrBC,IAAiB,EAGjBC,IAAa,EAIbC,IAAa,EAMbC,IAAa,EAIbC,IAAsB,EAWtBC,IAAoB,EAIpBhC,IAAsB,EAGtBiC,IAAe,EAGfC,IAAe,EAIfC,IAAW,EAGXC,GAAe,CAAC,EAGhBC,GAAkB5H,SAAS,CAAC,EAAG,CAAC,iBAAkB,QAAS,WAAY,OAAQ,gBAAiB,OAAQ,SAAU,OAAQ,KAAM,KAAM,KAAM,KAAM,QAAS,UAAW,WAAY,WAAY,YAAa,SAAU,QAAS,MAAO,WAAY,QAAS,QAAS,QAAS,QAG5Q6H,GAAgB,KAChBC,GAAwB9H,SAAS,CAAC,EAAG,CAAC,QAAS,QAAS,MAAO,SAAU,QAAS,UAGlF+H,GAAsB,KACtBC,GAA8BhI,SAAS,CAAC,EAAG,CAAC,MAAO,QAAS,MAAO,KAAM,QAAS,OAAQ,UAAW,cAAe,UAAW,QAAS,QAAS,QAAS,UAG1JiI,GAAS,KAKTC,GAAcvF,EAASuC,cAAc,QAQrCiD,GAAe,SAASA,aAAaC,GACnCH,IAAUA,KAAWG,IAKpBA,GAAqE,iBAA9C,IAARA,EAAsB,YAAcnG,EAAQmG,MAC9DA,EAAM,CAAC,GAITA,EAAM9H,MAAM8H,GAGZ5B,GAAe,iBAAkB4B,EAAMpI,SAAS,CAAC,EAAGoI,EAAI5B,cAAgBC,GACxEC,GAAe,iBAAkB0B,EAAMpI,SAAS,CAAC,EAAGoI,EAAI1B,cAAgBC,GACxEoB,GAAsB,sBAAuBK,EAAMpI,SAASM,MAAM0H,IAA8BI,EAAIC,mBAAqBL,GACzHH,GAAgB,sBAAuBO,EAAMpI,SAASM,MAAMwH,IAAwBM,EAAIE,mBAAqBR,GAC7GlB,GAAc,gBAAiBwB,EAAMpI,SAAS,CAAC,EAAGoI,EAAIxB,aAAe,CAAC,EACtEC,GAAc,gBAAiBuB,EAAMpI,SAAS,CAAC,EAAGoI,EAAIvB,aAAe,CAAC,EACtEc,GAAe,iBAAkBS,GAAMA,EAAIT,aAC3Cb,IAA0C,IAAxBsB,EAAItB,gBACtBC,IAA0C,IAAxBqB,EAAIrB,gBACtBC,GAA0BoB,EAAIpB,0BAA2B,EACzDC,GAAqBmB,EAAInB,qBAAsB,EAC/CC,GAAiBkB,EAAIlB,iBAAkB,EACvCG,GAAae,EAAIf,aAAc,EAC/BC,GAAsBc,EAAId,sBAAuB,EACjDC,IAA8C,IAA1Ba,EAAIb,kBACxBhC,GAAsB6C,EAAI7C,sBAAuB,EACjD6B,GAAagB,EAAIhB,aAAc,EAC/BI,IAAoC,IAArBY,EAAIZ,aACnBC,IAAoC,IAArBW,EAAIX,aACnBC,GAAWU,EAAIV,WAAY,EAC3BnB,GAAoB6B,EAAIG,oBAAsBhC,GAC1CU,KACFF,IAAkB,GAGhBO,KACFD,IAAa,GAIXM,KACFnB,GAAexG,SAAS,CAAC,EAAG,GAAGhC,OAAOsE,qBAAqBjB,KAC3DqF,GAAe,IACW,IAAtBiB,GAAa5G,OACff,SAASwG,GAAczF,GACvBf,SAAS0G,GAAcpF,KAGA,IAArBqG,GAAa3G,MACfhB,SAASwG,GAAcxF,GACvBhB,SAAS0G,GAAcnF,GACvBvB,SAAS0G,GAAcjF,KAGO,IAA5BkG,GAAa1G,aACfjB,SAASwG,GAAcvF,GACvBjB,SAAS0G,GAAcnF,GACvBvB,SAAS0G,GAAcjF,KAGG,IAAxBkG,GAAaxG,SACfnB,SAASwG,GAAcrF,GACvBnB,SAAS0G,GAAclF,GACvBxB,SAAS0G,GAAcjF,KAKvB2G,EAAII,WACFhC,KAAiBC,KACnBD,GAAelG,MAAMkG,KAGvBxG,SAASwG,GAAc4B,EAAII,WAGzBJ,EAAIK,WACF/B,KAAiBC,KACnBD,GAAepG,MAAMoG,KAGvB1G,SAAS0G,GAAc0B,EAAIK,WAGzBL,EAAIC,mBACNrI,SAAS+H,GAAqBK,EAAIC,mBAIhCZ,KACFjB,GAAa,UAAW,GAItBU,IACFlH,SAASwG,GAAc,CAAC,OAAQ,OAAQ,SAItCA,GAAakC,QACf1I,SAASwG,GAAc,CAAC,iBACjBI,GAAY+B,OAKjB1L,GACFA,EAAOmL,GAGTH,GAASG,EACX,EAEIQ,GAAiC5I,SAAS,CAAC,EAAG,CAAC,KAAM,KAAM,KAAM,KAAM,UAEvE6I,GAA0B7I,SAAS,CAAC,EAAG,CAAC,gBAAiB,OAAQ,QAAS,mBAK1E8I,GAAe9I,SAAS,CAAC,EAAGgB,GAChChB,SAAS8I,GAAc7H,GACvBjB,SAAS8I,GAAc5H,GAEvB,IAAI6H,GAAkB/I,SAAS,CAAC,EAAGmB,GACnCnB,SAAS+I,GAAiB3H,GAE1B,IAAI4H,GAAmB,qCACnBC,GAAgB,6BAChBC,GAAiB,+BAUjBC,GAAuB,SAASA,qBAAqB/I,GACvD,IAAIgJ,EAASpE,EAAc5E,GAItBgJ,GAAWA,EAAOC,UACrBD,EAAS,CACPE,aAAcJ,GACdG,QAAS,aAIb,IAAIA,EAAU7K,EAAkB4B,EAAQiJ,SACpCE,EAAgB/K,EAAkB4K,EAAOC,SAE7C,GAAIjJ,EAAQkJ,eAAiBL,GAI3B,OAAIG,EAAOE,eAAiBJ,GACP,QAAZG,EAMLD,EAAOE,eAAiBN,GACP,QAAZK,IAAwC,mBAAlBE,GAAsCX,GAA+BW,IAK7FC,QAAQV,GAAaO,IAG9B,GAAIjJ,EAAQkJ,eAAiBN,GAI3B,OAAII,EAAOE,eAAiBJ,GACP,SAAZG,EAKLD,EAAOE,eAAiBL,GACP,SAAZI,GAAsBR,GAAwBU,GAKhDC,QAAQT,GAAgBM,IAGjC,GAAIjJ,EAAQkJ,eAAiBJ,GAAgB,CAI3C,GAAIE,EAAOE,eAAiBL,KAAkBJ,GAAwBU,GACpE,OAAO,EAGT,GAAIH,EAAOE,eAAiBN,KAAqBJ,GAA+BW,GAC9E,OAAO,EAOT,IAAIE,EAA2BzJ,SAAS,CAAC,EAAG,CAAC,QAAS,QAAS,OAAQ,IAAK,WAI5E,OAAQ+I,GAAgBM,KAAaI,EAAyBJ,KAAaP,GAAaO,GAC1F,CAKA,OAAO,CACT,EAOIK,GAAe,SAASA,aAAaC,GACvCrL,EAAUoF,EAAUG,QAAS,CAAEzD,QAASuJ,IACxC,IACEA,EAAKC,WAAWC,YAAYF,EAC9B,CAAE,MAAOtG,GACP,IACEsG,EAAKG,UAAYxE,EACnB,CAAE,MAAOjC,GACPsG,EAAKI,QACP,CACF,CACF,EAQIC,GAAmB,SAASA,iBAAiBC,EAAMN,GACrD,IACErL,EAAUoF,EAAUG,QAAS,CAC3BqG,UAAWP,EAAKQ,iBAAiBF,GACjCvN,KAAMiN,GAEV,CAAE,MAAOtG,GACP/E,EAAUoF,EAAUG,QAAS,CAC3BqG,UAAW,KACXxN,KAAMiN,GAEV,CAEAA,EAAKS,gBAAgBH,EACvB,EAQII,GAAgB,SAASA,cAAcC,GAEzC,IAAIC,OAAM,EACNC,OAAoB,EAExB,GAAIpD,GACFkD,EAAQ,oBAAsBA,MACzB,CAEL,IAAIG,EAAU9L,EAAY2L,EAAO,eACjCE,EAAoBC,GAAWA,EAAQ,EACzC,CAEA,IAAIC,EAAerF,GAAqBA,GAAmBlC,WAAWmH,GAASA,EAE/E,IACEC,GAAM,IAAI5F,GAAYgG,gBAAgBD,EAAc,YACtD,CAAE,MAAOrH,GAAI,CAGb,IAAKkH,IAAQA,EAAIK,gBAAiB,CAEhC,IACIC,GAFJN,EAAM9E,GAAeO,mBAAmB,KAExB6E,KAEhBA,EAAKjB,WAAWC,YAAYgB,EAAKjB,WAAWkB,mBAC5CD,EAAKf,UAAYY,CACnB,CAOA,OALIJ,GAASE,GACXD,EAAIM,KAAKE,aAAapI,EAASqI,eAAeR,GAAoBD,EAAIM,KAAKI,WAAW,IAAM,MAIvFtF,GAAqBuF,KAAKX,EAAKrD,GAAiB,OAAS,QAAQ,EAC1E,EAQIiE,GAAkB,SAASA,gBAAgBxH,GAC7C,OAAO+B,GAAmBwF,KAAKvH,EAAKyB,eAAiBzB,EAAMA,EAAMU,EAAW+G,aAAe/G,EAAWgH,aAAehH,EAAWiH,WAAW,WACzI,OAAOjH,EAAWkH,aACpB,IAAG,EACL,EAQIC,GAAe,SAASA,aAAaC,GACvC,QAAIA,aAAehH,GAAQgH,aAAe/G,GAId,iBAAjB+G,EAAIC,UAAoD,iBAApBD,EAAIE,aAAuD,mBAApBF,EAAI5B,aAAgC4B,EAAIG,sBAAsBrH,GAAgD,mBAAxBkH,EAAIrB,iBAA8D,mBAArBqB,EAAII,cAA2D,iBAArBJ,EAAInC,cAAyD,mBAArBmC,EAAIV,aAKjT,EAQIe,GAAU,SAASA,QAAQvL,GAC7B,MAAuE,iBAA/C,IAAT4D,EAAuB,YAAclC,EAAQkC,IAAsB5D,aAAkB4D,EAAO5D,GAA8E,iBAAjD,IAAXA,EAAyB,YAAc0B,EAAQ1B,KAAoD,iBAApBA,EAAOuD,UAAoD,iBAApBvD,EAAOmL,QAC5P,EAUIK,GAAe,SAASA,aAAaC,EAAYC,EAAaC,GAC3DnG,GAAMiG,IAIX/N,EAAa8H,GAAMiG,IAAa,SAAUG,GACxCA,EAAKjB,KAAKxH,EAAWuI,EAAaC,EAAMjE,GAC1C,GACF,EAYImE,GAAoB,SAASA,kBAAkBH,GACjD,IAAI9G,OAAU,EAMd,GAHA4G,GAAa,yBAA0BE,EAAa,MAGhDT,GAAaS,GAEf,OADAvC,GAAauC,IACN,EAIT,GAAItN,EAAYsN,EAAYP,SAAU,mBAEpC,OADAhC,GAAauC,IACN,EAIT,IAAI5C,EAAU7K,EAAkByN,EAAYP,UAS5C,GANAK,GAAa,sBAAuBE,EAAa,CAC/C5C,QAASA,EACTgD,YAAa7F,MAIVsF,GAAQG,EAAYnB,sBAAwBgB,GAAQG,EAAY9G,WAAa2G,GAAQG,EAAY9G,QAAQ2F,qBAAuB3L,EAAW,UAAW8M,EAAYK,YAAcnN,EAAW,UAAW8M,EAAYN,aAErN,OADAjC,GAAauC,IACN,EAIT,IAAKzF,GAAa6C,IAAYzC,GAAYyC,GAAU,CAElD,GAAI5B,KAAiBG,GAAgByB,GAInC,IAHA,IAAIO,EAAa5E,EAAciH,GAC3BhB,EAAalG,EAAckH,GAEtB1P,EADQ0O,EAAWxO,OACF,EAAGF,GAAK,IAAKA,EACrCqN,EAAWmB,aAAalG,EAAUoG,EAAW1O,IAAI,GAAOuI,EAAemH,IAK3E,OADAvC,GAAauC,IACN,CACT,CAGA,OAAIA,aAAuB7H,IAAY+E,GAAqB8C,IAC1DvC,GAAauC,IACN,GAGQ,aAAZ5C,GAAsC,YAAZA,IAA0BlK,EAAW,uBAAwB8M,EAAYK,YAMpGrF,IAA+C,IAAzBgF,EAAYnI,WAEpCqB,EAAU8G,EAAYN,YACtBxG,EAAUtG,EAAcsG,EAASc,GAAkB,KACnDd,EAAUtG,EAAcsG,EAASe,GAAa,KAC1C+F,EAAYN,cAAgBxG,IAC9B7G,EAAUoF,EAAUG,QAAS,CAAEzD,QAAS6L,EAAYpH,cACpDoH,EAAYN,YAAcxG,IAK9B4G,GAAa,wBAAyBE,EAAa,OAE5C,IAnBLvC,GAAauC,IACN,EAmBX,EAWIM,GAAoB,SAASA,kBAAkBC,EAAOC,EAAQ3L,GAEhE,GAAI0G,KAA4B,OAAXiF,GAA8B,SAAXA,KAAuB3L,KAAS6B,GAAY7B,KAASoH,IAC3F,OAAO,EAOT,GAAInB,IAAmB5H,EAAWgH,GAAcsG,SAAgB,GAAI3F,IAAmB3H,EAAWiH,GAAcqG,QAAgB,KAAK/F,GAAa+F,IAAW5F,GAAY4F,GACvK,OAAO,EAGF,GAAI1E,GAAoB0E,SAAgB,GAAItN,EAAWoH,GAAmB1H,EAAciC,EAAOwF,GAAoB,WAAa,GAAgB,QAAXmG,GAA+B,eAAXA,GAAsC,SAAXA,GAAgC,WAAVD,GAAwD,IAAlCzN,EAAc+B,EAAO,WAAkB+G,GAAc2E,GAAe,GAAIxF,KAA4B7H,EAAWkH,GAAsBxH,EAAciC,EAAOwF,GAAoB,WAAa,GAAKxF,EACra,OAAO,CACT,CAEA,OAAO,CACT,EAYI4L,GAAsB,SAASA,oBAAoBT,GACrD,IAAIU,OAAO,EACP7L,OAAQ,EACR2L,OAAS,EACTtM,OAAI,EAER4L,GAAa,2BAA4BE,EAAa,MAEtD,IAAIL,EAAaK,EAAYL,WAI7B,GAAKA,EAAL,CAIA,IAAIgB,EAAY,CACdC,SAAU,GACVC,UAAW,GACXC,UAAU,EACVC,kBAAmBtG,IAKrB,IAHAvG,EAAIyL,EAAWnP,OAGR0D,KAAK,CAEV,IAAI8M,EADJN,EAAOf,EAAWzL,GAEd8J,EAAOgD,EAAMhD,KACbX,EAAe2D,EAAM3D,aAazB,GAXAxI,EAAQ7B,EAAW0N,EAAK7L,OACxB2L,EAASjO,EAAkByL,GAG3B2C,EAAUC,SAAWJ,EACrBG,EAAUE,UAAYhM,EACtB8L,EAAUG,UAAW,EACrBH,EAAUM,mBAAgBzJ,EAC1BsI,GAAa,wBAAyBE,EAAaW,GACnD9L,EAAQ8L,EAAUE,WAEdF,EAAUM,gBAKdlD,GAAiBC,EAAMgC,GAGlBW,EAAUG,UAKf,GAAI5N,EAAW,OAAQ2B,GACrBkJ,GAAiBC,EAAMgC,OADzB,CAMIhF,KACFnG,EAAQjC,EAAciC,EAAOmF,GAAkB,KAC/CnF,EAAQjC,EAAciC,EAAOoF,GAAa,MAI5C,IAAIsG,EAAQP,EAAYP,SAAShN,cACjC,GAAK6N,GAAkBC,EAAOC,EAAQ3L,GAKtC,IACMwI,EACF2C,EAAYkB,eAAe7D,EAAcW,EAAMnJ,GAG/CmL,EAAYJ,aAAa5B,EAAMnJ,GAGjC1C,EAASsF,EAAUG,QACrB,CAAE,MAAOR,GAAI,CAxBb,CAyBF,CAGA0I,GAAa,0BAA2BE,EAAa,KAxErD,CAyEF,EAOImB,GAAqB,SAASA,mBAAmBC,GACnD,IAAIC,OAAa,EACbC,EAAiBpC,GAAgBkC,GAKrC,IAFAtB,GAAa,0BAA2BsB,EAAU,MAE3CC,EAAaC,EAAeC,YAEjCzB,GAAa,yBAA0BuB,EAAY,MAG/ClB,GAAkBkB,KAKlBA,EAAWnI,mBAAmBlB,GAChCmJ,mBAAmBE,EAAWnI,SAIhCuH,GAAoBY,IAItBvB,GAAa,yBAA0BsB,EAAU,KACnD,EAuQA,OA7PA3J,EAAU+J,SAAW,SAAUnD,EAAOlC,GACpC,IAAIyC,OAAO,EACP6C,OAAe,EACfzB,OAAc,EACd0B,OAAU,EACVC,OAAa,EASjB,GALKtD,IACHA,EAAQ,eAIW,iBAAVA,IAAuBwB,GAAQxB,GAAQ,CAEhD,GAA8B,mBAAnBA,EAAMuD,SACf,MAAMvO,EAAgB,8BAGtB,GAAqB,iBADrBgL,EAAQA,EAAMuD,YAEZ,MAAMvO,EAAgB,kCAG5B,CAGA,IAAKoE,EAAUK,YAAa,CAC1B,GAAqC,WAAjC9B,EAAQO,EAAOsL,eAA6D,mBAAxBtL,EAAOsL,aAA6B,CAC1F,GAAqB,iBAAVxD,EACT,OAAO9H,EAAOsL,aAAaxD,GAG7B,GAAIwB,GAAQxB,GACV,OAAO9H,EAAOsL,aAAaxD,EAAMR,UAErC,CAEA,OAAOQ,CACT,CAeA,GAZKnD,IACHgB,GAAaC,GAIf1E,EAAUG,QAAU,GAGC,iBAAVyG,IACT5C,IAAW,GAGTA,SAAiB,GAAI4C,aAAiBnG,EAKV,KAD9BuJ,GADA7C,EAAOR,GAAc,kBACDjF,cAAcS,WAAWyE,GAAO,IACnCxG,UAA4C,SAA1B4J,EAAahC,UAGX,SAA1BgC,EAAahC,SADtBb,EAAO6C,EAKP7C,EAAKkD,YAAYL,OAEd,CAEL,IAAKrG,KAAeJ,KAAuBC,KAEnB,IAAxBoD,EAAMtL,QAAQ,KACZ,OAAOqG,IAAsBE,GAAsBF,GAAmBlC,WAAWmH,GAASA,EAO5F,KAHAO,EAAOR,GAAcC,IAInB,OAAOjD,GAAa,KAAO/B,EAE/B,CAGIuF,GAAQzD,IACVsC,GAAamB,EAAKmD,YAOpB,IAHA,IAAIC,EAAe9C,GAAgBzD,GAAW4C,EAAQO,GAG/CoB,EAAcgC,EAAaT,YAEH,IAAzBvB,EAAYnI,UAAkBmI,IAAgB0B,GAK9CvB,GAAkBH,KAKlBA,EAAY9G,mBAAmBlB,GACjCmJ,GAAmBnB,EAAY9G,SAIjCuH,GAAoBT,GAEpB0B,EAAU1B,GAMZ,GAHA0B,EAAU,KAGNjG,GACF,OAAO4C,EAIT,GAAIjD,GAAY,CACd,GAAIC,GAGF,IAFAsG,EAAahI,GAAuBsF,KAAKL,EAAKzF,eAEvCyF,EAAKmD,YAEVJ,EAAWG,YAAYlD,EAAKmD,iBAG9BJ,EAAa/C,EAcf,OAXItD,KAQFqG,EAAa/H,GAAWqF,KAAKlH,EAAkB4J,GAAY,IAGtDA,CACT,CAEA,IAAIM,EAAiBhH,GAAiB2D,EAAKf,UAAYe,EAAKyB,UAQ5D,OALIrF,KACFiH,EAAiBrP,EAAcqP,EAAgBjI,GAAkB,KACjEiI,EAAiBrP,EAAcqP,EAAgBhI,GAAa,MAGvDb,IAAsBE,GAAsBF,GAAmBlC,WAAW+K,GAAkBA,CACrG,EAQAxK,EAAUyK,UAAY,SAAU/F,GAC9BD,GAAaC,GACbjB,IAAa,CACf,EAOAzD,EAAU0K,YAAc,WACtBnG,GAAS,KACTd,IAAa,CACf,EAYAzD,EAAU2K,iBAAmB,SAAUC,EAAK3B,EAAM7L,GAE3CmH,IACHE,GAAa,CAAC,GAGhB,IAAIqE,EAAQhO,EAAkB8P,GAC1B7B,EAASjO,EAAkBmO,GAC/B,OAAOJ,GAAkBC,EAAOC,EAAQ3L,EAC1C,EASA4C,EAAU6K,QAAU,SAAUvC,EAAYwC,GACZ,mBAAjBA,IAIXzI,GAAMiG,GAAcjG,GAAMiG,IAAe,GACzC1N,EAAUyH,GAAMiG,GAAawC,GAC/B,EASA9K,EAAU+K,WAAa,SAAUzC,GAC3BjG,GAAMiG,IACR5N,EAAS2H,GAAMiG,GAEnB,EAQAtI,EAAUgL,YAAc,SAAU1C,GAC5BjG,GAAMiG,KACRjG,GAAMiG,GAAc,GAExB,EAOAtI,EAAUiL,eAAiB,WACzB5I,GAAQ,CAAC,CACX,EAEOrC,CACT,CAIA,OAFaF,iBAIf,CAvyCkFoL,sBCHlF,OAaA,SAAYC,EAAQD,GAEnB,aAE6D,iBAAnB3S,EAAOC,QAShDD,EAAOC,QAAU2S,EAAOlM,SACvBiM,EAASC,GAAQ,GACjB,SAAUC,GACT,IAAMA,EAAEnM,SACP,MAAM,IAAIoM,MAAO,4CAElB,OAAOH,EAASE,EACjB,EAEDF,EAASC,EAIT,CA1BF,CA0BuB,oBAAXrM,OAAyBA,OAASwM,MAAM,SAAUxM,EAAQyM,GAMtE,aAEA,IAAI7S,EAAM,GAEN8S,EAAWtS,OAAOG,eAElBoS,EAAQ/S,EAAI+S,MAEZC,EAAOhT,EAAIgT,KAAO,SAAUlP,GAC/B,OAAO9D,EAAIgT,KAAKlE,KAAMhL,EACvB,EAAI,SAAUA,GACb,OAAO9D,EAAI4B,OAAOV,MAAO,GAAI4C,EAC9B,EAGI3B,EAAOnC,EAAImC,KAEXS,EAAU5C,EAAI4C,QAEdqQ,EAAa,CAAC,EAEdxB,EAAWwB,EAAWxB,SAEtByB,EAASD,EAAW1S,eAEpB4S,EAAaD,EAAOzB,SAEpB2B,EAAuBD,EAAWrE,KAAMtO,QAExC6S,EAAU,CAAC,EAEXC,EAAa,SAASA,WAAYtN,GASpC,MAAsB,mBAARA,GAA8C,iBAAjBA,EAAI0B,UAC1B,mBAAb1B,EAAIuN,IACb,EAGGC,EAAW,SAASA,SAAUxN,GAChC,OAAc,MAAPA,GAAeA,IAAQA,EAAII,MACnC,EAGGG,EAAWH,EAAOG,SAIjBkN,EAA4B,CAC/BC,MAAM,EACNC,KAAK,EACLC,OAAO,EACPC,UAAU,GAGX,SAASC,QAASC,EAAMxG,EAAMY,GAG7B,IAAIhO,EAAG6T,EACNC,GAHD9F,EAAMA,GAAO5H,GAGCuC,cAAe,UAG7B,GADAmL,EAAOhP,KAAO8O,EACTxG,EACJ,IAAMpN,KAAKsT,GAYVO,EAAMzG,EAAMpN,IAAOoN,EAAK1G,cAAgB0G,EAAK1G,aAAc1G,KAE1D8T,EAAOxE,aAActP,EAAG6T,GAI3B7F,EAAI+F,KAAKvC,YAAasC,GAASzG,WAAWC,YAAawG,EACxD,CAGD,SAASE,OAAQnO,GAChB,OAAY,MAAPA,EACGA,EAAM,GAIQ,iBAARA,GAAmC,mBAARA,EACxCiN,EAAYxB,EAAS3C,KAAM9I,KAAW,gBAC/BA,CACT,CAOA,IACCwB,EAAU,QAGV4M,OAAS,SAAUC,EAAUC,GAI5B,OAAO,IAAIF,OAAOG,GAAGC,KAAMH,EAAUC,EACtC,EAyVD,SAASG,YAAazO,GAMrB,IAAI3F,IAAW2F,GAAO,WAAYA,GAAOA,EAAI3F,OAC5CqT,EAAOS,OAAQnO,GAEhB,OAAKsN,EAAYtN,KAASwN,EAAUxN,KAIpB,UAAT0N,GAA+B,IAAXrT,GACR,iBAAXA,GAAuBA,EAAS,GAAOA,EAAS,KAAO2F,EAChE,CAtWAoO,OAAOG,GAAKH,OAAO1S,UAAY,CAG9BgT,OAAQlN,EAERvB,YAAamO,OAGb/T,OAAQ,EAERsU,QAAS,WACR,OAAO5B,EAAMjE,KAAM8D,KACpB,EAIAnO,IAAK,SAAUmQ,GAGd,OAAY,MAAPA,EACG7B,EAAMjE,KAAM8D,MAIbgC,EAAM,EAAIhC,KAAMgC,EAAMhC,KAAKvS,QAAWuS,KAAMgC,EACpD,EAIAC,UAAW,SAAUC,GAGpB,IAAIC,EAAMX,OAAOY,MAAOpC,KAAK3M,cAAe6O,GAM5C,OAHAC,EAAIE,WAAarC,KAGVmC,CACR,EAGAG,KAAM,SAAUC,GACf,OAAOf,OAAOc,KAAMtC,KAAMuC,EAC3B,EAEAC,IAAK,SAAUD,GACd,OAAOvC,KAAKiC,UAAWT,OAAOgB,IAAKxC,MAAM,SAAUyC,EAAMlV,GACxD,OAAOgV,EAASrG,KAAMuG,EAAMlV,EAAGkV,EAChC,IACD,EAEAtC,MAAO,WACN,OAAOH,KAAKiC,UAAW9B,EAAM7R,MAAO0R,KAAMpP,WAC3C,EAEA8R,MAAO,WACN,OAAO1C,KAAK2C,GAAI,EACjB,EAEAC,KAAM,WACL,OAAO5C,KAAK2C,IAAK,EAClB,EAEAE,KAAM,WACL,OAAO7C,KAAKiC,UAAWT,OAAOsB,KAAM9C,MAAM,SAAU+C,EAAOxV,GAC1D,OAASA,EAAI,GAAM,CACpB,IACD,EAEAyV,IAAK,WACJ,OAAOhD,KAAKiC,UAAWT,OAAOsB,KAAM9C,MAAM,SAAU+C,EAAOxV,GAC1D,OAAOA,EAAI,CACZ,IACD,EAEAoV,GAAI,SAAUpV,GACb,IAAI0V,EAAMjD,KAAKvS,OACdyV,GAAK3V,GAAMA,EAAI,EAAI0V,EAAM,GAC1B,OAAOjD,KAAKiC,UAAWiB,GAAK,GAAKA,EAAID,EAAM,CAAEjD,KAAMkD,IAAQ,GAC5D,EAEAC,IAAK,WACJ,OAAOnD,KAAKqC,YAAcrC,KAAK3M,aAChC,EAIA9D,KAAMA,EACN6T,KAAMhW,EAAIgW,KACVC,OAAQjW,EAAIiW,QAGb7B,OAAO8B,OAAS9B,OAAOG,GAAG2B,OAAS,WAClC,IAAIC,EAAStI,EAAM8F,EAAKyC,EAAMC,EAAanS,EAC1CoS,EAAS9S,UAAW,IAAO,CAAC,EAC5BrD,EAAI,EACJE,EAASmD,UAAUnD,OACnBkW,GAAO,EAsBR,IAnBuB,kBAAXD,IACXC,EAAOD,EAGPA,EAAS9S,UAAWrD,IAAO,CAAC,EAC5BA,KAIsB,iBAAXmW,GAAwBhD,EAAYgD,KAC/CA,EAAS,CAAC,GAINnW,IAAME,IACViW,EAAS1D,KACTzS,KAGOA,EAAIE,EAAQF,IAGnB,GAAqC,OAA9BgW,EAAU3S,UAAWrD,IAG3B,IAAM0N,KAAQsI,EACbC,EAAOD,EAAStI,GAIF,cAATA,GAAwByI,IAAWF,IAKnCG,GAAQH,IAAUhC,OAAOoC,cAAeJ,KAC1CC,EAAcpW,MAAMC,QAASkW,MAC/BzC,EAAM2C,EAAQzI,GAIb3J,EADImS,IAAgBpW,MAAMC,QAASyT,GAC3B,GACI0C,GAAgBjC,OAAOoC,cAAe7C,GAG1CA,EAFA,CAAC,EAIV0C,GAAc,EAGdC,EAAQzI,GAASuG,OAAO8B,OAAQK,EAAMrS,EAAOkS,SAGzB/O,IAAT+O,IACXE,EAAQzI,GAASuI,IAOrB,OAAOE,CACR,EAEAlC,OAAO8B,OAAQ,CAGdO,QAAS,UAAajP,EAAUkP,KAAKC,UAAWjU,QAAS,MAAO,IAGhEkU,SAAS,EAETC,MAAO,SAAUC,GAChB,MAAM,IAAInE,MAAOmE,EAClB,EAEAC,KAAM,WAAY,EAElBP,cAAe,SAAUxQ,GACxB,IAAIgR,EAAOC,EAIX,SAAMjR,GAAgC,oBAAzByL,EAAS3C,KAAM9I,QAI5BgR,EAAQlE,EAAU9M,KASK,mBADvBiR,EAAO/D,EAAOpE,KAAMkI,EAAO,gBAAmBA,EAAM/Q,cACfkN,EAAWrE,KAAMmI,KAAW7D,EAClE,EAEA8D,cAAe,SAAUlR,GACxB,IAAI6H,EAEJ,IAAMA,KAAQ7H,EACb,OAAO,EAER,OAAO,CACR,EAIAmR,WAAY,SAAUpD,EAAMoC,EAAShI,GACpC2F,QAASC,EAAM,CAAEH,MAAOuC,GAAWA,EAAQvC,OAASzF,EACrD,EAEA+G,KAAM,SAAUlP,EAAKmP,GACpB,IAAI9U,EAAQF,EAAI,EAEhB,GAAKsU,YAAazO,GAEjB,IADA3F,EAAS2F,EAAI3F,OACLF,EAAIE,IACqC,IAA3C8U,EAASrG,KAAM9I,EAAK7F,GAAKA,EAAG6F,EAAK7F,IADnBA,UAMpB,IAAMA,KAAK6F,EACV,IAAgD,IAA3CmP,EAASrG,KAAM9I,EAAK7F,GAAKA,EAAG6F,EAAK7F,IACrC,MAKH,OAAO6F,CACR,EAGAoR,UAAW,SAAUpX,EAAKqX,GACzB,IAAItC,EAAMsC,GAAW,GAarB,OAXY,MAAPrX,IACCyU,YAAajU,OAAQR,IACzBoU,OAAOY,MAAOD,EACE,iBAAR/U,EACN,CAAEA,GAAQA,GAGZmC,EAAK2M,KAAMiG,EAAK/U,IAIX+U,CACR,EAEAuC,QAAS,SAAUjC,EAAMrV,EAAKG,GAC7B,OAAc,MAAPH,GAAe,EAAI4C,EAAQkM,KAAM9O,EAAKqV,EAAMlV,EACpD,EAIA6U,MAAO,SAAUM,EAAOiC,GAKvB,IAJA,IAAI1B,GAAO0B,EAAOlX,OACjByV,EAAI,EACJ3V,EAAImV,EAAMjV,OAEHyV,EAAID,EAAKC,IAChBR,EAAOnV,KAAQoX,EAAQzB,GAKxB,OAFAR,EAAMjV,OAASF,EAERmV,CACR,EAEAI,KAAM,SAAUZ,EAAOK,EAAUqC,GAShC,IARA,IACCnJ,EAAU,GACVlO,EAAI,EACJE,EAASyU,EAAMzU,OACfoX,GAAkBD,EAIXrX,EAAIE,EAAQF,KACAgV,EAAUL,EAAO3U,GAAKA,KAChBsX,GACxBpJ,EAAQlM,KAAM2S,EAAO3U,IAIvB,OAAOkO,CACR,EAGA+G,IAAK,SAAUN,EAAOK,EAAUuC,GAC/B,IAAIrX,EAAQqE,EACXvE,EAAI,EACJ4U,EAAM,GAGP,GAAKN,YAAaK,GAEjB,IADAzU,EAASyU,EAAMzU,OACPF,EAAIE,EAAQF,IAGL,OAFduE,EAAQyQ,EAAUL,EAAO3U,GAAKA,EAAGuX,KAGhC3C,EAAI5S,KAAMuC,QAMZ,IAAMvE,KAAK2U,EAGI,OAFdpQ,EAAQyQ,EAAUL,EAAO3U,GAAKA,EAAGuX,KAGhC3C,EAAI5S,KAAMuC,GAMb,OAAOsO,EAAM+B,EACd,EAGA4C,KAAM,EAINtE,QAASA,IAGa,mBAAXvN,SACXsO,OAAOG,GAAIzO,OAAOC,UAAa/F,EAAK8F,OAAOC,WAI5CqO,OAAOc,KAAM,uEAAuE0C,MAAO,MAC1F,SAAUC,EAAIhK,GACboF,EAAY,WAAapF,EAAO,KAAQA,EAAKvL,aAC9C,IAkBD,IAAIwV,EAWJ,SAAY1R,GACZ,IAAIjG,EACHkT,EACA0E,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAGAC,EACAjS,EACAkS,EACAC,EACAC,EACAC,EACAvK,EACAwK,EAGApC,EAAU,SAAW,EAAI,IAAIqC,KAC7BC,EAAe3S,EAAOG,SACtByS,EAAU,EACVC,EAAO,EACPC,EAAaC,cACbC,EAAaD,cACbE,EAAgBF,cAChBG,EAAyBH,cACzBI,UAAY,SAAUC,EAAGC,GAIxB,OAHKD,IAAMC,IACVlB,GAAe,GAET,CACR,EAGArF,EAAS,CAAK,EAAE3S,eAChBP,EAAM,GACNiC,EAAMjC,EAAIiC,IACVyX,EAAa1Z,EAAImC,KACjBA,EAAOnC,EAAImC,KACX4Q,EAAQ/S,EAAI+S,MAIZnQ,QAAU,SAAU+W,EAAMtE,GAGzB,IAFA,IAAIlV,EAAI,EACP0V,EAAM8D,EAAKtZ,OACJF,EAAI0V,EAAK1V,IAChB,GAAKwZ,EAAMxZ,KAAQkV,EAClB,OAAOlV,EAGT,OAAQ,CACT,EAEAyZ,EAAW,6HAMXC,EAAa,sBAGbC,EAAa,0BAA4BD,EACxC,0CAGDrK,EAAa,MAAQqK,EAAa,KAAOC,EAAa,OAASD,EAG9D,gBAAkBA,EAIlB,2DAA6DC,EAAa,OAC1ED,EAAa,OAEdE,EAAU,KAAOD,EAAP,wFAOoBtK,EAPpB,eAcVwK,EAAc,IAAIhX,OAAQ6W,EAAa,IAAK,KAC5CI,EAAQ,IAAIjX,OAAQ,IAAM6W,EAAa,8BACtCA,EAAa,KAAM,KAEpBK,EAAS,IAAIlX,OAAQ,IAAM6W,EAAa,KAAOA,EAAa,KAC5DM,EAAe,IAAInX,OAAQ,IAAM6W,EAAa,WAAaA,EAAa,IAAMA,EAC7E,KACDO,EAAW,IAAIpX,OAAQ6W,EAAa,MAEpCQ,EAAU,IAAIrX,OAAQ+W,GACtBO,EAAc,IAAItX,OAAQ,IAAM8W,EAAa,KAE7CS,EAAY,CACX,GAAM,IAAIvX,OAAQ,MAAQ8W,EAAa,KACvC,MAAS,IAAI9W,OAAQ,QAAU8W,EAAa,KAC5C,IAAO,IAAI9W,OAAQ,KAAO8W,EAAa,SACvC,KAAQ,IAAI9W,OAAQ,IAAMwM,GAC1B,OAAU,IAAIxM,OAAQ,IAAM+W,GAC5B,MAAS,IAAI/W,OAAQ,yDACpB6W,EAAa,+BAAiCA,EAAa,cAC3DA,EAAa,aAAeA,EAAa,SAAU,KACpD,KAAQ,IAAI7W,OAAQ,OAAS4W,EAAW,KAAM,KAI9C,aAAgB,IAAI5W,OAAQ,IAAM6W,EACjC,mDAAqDA,EACrD,mBAAqBA,EAAa,mBAAoB,MAGxDW,EAAQ,SACRC,EAAU,sCACVC,EAAU,SAEVC,EAAU,yBAGVC,EAAa,mCAEbC,GAAW,OAIXC,GAAY,IAAI9X,OAAQ,uBAAyB6W,EAAa,uBAAwB,KACtFkB,UAAY,SAAUC,EAAQC,GAC7B,IAAIC,EAAO,KAAOF,EAAOjI,MAAO,GAAM,MAEtC,OAAOkI,IASNC,EAAO,EACN7Y,OAAO8Y,aAAcD,EAAO,OAC5B7Y,OAAO8Y,aAAcD,GAAQ,GAAK,MAAe,KAAPA,EAAe,OAC5D,EAIAE,GAAa,sDACbC,WAAa,SAAUC,EAAIC,GAC1B,OAAKA,EAGQ,OAAPD,EACG,IAIDA,EAAGvI,MAAO,GAAI,GAAM,KAC1BuI,EAAGE,WAAYF,EAAGjb,OAAS,GAAIoR,SAAU,IAAO,IAI3C,KAAO6J,CACf,EAMAG,cAAgB,WACfjD,GACD,EAEAkD,GAAqBC,eACpB,SAAUtG,GACT,OAAyB,IAAlBA,EAAKuG,UAAqD,aAAhCvG,EAAK/F,SAAShN,aAChD,GACA,CAAEuZ,IAAK,aAAcC,KAAM,WAI7B,IACC3Z,EAAKjB,MACFlB,EAAM+S,EAAMjE,KAAMiK,EAAalK,YACjCkK,EAAalK,YAMd7O,EAAK+Y,EAAalK,WAAWxO,QAASqH,QACvC,CAAE,MAAQqU,GACT5Z,EAAO,CAAEjB,MAAOlB,EAAIK,OAGnB,SAAUiW,EAAQ0F,GACjBtC,EAAWxY,MAAOoV,EAAQvD,EAAMjE,KAAMkN,GACvC,EAIA,SAAU1F,EAAQ0F,GAKjB,IAJA,IAAIlG,EAAIQ,EAAOjW,OACdF,EAAI,EAGKmW,EAAQR,KAAQkG,EAAK7b,OAC/BmW,EAAOjW,OAASyV,EAAI,CACrB,EAEF,CAEA,SAASgC,OAAQzD,EAAUC,EAAS+C,EAAS4E,GAC5C,IAAIC,EAAG/b,EAAGkV,EAAM8G,EAAK3Z,EAAO4Z,EAAQC,EACnCC,EAAahI,GAAWA,EAAQtL,cAGhCtB,EAAW4M,EAAUA,EAAQ5M,SAAW,EAKzC,GAHA2P,EAAUA,GAAW,GAGI,iBAAbhD,IAA0BA,GACxB,IAAb3M,GAA+B,IAAbA,GAA+B,KAAbA,EAEpC,OAAO2P,EAIR,IAAM4E,IACLzD,EAAalE,GACbA,EAAUA,GAAW/N,EAEhBmS,GAAiB,CAIrB,GAAkB,KAAbhR,IAAqBlF,EAAQoY,EAAW2B,KAAMlI,IAGlD,GAAO6H,EAAI1Z,EAAO,IAGjB,GAAkB,IAAbkF,EAAiB,CACrB,KAAO2N,EAAOf,EAAQkI,eAAgBN,IAUrC,OAAO7E,EALP,GAAKhC,EAAKoH,KAAOP,EAEhB,OADA7E,EAAQlV,KAAMkT,GACPgC,CAOV,MAKC,GAAKiF,IAAgBjH,EAAOiH,EAAWE,eAAgBN,KACtDrD,EAAUvE,EAASe,IACnBA,EAAKoH,KAAOP,EAGZ,OADA7E,EAAQlV,KAAMkT,GACPgC,MAKH,IAAK7U,EAAO,GAElB,OADAL,EAAKjB,MAAOmW,EAAS/C,EAAQ/K,qBAAsB8K,IAC5CgD,EAGD,IAAO6E,EAAI1Z,EAAO,KAAS6Q,EAAQqJ,wBACzCpI,EAAQoI,uBAGR,OADAva,EAAKjB,MAAOmW,EAAS/C,EAAQoI,uBAAwBR,IAC9C7E,CACR,CAID,GAAKhE,EAAQsJ,MACXrD,EAAwBjF,EAAW,QACjCsE,IAAcA,EAAU1V,KAAMoR,MAIlB,IAAb3M,GAAqD,WAAnC4M,EAAQhF,SAAShN,eAA+B,CAYpE,GAVA+Z,EAAchI,EACdiI,EAAahI,EASK,IAAb5M,IACF0S,EAASnX,KAAMoR,IAAc8F,EAAalX,KAAMoR,IAAe,CAqBjE,KAlBAiI,EAAazB,GAAS5X,KAAMoR,IAAcuI,YAAatI,EAAQ9G,aAC9D8G,KAImBA,GAAYjB,EAAQwJ,SAGhCV,EAAM7H,EAAQzN,aAAc,OAClCsV,EAAMA,EAAIzZ,QAAS0Y,GAAYC,YAE/B/G,EAAQ7E,aAAc,KAAQ0M,EAAM1F,IAMtCtW,GADAic,EAASlE,EAAU7D,IACRhU,OACHF,KACPic,EAAQjc,IAAQgc,EAAM,IAAMA,EAAM,UAAa,IAC9CW,WAAYV,EAAQjc,IAEtBkc,EAAcD,EAAOW,KAAM,IAC5B,CAEA,IAIC,OAHA5a,EAAKjB,MAAOmW,EACXiF,EAAWU,iBAAkBX,IAEvBhF,CACR,CAAE,MAAQ4F,GACT3D,EAAwBjF,GAAU,EACnC,CAAE,QACI8H,IAAQ1F,GACZnC,EAAQtG,gBAAiB,KAE3B,CACD,CACD,CAID,OAAOoK,EAAQ/D,EAAS3R,QAASuX,EAAO,MAAQ3F,EAAS+C,EAAS4E,EACnE,CAQA,SAAS9C,cACR,IAAI+D,EAAO,GAYX,OAVA,SAASC,MAAOC,EAAK1Y,GAQpB,OALKwY,EAAK/a,KAAMib,EAAM,KAAQrF,EAAKsF,oBAG3BF,MAAOD,EAAKI,SAEXH,MAAOC,EAAM,KAAQ1Y,CAC/B,CAED,CAMA,SAAS6Y,aAAchJ,GAEtB,OADAA,EAAIkC,IAAY,EACTlC,CACR,CAMA,SAASiJ,OAAQjJ,GAChB,IAAIkJ,EAAKlX,EAASuC,cAAe,YAEjC,IACC,QAASyL,EAAIkJ,EACd,CAAE,MAAQ1B,GACT,OAAO,CACR,CAAE,QAGI0B,EAAGjQ,YACPiQ,EAAGjQ,WAAWC,YAAagQ,GAI5BA,EAAK,IACN,CACD,CAOA,SAASC,UAAWC,EAAOC,GAI1B,IAHA,IAAI5d,EAAM2d,EAAM/F,MAAO,KACtBzX,EAAIH,EAAIK,OAEDF,KACP4X,EAAK8F,WAAY7d,EAAKG,IAAQyd,CAEhC,CAQA,SAASE,aAActE,EAAGC,GACzB,IAAIsE,EAAMtE,GAAKD,EACdwE,EAAOD,GAAsB,IAAfvE,EAAE9R,UAAiC,IAAf+R,EAAE/R,UACnC8R,EAAEyE,YAAcxE,EAAEwE,YAGpB,GAAKD,EACJ,OAAOA,EAIR,GAAKD,EACJ,KAAUA,EAAMA,EAAIG,aACnB,GAAKH,IAAQtE,EACZ,OAAQ,EAKX,OAAOD,EAAI,GAAK,CACjB,CAMA,SAAS2E,kBAAmBzK,GAC3B,OAAO,SAAU2B,GAEhB,MAAgB,UADLA,EAAK/F,SAAShN,eACE+S,EAAK3B,OAASA,CAC1C,CACD,CAMA,SAAS0K,mBAAoB1K,GAC5B,OAAO,SAAU2B,GAChB,IAAIxH,EAAOwH,EAAK/F,SAAShN,cACzB,OAAkB,UAATuL,GAA6B,WAATA,IAAuBwH,EAAK3B,OAASA,CACnE,CACD,CAMA,SAAS2K,qBAAsBzC,GAG9B,OAAO,SAAUvG,GAKhB,MAAK,SAAUA,EASTA,EAAK7H,aAAgC,IAAlB6H,EAAKuG,SAGvB,UAAWvG,EACV,UAAWA,EAAK7H,WACb6H,EAAK7H,WAAWoO,WAAaA,EAE7BvG,EAAKuG,WAAaA,EAMpBvG,EAAKiJ,aAAe1C,GAI1BvG,EAAKiJ,cAAgB1C,GACrBF,GAAoBrG,KAAWuG,EAG1BvG,EAAKuG,WAAaA,EAKd,UAAWvG,GACfA,EAAKuG,WAAaA,CAK3B,CACD,CAMA,SAAS2C,uBAAwBhK,GAChC,OAAOgJ,cAAc,SAAUiB,GAE9B,OADAA,GAAYA,EACLjB,cAAc,SAAUtB,EAAM5N,GAMpC,IALA,IAAIyH,EACH2I,EAAelK,EAAI,GAAI0H,EAAK5b,OAAQme,GACpCre,EAAIse,EAAape,OAGVF,KACF8b,EAAQnG,EAAI2I,EAActe,MAC9B8b,EAAMnG,KAASzH,EAASyH,GAAMmG,EAAMnG,IAGvC,GACD,GACD,CAOA,SAAS8G,YAAatI,GACrB,OAAOA,QAAmD,IAAjCA,EAAQ/K,sBAAwC+K,CAC1E,CAirCA,IAAMnU,KA9qCNkT,EAAUyE,OAAOzE,QAAU,CAAC,EAO5B4E,EAAQH,OAAOG,MAAQ,SAAU5C,GAChC,IAAIqJ,EAAYrJ,GAAQA,EAAKnI,aAC5BuL,EAAUpD,IAAUA,EAAKrM,eAAiBqM,GAAO7G,gBAKlD,OAAQgM,EAAMvX,KAAMyb,GAAajG,GAAWA,EAAQnJ,UAAY,OACjE,EAOAkJ,EAAcV,OAAOU,YAAc,SAAUjL,GAC5C,IAAIoR,EAAYC,EACfzQ,EAAMZ,EAAOA,EAAKvE,eAAiBuE,EAAOwL,EAO3C,OAAK5K,GAAO5H,GAA6B,IAAjB4H,EAAIzG,UAAmByG,EAAIK,iBAMnDiK,GADAlS,EAAW4H,GACQK,gBACnBkK,GAAkBT,EAAO1R,GAQpBwS,GAAgBxS,IAClBqY,EAAYrY,EAASsY,cAAiBD,EAAUE,MAAQF,IAGrDA,EAAUG,iBACdH,EAAUG,iBAAkB,SAAUtD,eAAe,GAG1CmD,EAAUI,aACrBJ,EAAUI,YAAa,WAAYvD,gBASrCpI,EAAQwJ,MAAQW,QAAQ,SAAUC,GAEjC,OADAhF,EAAQ9G,YAAa8L,GAAK9L,YAAapL,EAASuC,cAAe,aACzB,IAAxB2U,EAAGT,mBACfS,EAAGT,iBAAkB,uBAAwB3c,MAChD,IAQAgT,EAAQ7D,WAAagO,QAAQ,SAAUC,GAEtC,OADAA,EAAGwB,UAAY,KACPxB,EAAG5W,aAAc,YAC1B,IAMAwM,EAAQ9J,qBAAuBiU,QAAQ,SAAUC,GAEhD,OADAA,EAAG9L,YAAapL,EAAS2Y,cAAe,MAChCzB,EAAGlU,qBAAsB,KAAMlJ,MACxC,IAGAgT,EAAQqJ,uBAAyB/B,EAAQ1X,KAAMsD,EAASmW,wBAMxDrJ,EAAQ8L,QAAU3B,QAAQ,SAAUC,GAEnC,OADAhF,EAAQ9G,YAAa8L,GAAKhB,GAAKhG,GACvBlQ,EAAS6Y,oBAAsB7Y,EAAS6Y,kBAAmB3I,GAAUpW,MAC9E,IAGKgT,EAAQ8L,SACZpH,EAAKsH,OAAa,GAAI,SAAU5C,GAC/B,IAAI6C,EAAS7C,EAAG/Z,QAASoY,GAAWC,WACpC,OAAO,SAAU1F,GAChB,OAAOA,EAAKxO,aAAc,QAAWyY,CACtC,CACD,EACAvH,EAAKwH,KAAW,GAAI,SAAU9C,EAAInI,GACjC,QAAuC,IAA3BA,EAAQkI,gBAAkC9D,EAAiB,CACtE,IAAIrD,EAAOf,EAAQkI,eAAgBC,GACnC,OAAOpH,EAAO,CAAEA,GAAS,EAC1B,CACD,IAEA0C,EAAKsH,OAAa,GAAK,SAAU5C,GAChC,IAAI6C,EAAS7C,EAAG/Z,QAASoY,GAAWC,WACpC,OAAO,SAAU1F,GAChB,IAAI9H,OAAwC,IAA1B8H,EAAKtH,kBACtBsH,EAAKtH,iBAAkB,MACxB,OAAOR,GAAQA,EAAK7I,QAAU4a,CAC/B,CACD,EAIAvH,EAAKwH,KAAW,GAAI,SAAU9C,EAAInI,GACjC,QAAuC,IAA3BA,EAAQkI,gBAAkC9D,EAAiB,CACtE,IAAInL,EAAMpN,EAAG2U,EACZO,EAAOf,EAAQkI,eAAgBC,GAEhC,GAAKpH,EAAO,CAIX,IADA9H,EAAO8H,EAAKtH,iBAAkB,QACjBR,EAAK7I,QAAU+X,EAC3B,MAAO,CAAEpH,GAMV,IAFAP,EAAQR,EAAQ8K,kBAAmB3C,GACnCtc,EAAI,EACMkV,EAAOP,EAAO3U,MAEvB,IADAoN,EAAO8H,EAAKtH,iBAAkB,QACjBR,EAAK7I,QAAU+X,EAC3B,MAAO,CAAEpH,EAGZ,CAEA,MAAO,EACR,CACD,GAID0C,EAAKwH,KAAY,IAAIlM,EAAQ9J,qBAC5B,SAAU2I,EAAKoC,GACd,YAA6C,IAAjCA,EAAQ/K,qBACZ+K,EAAQ/K,qBAAsB2I,GAG1BmB,EAAQsJ,IACZrI,EAAQ0I,iBAAkB9K,QAD3B,CAGR,EAEA,SAAUA,EAAKoC,GACd,IAAIe,EACHmK,EAAM,GACNrf,EAAI,EAGJkX,EAAU/C,EAAQ/K,qBAAsB2I,GAGzC,GAAa,MAARA,EAAc,CAClB,KAAUmD,EAAOgC,EAASlX,MACF,IAAlBkV,EAAK3N,UACT8X,EAAIrd,KAAMkT,GAIZ,OAAOmK,CACR,CACA,OAAOnI,CACR,EAGDU,EAAKwH,KAAc,MAAIlM,EAAQqJ,wBAA0B,SAAUuC,EAAW3K,GAC7E,QAA+C,IAAnCA,EAAQoI,wBAA0ChE,EAC7D,OAAOpE,EAAQoI,uBAAwBuC,EAEzC,EAQArG,EAAgB,GAOhBD,EAAY,IAELtF,EAAQsJ,IAAMhC,EAAQ1X,KAAMsD,EAASyW,qBAI3CQ,QAAQ,SAAUC,GAEjB,IAAIgC,EAOJhH,EAAQ9G,YAAa8L,GAAKvN,UAAY,UAAYuG,EAAZ,qBACpBA,EADoB,kEAQjCgH,EAAGT,iBAAkB,wBAAyB3c,QAClDsY,EAAUxW,KAAM,SAAW0X,EAAa,gBAKnC4D,EAAGT,iBAAkB,cAAe3c,QACzCsY,EAAUxW,KAAM,MAAQ0X,EAAa,aAAeD,EAAW,KAI1D6D,EAAGT,iBAAkB,QAAUvG,EAAU,MAAOpW,QACrDsY,EAAUxW,KAAM,OAQjBsd,EAAQlZ,EAASuC,cAAe,UAC1B2G,aAAc,OAAQ,IAC5BgO,EAAG9L,YAAa8N,GACVhC,EAAGT,iBAAkB,aAAc3c,QACxCsY,EAAUxW,KAAM,MAAQ0X,EAAa,QAAUA,EAAa,KAC3DA,EAAa,gBAMT4D,EAAGT,iBAAkB,YAAa3c,QACvCsY,EAAUxW,KAAM,YAMXsb,EAAGT,iBAAkB,KAAOvG,EAAU,MAAOpW,QAClDsY,EAAUxW,KAAM,YAKjBsb,EAAGT,iBAAkB,QACrBrE,EAAUxW,KAAM,cACjB,IAEAqb,QAAQ,SAAUC,GACjBA,EAAGvN,UAAY,oFAKf,IAAIuP,EAAQlZ,EAASuC,cAAe,SACpC2W,EAAMhQ,aAAc,OAAQ,UAC5BgO,EAAG9L,YAAa8N,GAAQhQ,aAAc,OAAQ,KAIzCgO,EAAGT,iBAAkB,YAAa3c,QACtCsY,EAAUxW,KAAM,OAAS0X,EAAa,eAKW,IAA7C4D,EAAGT,iBAAkB,YAAa3c,QACtCsY,EAAUxW,KAAM,WAAY,aAK7BsW,EAAQ9G,YAAa8L,GAAK7B,UAAW,EACc,IAA9C6B,EAAGT,iBAAkB,aAAc3c,QACvCsY,EAAUxW,KAAM,WAAY,aAK7Bsb,EAAGT,iBAAkB,QACrBrE,EAAUxW,KAAM,OACjB,MAGMkR,EAAQqM,gBAAkB/E,EAAQ1X,KAAQoL,EAAUoK,EAAQpK,SAClEoK,EAAQkH,uBACRlH,EAAQmH,oBACRnH,EAAQoH,kBACRpH,EAAQqH,qBAERtC,QAAQ,SAAUC,GAIjBpK,EAAQ0M,kBAAoB1R,EAAQS,KAAM2O,EAAI,KAI9CpP,EAAQS,KAAM2O,EAAI,aAClB7E,EAAczW,KAAM,KAAM4X,EAC3B,IAGDpB,EAAYA,EAAUtY,QAAU,IAAI2C,OAAQ2V,EAAUoE,KAAM,MAC5DnE,EAAgBA,EAAcvY,QAAU,IAAI2C,OAAQ4V,EAAcmE,KAAM,MAIxE4B,EAAahE,EAAQ1X,KAAMwV,EAAQuH,yBAKnCnH,EAAW8F,GAAchE,EAAQ1X,KAAMwV,EAAQI,UAC9C,SAAUW,EAAGC,GACZ,IAAIwG,EAAuB,IAAfzG,EAAE9R,SAAiB8R,EAAEhL,gBAAkBgL,EAClD0G,EAAMzG,GAAKA,EAAEjM,WACd,OAAOgM,IAAM0G,MAAWA,GAAwB,IAAjBA,EAAIxY,YAClCuY,EAAMpH,SACLoH,EAAMpH,SAAUqH,GAChB1G,EAAEwG,yBAA8D,GAAnCxG,EAAEwG,wBAAyBE,IAE3D,EACA,SAAU1G,EAAGC,GACZ,GAAKA,EACJ,KAAUA,EAAIA,EAAEjM,YACf,GAAKiM,IAAMD,EACV,OAAO,EAIV,OAAO,CACR,EAMDD,UAAYoF,EACZ,SAAUnF,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAIR,IAAI4H,GAAW3G,EAAEwG,yBAA2BvG,EAAEuG,wBAC9C,OAAKG,IAgBU,GAPfA,GAAY3G,EAAExQ,eAAiBwQ,KAASC,EAAEzQ,eAAiByQ,GAC1DD,EAAEwG,wBAAyBvG,GAG3B,KAIGpG,EAAQ+M,cAAgB3G,EAAEuG,wBAAyBxG,KAAQ2G,EAOzD3G,GAAKjT,GAAYiT,EAAExQ,eAAiB+P,GACxCF,EAAUE,EAAcS,IAChB,EAOJC,GAAKlT,GAAYkT,EAAEzQ,eAAiB+P,GACxCF,EAAUE,EAAcU,GACjB,EAIDnB,EACJ1V,QAAS0V,EAAWkB,GAAM5W,QAAS0V,EAAWmB,GAChD,EAGe,EAAV0G,GAAe,EAAI,EAC3B,EACA,SAAU3G,EAAGC,GAGZ,GAAKD,IAAMC,EAEV,OADAlB,GAAe,EACR,EAGR,IAAIwF,EACH5d,EAAI,EACJkgB,EAAM7G,EAAEhM,WACR0S,EAAMzG,EAAEjM,WACR8S,EAAK,CAAE9G,GACP+G,EAAK,CAAE9G,GAGR,IAAM4G,IAAQH,EAMb,OAAO1G,GAAKjT,GAAY,EACvBkT,GAAKlT,EAAW,EAEhB8Z,GAAO,EACPH,EAAM,EACN5H,EACE1V,QAAS0V,EAAWkB,GAAM5W,QAAS0V,EAAWmB,GAChD,EAGK,GAAK4G,IAAQH,EACnB,OAAOpC,aAActE,EAAGC,GAKzB,IADAsE,EAAMvE,EACIuE,EAAMA,EAAIvQ,YACnB8S,EAAGE,QAASzC,GAGb,IADAA,EAAMtE,EACIsE,EAAMA,EAAIvQ,YACnB+S,EAAGC,QAASzC,GAIb,KAAQuC,EAAIngB,KAAQogB,EAAIpgB,IACvBA,IAGD,OAAOA,EAGN2d,aAAcwC,EAAIngB,GAAKogB,EAAIpgB,IAO3BmgB,EAAIngB,IAAO4Y,GAAgB,EAC3BwH,EAAIpgB,IAAO4Y,EAAe,EAE1B,CACF,EAEOxS,GA/cCA,CAgdT,EAEAuR,OAAOzJ,QAAU,SAAUoS,EAAMC,GAChC,OAAO5I,OAAQ2I,EAAM,KAAM,KAAMC,EAClC,EAEA5I,OAAO4H,gBAAkB,SAAUrK,EAAMoL,GAGxC,GAFAjI,EAAanD,GAERhC,EAAQqM,iBAAmBhH,IAC9BY,EAAwBmH,EAAO,QAC7B7H,IAAkBA,EAAc3V,KAAMwd,OACtC9H,IAAkBA,EAAU1V,KAAMwd,IAErC,IACC,IAAI1L,EAAM1G,EAAQS,KAAMuG,EAAMoL,GAG9B,GAAK1L,GAAO1B,EAAQ0M,mBAInB1K,EAAK9O,UAAuC,KAA3B8O,EAAK9O,SAASmB,SAC/B,OAAOqN,CAET,CAAE,MAAQgH,GACTzC,EAAwBmH,GAAM,EAC/B,CAGD,OAAO3I,OAAQ2I,EAAMla,EAAU,KAAM,CAAE8O,IAAShV,OAAS,CAC1D,EAEAyX,OAAOe,SAAW,SAAUvE,EAASe,GAUpC,OAHOf,EAAQtL,eAAiBsL,IAAa/N,GAC5CiS,EAAalE,GAEPuE,EAAUvE,EAASe,EAC3B,EAEAyC,OAAOvH,KAAO,SAAU8E,EAAMxH,IAOtBwH,EAAKrM,eAAiBqM,IAAU9O,GACtCiS,EAAanD,GAGd,IAAId,EAAKwD,EAAK8F,WAAYhQ,EAAKvL,eAG9B0R,EAAMO,GAAMrB,EAAOpE,KAAMiJ,EAAK8F,WAAYhQ,EAAKvL,eAC9CiS,EAAIc,EAAMxH,GAAO6K,QACjBrR,EAEF,YAAeA,IAAR2M,EACNA,EACAX,EAAQ7D,aAAekJ,EACtBrD,EAAKxO,aAAcgH,IACjBmG,EAAMqB,EAAKtH,iBAAkBF,KAAYmG,EAAI2M,UAC9C3M,EAAItP,MACJ,IACJ,EAEAoT,OAAOkD,OAAS,SAAU4F,GACzB,OAASA,EAAM,IAAKle,QAAS0Y,GAAYC,WAC1C,EAEAvD,OAAOjB,MAAQ,SAAUC,GACxB,MAAM,IAAInE,MAAO,0CAA4CmE,EAC9D,EAMAgB,OAAO+I,WAAa,SAAUxJ,GAC7B,IAAIhC,EACHyL,EAAa,GACbhL,EAAI,EACJ3V,EAAI,EAOL,GAJAoY,GAAgBlF,EAAQ0N,iBACxBzI,GAAajF,EAAQ2N,YAAc3J,EAAQtE,MAAO,GAClDsE,EAAQrB,KAAMuD,WAEThB,EAAe,CACnB,KAAUlD,EAAOgC,EAASlX,MACpBkV,IAASgC,EAASlX,KACtB2V,EAAIgL,EAAW3e,KAAMhC,IAGvB,KAAQ2V,KACPuB,EAAQpB,OAAQ6K,EAAYhL,GAAK,EAEnC,CAMA,OAFAwC,EAAY,KAELjB,CACR,EAMAW,EAAUF,OAAOE,QAAU,SAAU3C,GACpC,IAAI9H,EACHwH,EAAM,GACN5U,EAAI,EACJuH,EAAW2N,EAAK3N,SAEjB,GAAMA,GAQC,GAAkB,IAAbA,GAA+B,IAAbA,GAA+B,KAAbA,EAAkB,CAIjE,GAAiC,iBAArB2N,EAAK9F,YAChB,OAAO8F,EAAK9F,YAIZ,IAAM8F,EAAOA,EAAKzD,WAAYyD,EAAMA,EAAOA,EAAK6I,YAC/CnJ,GAAOiD,EAAS3C,EAGnB,MAAO,GAAkB,IAAb3N,GAA+B,IAAbA,EAC7B,OAAO2N,EAAK4L,eAnBZ,KAAU1T,EAAO8H,EAAMlV,MAGtB4U,GAAOiD,EAASzK,GAqBlB,OAAOwH,CACR,EAEAgD,EAAOD,OAAOoJ,UAAY,CAGzB7D,YAAa,GAEb8D,aAAc5D,aAEd/a,MAAO+X,EAEPsD,WAAY,CAAC,EAEb0B,KAAM,CAAC,EAEP6B,SAAU,CACT,IAAK,CAAEvF,IAAK,aAAcvG,OAAO,GACjC,IAAK,CAAEuG,IAAK,cACZ,IAAK,CAAEA,IAAK,kBAAmBvG,OAAO,GACtC,IAAK,CAAEuG,IAAK,oBAGbwF,UAAW,CACV,KAAQ,SAAU7e,GAWjB,OAVAA,EAAO,GAAMA,EAAO,GAAIE,QAASoY,GAAWC,WAG5CvY,EAAO,IAAQA,EAAO,IAAOA,EAAO,IACnCA,EAAO,IAAO,IAAKE,QAASoY,GAAWC,WAEpB,OAAfvY,EAAO,KACXA,EAAO,GAAM,IAAMA,EAAO,GAAM,KAG1BA,EAAMuQ,MAAO,EAAG,EACxB,EAEA,MAAS,SAAUvQ,GAiClB,OArBAA,EAAO,GAAMA,EAAO,GAAIF,cAEU,QAA7BE,EAAO,GAAIuQ,MAAO,EAAG,IAGnBvQ,EAAO,IACZsV,OAAOjB,MAAOrU,EAAO,IAKtBA,EAAO,KAASA,EAAO,GACtBA,EAAO,IAAQA,EAAO,IAAO,GAC7B,GAAqB,SAAfA,EAAO,IAAiC,QAAfA,EAAO,KACvCA,EAAO,KAAWA,EAAO,GAAMA,EAAO,IAAwB,QAAfA,EAAO,KAG3CA,EAAO,IAClBsV,OAAOjB,MAAOrU,EAAO,IAGfA,CACR,EAEA,OAAU,SAAUA,GACnB,IAAI8e,EACHC,GAAY/e,EAAO,IAAOA,EAAO,GAElC,OAAK+X,EAAmB,MAAEtX,KAAMT,EAAO,IAC/B,MAIHA,EAAO,GACXA,EAAO,GAAMA,EAAO,IAAOA,EAAO,IAAO,GAG9B+e,GAAYlH,EAAQpX,KAAMse,KAGnCD,EAASpJ,EAAUqJ,GAAU,MAG7BD,EAASC,EAAS3e,QAAS,IAAK2e,EAASlhB,OAASihB,GAAWC,EAASlhB,UAGxEmC,EAAO,GAAMA,EAAO,GAAIuQ,MAAO,EAAGuO,GAClC9e,EAAO,GAAM+e,EAASxO,MAAO,EAAGuO,IAI1B9e,EAAMuQ,MAAO,EAAG,GACxB,GAGDsM,OAAQ,CAEP,IAAO,SAAUmC,GAChB,IAAIlS,EAAWkS,EAAiB9e,QAASoY,GAAWC,WAAYzY,cAChE,MAA4B,MAArBkf,EACN,WACC,OAAO,CACR,EACA,SAAUnM,GACT,OAAOA,EAAK/F,UAAY+F,EAAK/F,SAAShN,gBAAkBgN,CACzD,CACF,EAEA,MAAS,SAAU2P,GAClB,IAAIwC,EAAUvI,EAAY+F,EAAY,KAEtC,OAAOwC,IACJA,EAAU,IAAIze,OAAQ,MAAQ6W,EAC/B,IAAMoF,EAAY,IAAMpF,EAAa,SAAaX,EACjD+F,GAAW,SAAU5J,GACpB,OAAOoM,EAAQxe,KACY,iBAAnBoS,EAAK4J,WAA0B5J,EAAK4J,gBACd,IAAtB5J,EAAKxO,cACXwO,EAAKxO,aAAc,UACpB,GAEJ,GACF,EAEA,KAAQ,SAAUgH,EAAM6T,EAAUC,GACjC,OAAO,SAAUtM,GAChB,IAAIuM,EAAS9J,OAAOvH,KAAM8E,EAAMxH,GAEhC,OAAe,MAAV+T,EACgB,OAAbF,GAEFA,IAINE,GAAU,GAIU,MAAbF,EAAmBE,IAAWD,EACvB,OAAbD,EAAoBE,IAAWD,EAClB,OAAbD,EAAoBC,GAAqC,IAA5BC,EAAOhf,QAAS+e,GAChC,OAAbD,EAAoBC,GAASC,EAAOhf,QAAS+e,IAAW,EAC3C,OAAbD,EAAoBC,GAASC,EAAO7O,OAAQ4O,EAAMthB,UAAashB,EAClD,OAAbD,GAAsB,IAAME,EAAOlf,QAASsX,EAAa,KAAQ,KAAMpX,QAAS+e,IAAW,EAC9E,OAAbD,IAAoBE,IAAWD,GAASC,EAAO7O,MAAO,EAAG4O,EAAMthB,OAAS,KAAQshB,EAAQ,KAI1F,CACD,EAEA,MAAS,SAAUjO,EAAMmO,EAAMC,EAAWxM,EAAOE,GAChD,IAAIuM,EAAgC,QAAvBrO,EAAKX,MAAO,EAAG,GAC3BiP,EAA+B,SAArBtO,EAAKX,OAAQ,GACvBkP,EAAkB,YAATJ,EAEV,OAAiB,IAAVvM,GAAwB,IAATE,EAGrB,SAAUH,GACT,QAASA,EAAK7H,UACf,EAEA,SAAU6H,EAAM6M,EAAU7c,GACzB,IAAI8X,EAAOgF,EAAaC,EAAY7U,EAAM8U,EAAWC,EACpDzG,EAAMkG,IAAWC,EAAU,cAAgB,kBAC3ChV,EAASqI,EAAK7H,WACdK,EAAOoU,GAAU5M,EAAK/F,SAAShN,cAC/BigB,GAAYld,IAAQ4c,EACpBjE,GAAO,EAER,GAAKhR,EAAS,CAGb,GAAK+U,EAAS,CACb,KAAQlG,GAAM,CAEb,IADAtO,EAAO8H,EACG9H,EAAOA,EAAMsO,IACtB,GAAKoG,EACJ1U,EAAK+B,SAAShN,gBAAkBuL,EACd,IAAlBN,EAAK7F,SAEL,OAAO,EAKT4a,EAAQzG,EAAe,SAATnI,IAAoB4O,GAAS,aAC5C,CACA,OAAO,CACR,CAKA,GAHAA,EAAQ,CAAEN,EAAUhV,EAAO4E,WAAa5E,EAAOwV,WAG1CR,GAAWO,GAkBf,IAHAvE,GADAqE,GADAlF,GAHAgF,GAJAC,GADA7U,EAAOP,GACYyJ,KAAelJ,EAAMkJ,GAAY,CAAC,IAI3BlJ,EAAKkV,YAC5BL,EAAY7U,EAAKkV,UAAa,CAAC,IAEb/O,IAAU,IACZ,KAAQsF,GAAWmE,EAAO,KACzBA,EAAO,GAC3B5P,EAAO8U,GAAarV,EAAO6B,WAAYwT,GAE7B9U,IAAS8U,GAAa9U,GAAQA,EAAMsO,KAG3CmC,EAAOqE,EAAY,IAAOC,EAAMrgB,OAGlC,GAAuB,IAAlBsL,EAAK7F,YAAoBsW,GAAQzQ,IAAS8H,EAAO,CACrD8M,EAAazO,GAAS,CAAEsF,EAASqJ,EAAWrE,GAC5C,KACD,OAwBD,GAlBKuE,IAaJvE,EADAqE,GADAlF,GAHAgF,GAJAC,GADA7U,EAAO8H,GACYoB,KAAelJ,EAAMkJ,GAAY,CAAC,IAI3BlJ,EAAKkV,YAC5BL,EAAY7U,EAAKkV,UAAa,CAAC,IAEb/O,IAAU,IACZ,KAAQsF,GAAWmE,EAAO,KAMhC,IAATa,EAGJ,MAAUzQ,IAAS8U,GAAa9U,GAAQA,EAAMsO,KAC3CmC,EAAOqE,EAAY,IAAOC,EAAMrgB,UAE3BggB,EACN1U,EAAK+B,SAAShN,gBAAkBuL,EACd,IAAlBN,EAAK7F,cACHsW,IAGGuE,KAMJJ,GALAC,EAAa7U,EAAMkJ,KAChBlJ,EAAMkJ,GAAY,CAAC,IAIIlJ,EAAKkV,YAC5BL,EAAY7U,EAAKkV,UAAa,CAAC,IAErB/O,GAAS,CAAEsF,EAASgF,IAG7BzQ,IAAS8H,MAUlB,OADA2I,GAAQxI,KACQF,GAAW0I,EAAO1I,GAAU,GAAK0I,EAAO1I,GAAS,CAClE,CACD,CACF,EAEA,OAAU,SAAUoN,EAAQlE,GAM3B,IAAIld,EACHiT,EAAKwD,EAAKgC,QAAS2I,IAAY3K,EAAK4K,WAAYD,EAAOpgB,gBACtDwV,OAAOjB,MAAO,uBAAyB6L,GAKzC,OAAKnO,EAAIkC,GACDlC,EAAIiK,GAIPjK,EAAGlU,OAAS,GAChBiB,EAAO,CAAEohB,EAAQA,EAAQ,GAAIlE,GACtBzG,EAAK4K,WAAWpiB,eAAgBmiB,EAAOpgB,eAC7Cib,cAAc,SAAUtB,EAAM5N,GAI7B,IAHA,IAAIuU,EACHC,EAAUtO,EAAI0H,EAAMuC,GACpBre,EAAI0iB,EAAQxiB,OACLF,KAEP8b,EADA2G,EAAMhgB,QAASqZ,EAAM4G,EAAS1iB,OACbkO,EAASuU,GAAQC,EAAS1iB,GAE7C,IACA,SAAUkV,GACT,OAAOd,EAAIc,EAAM,EAAG/T,EACrB,GAGKiT,CACR,GAGDwF,QAAS,CAGR,IAAOwD,cAAc,SAAUlJ,GAK9B,IAAIoL,EAAQ,GACXpI,EAAU,GACVyL,EAAU3K,EAAS9D,EAAS3R,QAASuX,EAAO,OAE7C,OAAO6I,EAASrM,GACf8G,cAAc,SAAUtB,EAAM5N,EAAS6T,EAAU7c,GAMhD,IALA,IAAIgQ,EACH0N,EAAYD,EAAS7G,EAAM,KAAM5W,EAAK,IACtClF,EAAI8b,EAAK5b,OAGFF,MACAkV,EAAO0N,EAAW5iB,MACxB8b,EAAM9b,KAASkO,EAASlO,GAAMkV,GAGjC,IACA,SAAUA,EAAM6M,EAAU7c,GAMzB,OALAoa,EAAO,GAAMpK,EACbyN,EAASrD,EAAO,KAAMpa,EAAKgS,GAG3BoI,EAAO,GAAM,MACLpI,EAAQpV,KACjB,CACF,IAEA,IAAOsb,cAAc,SAAUlJ,GAC9B,OAAO,SAAUgB,GAChB,OAAOyC,OAAQzD,EAAUgB,GAAOhV,OAAS,CAC1C,CACD,IAEA,SAAYkd,cAAc,SAAUtY,GAEnC,OADAA,EAAOA,EAAKvC,QAASoY,GAAWC,WACzB,SAAU1F,GAChB,OAASA,EAAK9F,aAAeyI,EAAS3C,IAASzS,QAASqC,IAAU,CACnE,CACD,IASA,KAAQsY,cAAc,SAAUyF,GAO/B,OAJM1I,EAAYrX,KAAM+f,GAAQ,KAC/BlL,OAAOjB,MAAO,qBAAuBmM,GAEtCA,EAAOA,EAAKtgB,QAASoY,GAAWC,WAAYzY,cACrC,SAAU+S,GAChB,IAAI4N,EACJ,GACC,GAAOA,EAAWvK,EACjBrD,EAAK2N,KACL3N,EAAKxO,aAAc,aAAgBwO,EAAKxO,aAAc,QAGtD,OADAoc,EAAWA,EAAS3gB,iBACA0gB,GAA2C,IAAnCC,EAASrgB,QAASogB,EAAO,YAE3C3N,EAAOA,EAAK7H,aAAkC,IAAlB6H,EAAK3N,UAC7C,OAAO,CACR,CACD,IAGA,OAAU,SAAU2N,GACnB,IAAI6N,EAAO9c,EAAO+c,UAAY/c,EAAO+c,SAASD,KAC9C,OAAOA,GAAQA,EAAKnQ,MAAO,KAAQsC,EAAKoH,EACzC,EAEA,KAAQ,SAAUpH,GACjB,OAAOA,IAASoD,CACjB,EAEA,MAAS,SAAUpD,GAClB,OAAOA,IAAS9O,EAAS6c,iBACrB7c,EAAS8c,UAAY9c,EAAS8c,gBAC7BhO,EAAK3B,MAAQ2B,EAAKiO,OAASjO,EAAKkO,SACtC,EAGA,QAAWlF,sBAAsB,GACjC,SAAYA,sBAAsB,GAElC,QAAW,SAAUhJ,GAIpB,IAAI/F,EAAW+F,EAAK/F,SAAShN,cAC7B,MAAsB,UAAbgN,KAA0B+F,EAAKmO,SACxB,WAAblU,KAA2B+F,EAAKoO,QACpC,EAEA,SAAY,SAAUpO,GASrB,OALKA,EAAK7H,YAET6H,EAAK7H,WAAWkW,eAGQ,IAAlBrO,EAAKoO,QACb,EAGA,MAAS,SAAUpO,GAMlB,IAAMA,EAAOA,EAAKzD,WAAYyD,EAAMA,EAAOA,EAAK6I,YAC/C,GAAK7I,EAAK3N,SAAW,EACpB,OAAO,EAGT,OAAO,CACR,EAEA,OAAU,SAAU2N,GACnB,OAAQ0C,EAAKgC,QAAiB,MAAG1E,EAClC,EAGA,OAAU,SAAUA,GACnB,OAAOqF,EAAQzX,KAAMoS,EAAK/F,SAC3B,EAEA,MAAS,SAAU+F,GAClB,OAAOoF,EAAQxX,KAAMoS,EAAK/F,SAC3B,EAEA,OAAU,SAAU+F,GACnB,IAAIxH,EAAOwH,EAAK/F,SAAShN,cACzB,MAAgB,UAATuL,GAAkC,WAAdwH,EAAK3B,MAA8B,WAAT7F,CACtD,EAEA,KAAQ,SAAUwH,GACjB,IAAI9E,EACJ,MAAuC,UAAhC8E,EAAK/F,SAAShN,eACN,SAAd+S,EAAK3B,OAIuC,OAAxCnD,EAAO8E,EAAKxO,aAAc,UACN,SAAvB0J,EAAKjO,cACR,EAGA,MAASic,wBAAwB,WAChC,MAAO,CAAE,EACV,IAEA,KAAQA,wBAAwB,SAAUoF,EAAetjB,GACxD,MAAO,CAAEA,EAAS,EACnB,IAEA,GAAMke,wBAAwB,SAAUoF,EAAetjB,EAAQme,GAC9D,MAAO,CAAEA,EAAW,EAAIA,EAAWne,EAASme,EAC7C,IAEA,KAAQD,wBAAwB,SAAUE,EAAcpe,GAEvD,IADA,IAAIF,EAAI,EACAA,EAAIE,EAAQF,GAAK,EACxBse,EAAatc,KAAMhC,GAEpB,OAAOse,CACR,IAEA,IAAOF,wBAAwB,SAAUE,EAAcpe,GAEtD,IADA,IAAIF,EAAI,EACAA,EAAIE,EAAQF,GAAK,EACxBse,EAAatc,KAAMhC,GAEpB,OAAOse,CACR,IAEA,GAAMF,wBAAwB,SAAUE,EAAcpe,EAAQme,GAM7D,IALA,IAAIre,EAAIqe,EAAW,EAClBA,EAAWne,EACXme,EAAWne,EACVA,EACAme,IACQre,GAAK,GACdse,EAAatc,KAAMhC,GAEpB,OAAOse,CACR,IAEA,GAAMF,wBAAwB,SAAUE,EAAcpe,EAAQme,GAE7D,IADA,IAAIre,EAAIqe,EAAW,EAAIA,EAAWne,EAASme,IACjCre,EAAIE,GACboe,EAAatc,KAAMhC,GAEpB,OAAOse,CACR,MAIF1G,EAAKgC,QAAe,IAAIhC,EAAKgC,QAAc,GAGhC,CAAE6J,OAAO,EAAMC,UAAU,EAAMC,MAAM,EAAMC,UAAU,EAAMC,OAAO,GAC5EjM,EAAKgC,QAAS5Z,GAAMge,kBAAmBhe,GAExC,IAAMA,IAAK,CAAE8jB,QAAQ,EAAMC,OAAO,GACjCnM,EAAKgC,QAAS5Z,GAAMie,mBAAoBje,GAIzC,SAASwiB,aAAc,CA0EvB,SAAS7F,WAAYqH,GAIpB,IAHA,IAAIhkB,EAAI,EACP0V,EAAMsO,EAAO9jB,OACbgU,EAAW,GACJlU,EAAI0V,EAAK1V,IAChBkU,GAAY8P,EAAQhkB,GAAIuE,MAEzB,OAAO2P,CACR,CAEA,SAASsH,cAAemH,EAASsB,EAAYC,GAC5C,IAAIxI,EAAMuI,EAAWvI,IACpByI,EAAOF,EAAWtI,KAClBsB,EAAMkH,GAAQzI,EACd0I,EAAmBF,GAAgB,eAARjH,EAC3BoH,EAAWvL,IAEZ,OAAOmL,EAAW9O,MAGjB,SAAUD,EAAMf,EAASjP,GACxB,KAAUgQ,EAAOA,EAAMwG,IACtB,GAAuB,IAAlBxG,EAAK3N,UAAkB6c,EAC3B,OAAOzB,EAASzN,EAAMf,EAASjP,GAGjC,OAAO,CACR,EAGA,SAAUgQ,EAAMf,EAASjP,GACxB,IAAIof,EAAUtC,EAAaC,EAC1BsC,EAAW,CAAE1L,EAASwL,GAGvB,GAAKnf,GACJ,KAAUgQ,EAAOA,EAAMwG,IACtB,IAAuB,IAAlBxG,EAAK3N,UAAkB6c,IACtBzB,EAASzN,EAAMf,EAASjP,GAC5B,OAAO,OAKV,KAAUgQ,EAAOA,EAAMwG,IACtB,GAAuB,IAAlBxG,EAAK3N,UAAkB6c,EAQ3B,GAHApC,GAJAC,EAAa/M,EAAMoB,KAAepB,EAAMoB,GAAY,CAAC,IAI3BpB,EAAKoN,YAC5BL,EAAY/M,EAAKoN,UAAa,CAAC,GAE7B6B,GAAQA,IAASjP,EAAK/F,SAAShN,cACnC+S,EAAOA,EAAMwG,IAASxG,MAChB,KAAOoP,EAAWtC,EAAa/E,KACrCqH,EAAU,KAAQzL,GAAWyL,EAAU,KAAQD,EAG/C,OAASE,EAAU,GAAMD,EAAU,GAOnC,GAHAtC,EAAa/E,GAAQsH,EAGdA,EAAU,GAAM5B,EAASzN,EAAMf,EAASjP,GAC9C,OAAO,CAET,CAIH,OAAO,CACR,CACF,CAEA,SAASsf,eAAgBC,GACxB,OAAOA,EAASvkB,OAAS,EACxB,SAAUgV,EAAMf,EAASjP,GAExB,IADA,IAAIlF,EAAIykB,EAASvkB,OACTF,KACP,IAAMykB,EAAUzkB,GAAKkV,EAAMf,EAASjP,GACnC,OAAO,EAGT,OAAO,CACR,EACAuf,EAAU,EACZ,CAWA,SAASC,SAAU9B,EAAW3N,EAAKiK,EAAQ/K,EAASjP,GAOnD,IANA,IAAIgQ,EACHyP,EAAe,GACf3kB,EAAI,EACJ0V,EAAMkN,EAAU1iB,OAChB0kB,EAAgB,MAAP3P,EAEFjV,EAAI0V,EAAK1V,KACTkV,EAAO0N,EAAW5iB,MAClBkf,IAAUA,EAAQhK,EAAMf,EAASjP,KACtCyf,EAAa3iB,KAAMkT,GACd0P,GACJ3P,EAAIjT,KAAMhC,KAMd,OAAO2kB,CACR,CAEA,SAASE,WAAY3D,EAAWhN,EAAUyO,EAASmC,EAAYC,EAAYC,GAO1E,OANKF,IAAeA,EAAYxO,KAC/BwO,EAAaD,WAAYC,IAErBC,IAAeA,EAAYzO,KAC/ByO,EAAaF,WAAYE,EAAYC,IAE/B5H,cAAc,SAAUtB,EAAM5E,EAAS/C,EAASjP,GACtD,IAAI+f,EAAMjlB,EAAGkV,EACZgQ,EAAS,GACTC,EAAU,GACVC,EAAclO,EAAQhX,OAGtByU,EAAQmH,GA5CX,SAASuJ,iBAAkBnR,EAAUoR,EAAUpO,GAG9C,IAFA,IAAIlX,EAAI,EACP0V,EAAM4P,EAASplB,OACRF,EAAI0V,EAAK1V,IAChB2X,OAAQzD,EAAUoR,EAAUtlB,GAAKkX,GAElC,OAAOA,CACR,CAqCmBmO,CACfnR,GAAY,IACZC,EAAQ5M,SAAW,CAAE4M,GAAYA,EACjC,IAIDoR,GAAYrE,IAAepF,GAAS5H,EAEnCS,EADA+P,SAAU/P,EAAOuQ,EAAQhE,EAAW/M,EAASjP,GAG9CsgB,EAAa7C,EAGZoC,IAAgBjJ,EAAOoF,EAAYkE,GAAeN,GAGjD,GAGA5N,EACDqO,EAQF,GALK5C,GACJA,EAAS4C,EAAWC,EAAYrR,EAASjP,GAIrC4f,EAMJ,IALAG,EAAOP,SAAUc,EAAYL,GAC7BL,EAAYG,EAAM,GAAI9Q,EAASjP,GAG/BlF,EAAIilB,EAAK/kB,OACDF,MACAkV,EAAO+P,EAAMjlB,MACnBwlB,EAAYL,EAASnlB,MAAWulB,EAAWJ,EAASnlB,IAAQkV,IAK/D,GAAK4G,GACJ,GAAKiJ,GAAc7D,EAAY,CAC9B,GAAK6D,EAAa,CAKjB,IAFAE,EAAO,GACPjlB,EAAIwlB,EAAWtlB,OACPF,MACAkV,EAAOsQ,EAAYxlB,KAGzBilB,EAAKjjB,KAAQujB,EAAWvlB,GAAMkV,GAGhC6P,EAAY,KAAQS,EAAa,GAAMP,EAAM/f,EAC9C,CAIA,IADAlF,EAAIwlB,EAAWtlB,OACPF,MACAkV,EAAOsQ,EAAYxlB,MACvBilB,EAAOF,EAAatiB,QAASqZ,EAAM5G,GAASgQ,EAAQllB,KAAS,IAE/D8b,EAAMmJ,KAAY/N,EAAS+N,GAAS/P,GAGvC,OAIAsQ,EAAad,SACZc,IAAetO,EACdsO,EAAW1P,OAAQsP,EAAaI,EAAWtlB,QAC3CslB,GAEGT,EACJA,EAAY,KAAM7N,EAASsO,EAAYtgB,GAEvClD,EAAKjB,MAAOmW,EAASsO,EAGxB,GACD,CAEA,SAASC,kBAAmBzB,GAyB3B,IAxBA,IAAI0B,EAAc/C,EAAShN,EAC1BD,EAAMsO,EAAO9jB,OACbylB,EAAkB/N,EAAKqJ,SAAU+C,EAAQ,GAAIzQ,MAC7CqS,EAAmBD,GAAmB/N,EAAKqJ,SAAU,KACrDjhB,EAAI2lB,EAAkB,EAAI,EAG1BE,EAAerK,eAAe,SAAUtG,GACvC,OAAOA,IAASwQ,CACjB,GAAGE,GAAkB,GACrBE,EAAkBtK,eAAe,SAAUtG,GAC1C,OAAOzS,QAASijB,EAAcxQ,IAAU,CACzC,GAAG0Q,GAAkB,GACrBnB,EAAW,CAAE,SAAUvP,EAAMf,EAASjP,GACrC,IAAI0P,GAAS+Q,IAAqBzgB,GAAOiP,IAAY+D,MAClDwN,EAAevR,GAAU5M,SAC1Bse,EAAc3Q,EAAMf,EAASjP,GAC7B4gB,EAAiB5Q,EAAMf,EAASjP,IAIlC,OADAwgB,EAAe,KACR9Q,CACR,GAEO5U,EAAI0V,EAAK1V,IAChB,GAAO2iB,EAAU/K,EAAKqJ,SAAU+C,EAAQhkB,GAAIuT,MAC3CkR,EAAW,CAAEjJ,cAAegJ,eAAgBC,GAAY9B,QAClD,CAIN,IAHAA,EAAU/K,EAAKsH,OAAQ8E,EAAQhkB,GAAIuT,MAAOxS,MAAO,KAAMijB,EAAQhkB,GAAIkO,UAGrDoI,GAAY,CAIzB,IADAX,IAAM3V,EACE2V,EAAID,IACNkC,EAAKqJ,SAAU+C,EAAQrO,GAAIpC,MADhBoC,KAKjB,OAAOkP,WACN7kB,EAAI,GAAKwkB,eAAgBC,GACzBzkB,EAAI,GAAK2c,WAGTqH,EACEpR,MAAO,EAAG5S,EAAI,GACdyB,OAAQ,CAAE8C,MAAgC,MAAzByf,EAAQhkB,EAAI,GAAIuT,KAAe,IAAM,MACtDhR,QAASuX,EAAO,MAClB6I,EACA3iB,EAAI2V,GAAK8P,kBAAmBzB,EAAOpR,MAAO5S,EAAG2V,IAC7CA,EAAID,GAAO+P,kBAAqBzB,EAASA,EAAOpR,MAAO+C,IACvDA,EAAID,GAAOiH,WAAYqH,GAEzB,CACAS,EAASziB,KAAM2gB,EAChB,CAGD,OAAO6B,eAAgBC,EACxB,CAmTA,OAtpBAjC,WAAWjhB,UAAYqW,EAAKmO,QAAUnO,EAAKgC,QAC3ChC,EAAK4K,WAAa,IAAIA,WAEtBzK,EAAWJ,OAAOI,SAAW,SAAU7D,EAAU8R,GAChD,IAAItD,EAASrgB,EAAO2hB,EAAQzQ,EAC3B0S,EAAOhK,EAAQiK,EACfC,EAASlN,EAAY/E,EAAW,KAEjC,GAAKiS,EACJ,OAAOH,EAAY,EAAIG,EAAOvT,MAAO,GAOtC,IAJAqT,EAAQ/R,EACR+H,EAAS,GACTiK,EAAatO,EAAKsJ,UAEV+E,GAAQ,CA2Bf,IAAM1S,KAxBAmP,KAAargB,EAAQ0X,EAAOqC,KAAM6J,MAClC5jB,IAGJ4jB,EAAQA,EAAMrT,MAAOvQ,EAAO,GAAInC,SAAY+lB,GAE7ChK,EAAOja,KAAQgiB,EAAS,KAGzBtB,GAAU,GAGHrgB,EAAQ2X,EAAaoC,KAAM6J,MACjCvD,EAAUrgB,EAAM8a,QAChB6G,EAAOhiB,KAAM,CACZuC,MAAOme,EAGPnP,KAAMlR,EAAO,GAAIE,QAASuX,EAAO,OAElCmM,EAAQA,EAAMrT,MAAO8P,EAAQxiB,SAIhB0X,EAAKsH,SACX7c,EAAQ+X,EAAW7G,GAAO6I,KAAM6J,KAAgBC,EAAY3S,MAChElR,EAAQ6jB,EAAY3S,GAAQlR,MAC9BqgB,EAAUrgB,EAAM8a,QAChB6G,EAAOhiB,KAAM,CACZuC,MAAOme,EACPnP,KAAMA,EACNrF,QAAS7L,IAEV4jB,EAAQA,EAAMrT,MAAO8P,EAAQxiB,SAI/B,IAAMwiB,EACL,KAEF,CAKA,OAAOsD,EACNC,EAAM/lB,OACN+lB,EACCtO,OAAOjB,MAAOxC,GAGd+E,EAAY/E,EAAU+H,GAASrJ,MAAO,EACzC,EA2ZAoF,EAAUL,OAAOK,QAAU,SAAU9D,EAAU7R,GAC9C,IAAIrC,EACHomB,EAAc,GACdC,EAAkB,GAClBF,EAASjN,EAAehF,EAAW,KAEpC,IAAMiS,EAAS,CAOd,IAJM9jB,IACLA,EAAQ0V,EAAU7D,IAEnBlU,EAAIqC,EAAMnC,OACFF,MACPmmB,EAASV,kBAAmBpjB,EAAOrC,KACtBsW,GACZ8P,EAAYpkB,KAAMmkB,GAElBE,EAAgBrkB,KAAMmkB,GAKxBA,EAASjN,EACRhF,EArJH,SAASoS,yBAA0BD,EAAiBD,GACnD,IAAIG,EAAQH,EAAYlmB,OAAS,EAChCsmB,EAAYH,EAAgBnmB,OAAS,EACrCumB,aAAe,SAAU3K,EAAM3H,EAASjP,EAAKgS,EAASwP,GACrD,IAAIxR,EAAMS,EAAGgN,EACZgE,EAAe,EACf3mB,EAAI,IACJ4iB,EAAY9G,GAAQ,GACpB8K,EAAa,GACbC,EAAgB3O,EAGhBvD,EAAQmH,GAAQ0K,GAAa5O,EAAKwH,KAAY,IAAG,IAAKsH,GAGtDI,EAAkBjO,GAA4B,MAAjBgO,EAAwB,EAAItQ,KAAKC,UAAY,GAC1Ed,EAAMf,EAAMzU,OAcb,IAZKwmB,IAMJxO,EAAmB/D,GAAW/N,GAAY+N,GAAWuS,GAM9C1mB,IAAM0V,GAAgC,OAAvBR,EAAOP,EAAO3U,IAAeA,IAAM,CACzD,GAAKwmB,GAAatR,EAAO,CAWxB,IAVAS,EAAI,EAMExB,GAAWe,EAAKrM,eAAiBzC,IACtCiS,EAAanD,GACbhQ,GAAOqT,GAEEoK,EAAU0D,EAAiB1Q,MACpC,GAAKgN,EAASzN,EAAMf,GAAW/N,EAAUlB,GAAQ,CAChDgS,EAAQlV,KAAMkT,GACd,KACD,CAEIwR,IACJ7N,EAAUiO,EAEZ,CAGKP,KAGGrR,GAAQyN,GAAWzN,IACzByR,IAII7K,GACJ8G,EAAU5gB,KAAMkT,GAGnB,CAaA,GATAyR,GAAgB3mB,EASXumB,GAASvmB,IAAM2mB,EAAe,CAElC,IADAhR,EAAI,EACMgN,EAAUyD,EAAazQ,MAChCgN,EAASC,EAAWgE,EAAYzS,EAASjP,GAG1C,GAAK4W,EAAO,CAGX,GAAK6K,EAAe,EACnB,KAAQ3mB,KACC4iB,EAAW5iB,IAAO4mB,EAAY5mB,KACrC4mB,EAAY5mB,GAAM8B,EAAI6M,KAAMuI,IAM/B0P,EAAalC,SAAUkC,EACxB,CAGA5kB,EAAKjB,MAAOmW,EAAS0P,GAGhBF,IAAc5K,GAAQ8K,EAAW1mB,OAAS,GAC5CymB,EAAeP,EAAYlmB,OAAW,GAExCyX,OAAO+I,WAAYxJ,EAErB,CAQA,OALKwP,IACJ7N,EAAUiO,EACV5O,EAAmB2O,GAGbjE,CACR,EAED,OAAO2D,EACNnJ,aAAcqJ,cACdA,YACF,CA2BGH,CAA0BD,EAAiBD,IAI5CD,EAAOjS,SAAWA,CACnB,CACA,OAAOiS,CACR,EAWAlO,EAASN,OAAOM,OAAS,SAAU/D,EAAUC,EAAS+C,EAAS4E,GAC9D,IAAI9b,EAAGgkB,EAAQ+C,EAAOxT,EAAM6L,EAC3B4H,EAA+B,mBAAb9S,GAA2BA,EAC7C7R,GAASyZ,GAAQ/D,EAAY7D,EAAW8S,EAAS9S,UAAYA,GAM9D,GAJAgD,EAAUA,GAAW,GAIC,IAAjB7U,EAAMnC,OAAe,CAIzB,IADA8jB,EAAS3hB,EAAO,GAAMA,EAAO,GAAIuQ,MAAO,IAC5B1S,OAAS,GAAsC,QAA/B6mB,EAAQ/C,EAAQ,IAAMzQ,MAC5B,IAArBY,EAAQ5M,UAAkBgR,GAAkBX,EAAKqJ,SAAU+C,EAAQ,GAAIzQ,MAAS,CAIhF,KAFAY,GAAYyD,EAAKwH,KAAW,GAAG2H,EAAM7Y,QAAS,GAC5C3L,QAASoY,GAAWC,WAAazG,IAAa,IAAM,IAErD,OAAO+C,EAGI8P,IACX7S,EAAUA,EAAQ9G,YAGnB6G,EAAWA,EAAStB,MAAOoR,EAAO7G,QAAQ5Y,MAAMrE,OACjD,CAIA,IADAF,EAAIoa,EAA0B,aAAEtX,KAAMoR,GAAa,EAAI8P,EAAO9jB,OACtDF,MACP+mB,EAAQ/C,EAAQhkB,IAGX4X,EAAKqJ,SAAY1N,EAAOwT,EAAMxT,QAGnC,IAAO6L,EAAOxH,EAAKwH,KAAM7L,MAGjBuI,EAAOsD,EACb2H,EAAM7Y,QAAS,GAAI3L,QAASoY,GAAWC,WACvCF,GAAS5X,KAAMkhB,EAAQ,GAAIzQ,OAAUkJ,YAAatI,EAAQ9G,aACzD8G,IACI,CAKL,GAFA6P,EAAOlO,OAAQ9V,EAAG,KAClBkU,EAAW4H,EAAK5b,QAAUyc,WAAYqH,IAGrC,OADAhiB,EAAKjB,MAAOmW,EAAS4E,GACd5E,EAGR,KACD,CAGH,CAWA,OAPE8P,GAAYhP,EAAS9D,EAAU7R,IAChCyZ,EACA3H,GACCoE,EACDrB,GACC/C,GAAWuG,GAAS5X,KAAMoR,IAAcuI,YAAatI,EAAQ9G,aAAgB8G,GAExE+C,CACR,EAKAhE,EAAQ2N,WAAavK,EAAQmB,MAAO,IAAK5B,KAAMuD,WAAYwD,KAAM,MAAStG,EAI1EpD,EAAQ0N,mBAAqBxI,EAG7BC,IAIAnF,EAAQ+M,aAAe5C,QAAQ,SAAUC,GAGxC,OAA4E,EAArEA,EAAGuC,wBAAyBzZ,EAASuC,cAAe,YAC5D,IAKM0U,QAAQ,SAAUC,GAEvB,OADAA,EAAGvN,UAAY,mBACiC,MAAzCuN,EAAG7L,WAAW/K,aAAc,OACpC,KACC6W,UAAW,0BAA0B,SAAUrI,EAAMxH,EAAMoK,GAC1D,IAAMA,EACL,OAAO5C,EAAKxO,aAAcgH,EAA6B,SAAvBA,EAAKvL,cAA2B,EAAI,EAEtE,IAKK+Q,EAAQ7D,YAAegO,QAAQ,SAAUC,GAG9C,OAFAA,EAAGvN,UAAY,WACfuN,EAAG7L,WAAWnC,aAAc,QAAS,IACY,KAA1CgO,EAAG7L,WAAW/K,aAAc,QACpC,KACC6W,UAAW,SAAS,SAAUrI,EAAM+R,EAAOnP,GAC1C,IAAMA,GAAyC,UAAhC5C,EAAK/F,SAAShN,cAC5B,OAAO+S,EAAKgS,YAEd,IAKK7J,QAAQ,SAAUC,GACvB,OAAwC,MAAjCA,EAAG5W,aAAc,WACzB,KACC6W,UAAW9D,GAAU,SAAUvE,EAAMxH,EAAMoK,GAC1C,IAAIjE,EACJ,IAAMiE,EACL,OAAwB,IAAjB5C,EAAMxH,GAAkBA,EAAKvL,eACjC0R,EAAMqB,EAAKtH,iBAAkBF,KAAYmG,EAAI2M,UAC9C3M,EAAItP,MACJ,IAEJ,IAGMoT,MAEL,CA54EF,CA44EK1R,GAILgO,OAAOmL,KAAOzH,EACd1D,OAAOqM,KAAO3I,EAAOoJ,UAGrB9M,OAAOqM,KAAM,KAAQrM,OAAOqM,KAAK1G,QACjC3F,OAAOyM,WAAazM,OAAOkT,OAASxP,EAAO+I,WAC3CzM,OAAOnP,KAAO6S,EAAOE,QACrB5D,OAAOmT,SAAWzP,EAAOG,MACzB7D,OAAOyE,SAAWf,EAAOe,SACzBzE,OAAOoT,eAAiB1P,EAAOkD,OAK/B,IAAIa,IAAM,SAAUxG,EAAMwG,EAAK4L,GAI9B,IAHA,IAAI5E,EAAU,GACb6E,OAAqBrgB,IAAVogB,GAEFpS,EAAOA,EAAMwG,KAA6B,IAAlBxG,EAAK3N,UACtC,GAAuB,IAAlB2N,EAAK3N,SAAiB,CAC1B,GAAKggB,GAAYtT,OAAQiB,GAAOsS,GAAIF,GACnC,MAED5E,EAAQ1gB,KAAMkT,EACf,CAED,OAAOwN,CACR,EAGI+E,SAAW,SAAUC,EAAGxS,GAG3B,IAFA,IAAIwN,EAAU,GAENgF,EAAGA,EAAIA,EAAE3J,YACI,IAAf2J,EAAEngB,UAAkBmgB,IAAMxS,GAC9BwN,EAAQ1gB,KAAM0lB,GAIhB,OAAOhF,CACR,EAGIiF,EAAgB1T,OAAOqM,KAAKje,MAAMulB,aAItC,SAASzY,SAAU+F,EAAMxH,GAExB,OAAOwH,EAAK/F,UAAY+F,EAAK/F,SAAShN,gBAAkBuL,EAAKvL,aAE9D,CACA,IAAI0lB,EAAa,kEAKjB,SAASC,OAAQvH,EAAUwH,EAAWC,GACrC,OAAK7U,EAAY4U,GACT9T,OAAOsB,KAAMgL,GAAU,SAAUrL,EAAMlV,GAC7C,QAAS+nB,EAAUpZ,KAAMuG,EAAMlV,EAAGkV,KAAW8S,CAC9C,IAIID,EAAUxgB,SACP0M,OAAOsB,KAAMgL,GAAU,SAAUrL,GACvC,OAASA,IAAS6S,IAAgBC,CACnC,IAIyB,iBAAdD,EACJ9T,OAAOsB,KAAMgL,GAAU,SAAUrL,GACvC,OAASzS,EAAQkM,KAAMoZ,EAAW7S,IAAU,IAAQ8S,CACrD,IAIM/T,OAAOiL,OAAQ6I,EAAWxH,EAAUyH,EAC5C,CAEA/T,OAAOiL,OAAS,SAAUoB,EAAM3L,EAAOqT,GACtC,IAAI9S,EAAOP,EAAO,GAMlB,OAJKqT,IACJ1H,EAAO,QAAUA,EAAO,KAGH,IAAjB3L,EAAMzU,QAAkC,IAAlBgV,EAAK3N,SACxB0M,OAAOmL,KAAKG,gBAAiBrK,EAAMoL,GAAS,CAAEpL,GAAS,GAGxDjB,OAAOmL,KAAKlR,QAASoS,EAAMrM,OAAOsB,KAAMZ,GAAO,SAAUO,GAC/D,OAAyB,IAAlBA,EAAK3N,QACb,IACD,EAEA0M,OAAOG,GAAG2B,OAAQ,CACjBqJ,KAAM,SAAUlL,GACf,IAAIlU,EAAG4U,EACNc,EAAMjD,KAAKvS,OACX+nB,EAAOxV,KAER,GAAyB,iBAAbyB,EACX,OAAOzB,KAAKiC,UAAWT,OAAQC,GAAWgL,QAAQ,WACjD,IAAMlf,EAAI,EAAGA,EAAI0V,EAAK1V,IACrB,GAAKiU,OAAOyE,SAAUuP,EAAMjoB,GAAKyS,MAChC,OAAO,CAGV,KAKD,IAFAmC,EAAMnC,KAAKiC,UAAW,IAEhB1U,EAAI,EAAGA,EAAI0V,EAAK1V,IACrBiU,OAAOmL,KAAMlL,EAAU+T,EAAMjoB,GAAK4U,GAGnC,OAAOc,EAAM,EAAIzB,OAAOyM,WAAY9L,GAAQA,CAC7C,EACAsK,OAAQ,SAAUhL,GACjB,OAAOzB,KAAKiC,UAAWoT,OAAQrV,KAAMyB,GAAY,IAAI,GACtD,EACA8T,IAAK,SAAU9T,GACd,OAAOzB,KAAKiC,UAAWoT,OAAQrV,KAAMyB,GAAY,IAAI,GACtD,EACAsT,GAAI,SAAUtT,GACb,QAAS4T,OACRrV,KAIoB,iBAAbyB,GAAyByT,EAAc7kB,KAAMoR,GACnDD,OAAQC,GACRA,GAAY,IACb,GACChU,MACH,IAQD,IAAIgoB,EAMHzN,EAAa,uCAENxG,OAAOG,GAAGC,KAAO,SAAUH,EAAUC,EAAS/M,GACpD,IAAI/E,EAAO6S,EAGX,IAAMhB,EACL,OAAOzB,KAQR,GAHArL,EAAOA,GAAQ8gB,EAGU,iBAAbhU,EAAwB,CAanC,KAPC7R,EALsB,MAAlB6R,EAAU,IACsB,MAApCA,EAAUA,EAAShU,OAAS,IAC5BgU,EAAShU,QAAU,EAGX,CAAE,KAAMgU,EAAU,MAGlBuG,EAAW2B,KAAMlI,MAIV7R,EAAO,IAAQ8R,EA6CxB,OAAMA,GAAWA,EAAQI,QACtBJ,GAAW/M,GAAOgY,KAAMlL,GAK1BzB,KAAK3M,YAAaqO,GAAUiL,KAAMlL,GAhDzC,GAAK7R,EAAO,GAAM,CAYjB,GAXA8R,EAAUA,aAAmBF,OAASE,EAAS,GAAMA,EAIrDF,OAAOY,MAAOpC,KAAMwB,OAAOkU,UAC1B9lB,EAAO,GACP8R,GAAWA,EAAQ5M,SAAW4M,EAAQtL,eAAiBsL,EAAU/N,GACjE,IAIIyhB,EAAW/kB,KAAMT,EAAO,KAAS4R,OAAOoC,cAAelC,GAC3D,IAAM9R,KAAS8R,EAGThB,EAAYV,KAAMpQ,IACtBoQ,KAAMpQ,GAAS8R,EAAS9R,IAIxBoQ,KAAKrC,KAAM/N,EAAO8R,EAAS9R,IAK9B,OAAOoQ,IAGR,CASC,OARAyC,EAAO9O,EAASiW,eAAgBha,EAAO,OAKtCoQ,KAAM,GAAMyC,EACZzC,KAAKvS,OAAS,GAERuS,IAcV,CAAO,OAAKyB,EAAS3M,UACpBkL,KAAM,GAAMyB,EACZzB,KAAKvS,OAAS,EACPuS,MAIIU,EAAYe,QACDhN,IAAfE,EAAKghB,MACXhhB,EAAKghB,MAAOlU,GAGZA,EAAUD,QAGLA,OAAOgD,UAAW/C,EAAUzB,KACpC,GAGIlR,UAAY0S,OAAOG,GAGxB8T,EAAajU,OAAQ7N,GAGrB,IAAIiiB,EAAe,iCAGlBC,EAAmB,CAClBC,UAAU,EACVC,UAAU,EACV7M,MAAM,EACN8M,MAAM,GAoFR,SAASC,QAAS9K,EAAKlC,GACtB,MAAUkC,EAAMA,EAAKlC,KAA4B,IAAjBkC,EAAIrW,WACpC,OAAOqW,CACR,CApFA3J,OAAOG,GAAG2B,OAAQ,CACjB4S,IAAK,SAAUxS,GACd,IAAIyS,EAAU3U,OAAQkC,EAAQ1D,MAC7B7O,EAAIglB,EAAQ1oB,OAEb,OAAOuS,KAAKyM,QAAQ,WAEnB,IADA,IAAIlf,EAAI,EACAA,EAAI4D,EAAG5D,IACd,GAAKiU,OAAOyE,SAAUjG,KAAMmW,EAAS5oB,IACpC,OAAO,CAGV,GACD,EAEA6oB,QAAS,SAAU9H,EAAW5M,GAC7B,IAAIyJ,EACH5d,EAAI,EACJ4D,EAAI6O,KAAKvS,OACTwiB,EAAU,GACVkG,EAA+B,iBAAd7H,GAA0B9M,OAAQ8M,GAGpD,IAAM4G,EAAc7kB,KAAMie,GACzB,KAAQ/gB,EAAI4D,EAAG5D,IACd,IAAM4d,EAAMnL,KAAMzS,GAAK4d,GAAOA,IAAQzJ,EAASyJ,EAAMA,EAAIvQ,WAGxD,GAAKuQ,EAAIrW,SAAW,KAAQqhB,EAC3BA,EAAQE,MAAOlL,IAAS,EAGP,IAAjBA,EAAIrW,UACH0M,OAAOmL,KAAKG,gBAAiB3B,EAAKmD,IAAgB,CAEnD2B,EAAQ1gB,KAAM4b,GACd,KACD,CAKH,OAAOnL,KAAKiC,UAAWgO,EAAQxiB,OAAS,EAAI+T,OAAOyM,WAAYgC,GAAYA,EAC5E,EAGAoG,MAAO,SAAU5T,GAGhB,OAAMA,EAKe,iBAATA,EACJzS,EAAQkM,KAAMsF,OAAQiB,GAAQzC,KAAM,IAIrChQ,EAAQkM,KAAM8D,KAGpByC,EAAKX,OAASW,EAAM,GAAMA,GAZjBzC,KAAM,IAAOA,KAAM,GAAIpF,WAAeoF,KAAK0C,QAAQ4T,UAAU7oB,QAAU,CAclF,EAEA8oB,IAAK,SAAU9U,EAAUC,GACxB,OAAO1B,KAAKiC,UACXT,OAAOyM,WACNzM,OAAOY,MAAOpC,KAAKnO,MAAO2P,OAAQC,EAAUC,KAG/C,EAEA8U,QAAS,SAAU/U,GAClB,OAAOzB,KAAKuW,IAAiB,MAAZ9U,EAChBzB,KAAKqC,WAAarC,KAAKqC,WAAWoK,OAAQhL,GAE5C,IAQDD,OAAOc,KAAM,CACZlI,OAAQ,SAAUqI,GACjB,IAAIrI,EAASqI,EAAK7H,WAClB,OAAOR,GAA8B,KAApBA,EAAOtF,SAAkBsF,EAAS,IACpD,EACAqc,QAAS,SAAUhU,GAClB,OAAOwG,IAAKxG,EAAM,aACnB,EACAiU,aAAc,SAAUjU,EAAMwC,EAAI4P,GACjC,OAAO5L,IAAKxG,EAAM,aAAcoS,EACjC,EACA3L,KAAM,SAAUzG,GACf,OAAOwT,QAASxT,EAAM,cACvB,EACAuT,KAAM,SAAUvT,GACf,OAAOwT,QAASxT,EAAM,kBACvB,EACAkU,QAAS,SAAUlU,GAClB,OAAOwG,IAAKxG,EAAM,cACnB,EACA6T,QAAS,SAAU7T,GAClB,OAAOwG,IAAKxG,EAAM,kBACnB,EACAmU,UAAW,SAAUnU,EAAMwC,EAAI4P,GAC9B,OAAO5L,IAAKxG,EAAM,cAAeoS,EAClC,EACAgC,UAAW,SAAUpU,EAAMwC,EAAI4P,GAC9B,OAAO5L,IAAKxG,EAAM,kBAAmBoS,EACtC,EACAG,SAAU,SAAUvS,GACnB,OAAOuS,UAAYvS,EAAK7H,YAAc,CAAC,GAAIoE,WAAYyD,EACxD,EACAqT,SAAU,SAAUrT,GACnB,OAAOuS,SAAUvS,EAAKzD,WACvB,EACA+W,SAAU,SAAUtT,GACnB,OAA6B,MAAxBA,EAAKqU,iBAKT5W,EAAUuC,EAAKqU,iBAERrU,EAAKqU,iBAMRpa,SAAU+F,EAAM,cACpBA,EAAOA,EAAKtM,SAAWsM,GAGjBjB,OAAOY,MAAO,GAAIK,EAAKxG,YAC/B,IACE,SAAUhB,EAAM0G,GAClBH,OAAOG,GAAI1G,GAAS,SAAU4Z,EAAOpT,GACpC,IAAIwO,EAAUzO,OAAOgB,IAAKxC,KAAM2B,EAAIkT,GAuBpC,MArB0B,UAArB5Z,EAAKkF,OAAQ,KACjBsB,EAAWoT,GAGPpT,GAAgC,iBAAbA,IACvBwO,EAAUzO,OAAOiL,OAAQhL,EAAUwO,IAG/BjQ,KAAKvS,OAAS,IAGZooB,EAAkB5a,IACvBuG,OAAOyM,WAAYgC,GAIf2F,EAAavlB,KAAM4K,IACvBgV,EAAQ8G,WAIH/W,KAAKiC,UAAWgO,EACxB,CACD,IACA,IAAI+G,EAAgB,oBAsOpB,SAASC,SAAUC,GAClB,OAAOA,CACR,CACA,SAASC,QAASC,GACjB,MAAMA,CACP,CAEA,SAASC,WAAYvlB,EAAOwlB,EAASC,EAAQC,GAC5C,IAAIC,EAEJ,IAGM3lB,GAAS4O,EAAc+W,EAAS3lB,EAAM4lB,SAC1CD,EAAOvb,KAAMpK,GAAQuU,KAAMiR,GAAUK,KAAMJ,GAGhCzlB,GAAS4O,EAAc+W,EAAS3lB,EAAM8lB,MACjDH,EAAOvb,KAAMpK,EAAOwlB,EAASC,GAQ7BD,EAAQhpB,WAAOmG,EAAW,CAAE3C,GAAQqO,MAAOqX,GAM7C,CAAE,MAAQ1lB,GAITylB,EAAOjpB,WAAOmG,EAAW,CAAE3C,GAC5B,CACD,CAzOA0P,OAAOqW,UAAY,SAAUtU,GAI5BA,EAA6B,iBAAZA,EAlClB,SAASuU,cAAevU,GACvB,IAAIhS,EAAS,CAAC,EAId,OAHAiQ,OAAOc,KAAMiB,EAAQ3T,MAAOonB,IAAmB,IAAI,SAAU3iB,EAAG0jB,GAC/DxmB,EAAQwmB,IAAS,CAClB,IACOxmB,CACR,CA6BEumB,CAAevU,GACf/B,OAAO8B,OAAQ,CAAC,EAAGC,GAEpB,IACCyU,EAGAC,EAGAC,EAGAC,EAGApR,EAAO,GAGPqR,EAAQ,GAGRC,GAAe,EAGfC,KAAO,WAQN,IALAH,EAASA,GAAU5U,EAAQgV,KAI3BL,EAAQF,GAAS,EACTI,EAAM3qB,OAAQ4qB,GAAe,EAEpC,IADAJ,EAASG,EAAM1N,UACL2N,EAActR,EAAKtZ,SAGmC,IAA1DsZ,EAAMsR,GAAc/pB,MAAO2pB,EAAQ,GAAKA,EAAQ,KACpD1U,EAAQiV,cAGRH,EAActR,EAAKtZ,OACnBwqB,GAAS,GAMN1U,EAAQ0U,SACbA,GAAS,GAGVD,GAAS,EAGJG,IAIHpR,EADIkR,EACG,GAIA,GAGV,EAGAzC,EAAO,CAGNe,IAAK,WA2BJ,OA1BKxP,IAGCkR,IAAWD,IACfK,EAActR,EAAKtZ,OAAS,EAC5B2qB,EAAM7oB,KAAM0oB,IAGb,SAAW1B,IAAK7nB,GACf8S,OAAOc,KAAM5T,GAAM,SAAU2F,EAAGyQ,GAC1BpE,EAAYoE,GACVvB,EAAQmR,QAAWc,EAAKU,IAAKpR,IAClCiC,EAAKxX,KAAMuV,GAEDA,GAAOA,EAAIrX,QAA4B,WAAlB8T,OAAQuD,IAGxCyR,IAAKzR,EAEP,GACC,CAZF,CAYKlU,WAEAqnB,IAAWD,GACfM,QAGKtY,IACR,EAGAjF,OAAQ,WAYP,OAXAyG,OAAOc,KAAM1R,WAAW,SAAUyD,EAAGyQ,GAEpC,IADA,IAAIuR,GACMA,EAAQ7U,OAAOkD,QAASI,EAAKiC,EAAMsP,KAAa,GACzDtP,EAAK1D,OAAQgT,EAAO,GAGfA,GAASgC,GACbA,GAGH,IACOrY,IACR,EAIAkW,IAAK,SAAUvU,GACd,OAAOA,EACNH,OAAOkD,QAAS/C,EAAIoF,IAAU,EAC9BA,EAAKtZ,OAAS,CAChB,EAGAgrB,MAAO,WAIN,OAHK1R,IACJA,EAAO,IAED/G,IACR,EAKA0Y,QAAS,WAGR,OAFAP,EAASC,EAAQ,GACjBrR,EAAOkR,EAAS,GACTjY,IACR,EACAgJ,SAAU,WACT,OAAQjC,CACT,EAKA4R,KAAM,WAKL,OAJAR,EAASC,EAAQ,GACXH,GAAWD,IAChBjR,EAAOkR,EAAS,IAEVjY,IACR,EACAmY,OAAQ,WACP,QAASA,CACV,EAGAS,SAAU,SAAUlX,EAAShT,GAS5B,OARMypB,IAELzpB,EAAO,CAAEgT,GADThT,EAAOA,GAAQ,IACQyR,MAAQzR,EAAKyR,QAAUzR,GAC9C0pB,EAAM7oB,KAAMb,GACNspB,GACLM,QAGKtY,IACR,EAGAsY,KAAM,WAEL,OADA9C,EAAKoD,SAAU5Y,KAAMpP,WACdoP,IACR,EAGAkY,MAAO,WACN,QAASA,CACV,GAGF,OAAO1C,CACR,EA2CAhU,OAAO8B,OAAQ,CAEduV,SAAU,SAAUpoB,GACnB,IAAIqoB,EAAS,CAIX,CAAE,SAAU,WAAYtX,OAAOqW,UAAW,UACzCrW,OAAOqW,UAAW,UAAY,GAC/B,CAAE,UAAW,OAAQrW,OAAOqW,UAAW,eACtCrW,OAAOqW,UAAW,eAAiB,EAAG,YACvC,CAAE,SAAU,OAAQrW,OAAOqW,UAAW,eACrCrW,OAAOqW,UAAW,eAAiB,EAAG,aAExCkB,EAAQ,UACRrB,EAAU,CACTqB,MAAO,WACN,OAAOA,CACR,EACAC,OAAQ,WAEP,OADAC,EAAS5S,KAAMzV,WAAY+mB,KAAM/mB,WAC1BoP,IACR,EACA,MAAS,SAAU2B,GAClB,OAAO+V,EAAQE,KAAM,KAAMjW,EAC5B,EAGAuX,KAAM,WACL,IAAIC,EAAMvoB,UAEV,OAAO4Q,OAAOqX,UAAU,SAAUO,GACjC5X,OAAOc,KAAMwW,GAAQ,SAAU7T,EAAIoU,GAGlC,IAAI1X,EAAKjB,EAAYyY,EAAKE,EAAO,MAAWF,EAAKE,EAAO,IAKxDJ,EAAUI,EAAO,KAAO,WACvB,IAAIC,EAAW3X,GAAMA,EAAGrT,MAAO0R,KAAMpP,WAChC0oB,GAAY5Y,EAAY4Y,EAAS5B,SACrC4B,EAAS5B,UACP6B,SAAUH,EAASI,QACnBnT,KAAM+S,EAAS9B,SACfK,KAAMyB,EAAS7B,QAEjB6B,EAAUC,EAAO,GAAM,QACtBrZ,KACA2B,EAAK,CAAE2X,GAAa1oB,UAGvB,GACD,IACAuoB,EAAM,IACP,IAAIzB,SACL,EACAE,KAAM,SAAU6B,EAAaC,EAAYC,GACxC,IAAIC,EAAW,EACf,SAAStC,QAASuC,EAAOZ,EAAUjO,EAAS8O,GAC3C,OAAO,WACN,IAAIC,EAAO/Z,KACVtR,EAAOkC,UACPopB,WAAa,WACZ,IAAIV,EAAU1B,EAKd,KAAKiC,EAAQD,GAAb,CAQA,IAJAN,EAAWtO,EAAQ1c,MAAOyrB,EAAMrrB,MAIduqB,EAASvB,UAC1B,MAAM,IAAIlnB,UAAW,4BAOtBonB,EAAO0B,IAKgB,iBAAbA,GACY,mBAAbA,IACRA,EAAS1B,KAGLlX,EAAYkX,GAGXkC,EACJlC,EAAK1b,KACJod,EACAhC,QAASsC,EAAUX,EAAUhC,SAAU6C,GACvCxC,QAASsC,EAAUX,EAAU9B,QAAS2C,KAOvCF,IAEAhC,EAAK1b,KACJod,EACAhC,QAASsC,EAAUX,EAAUhC,SAAU6C,GACvCxC,QAASsC,EAAUX,EAAU9B,QAAS2C,GACtCxC,QAASsC,EAAUX,EAAUhC,SAC5BgC,EAASgB,eASPjP,IAAYiM,WAChB8C,OAAOtlB,EACP/F,EAAO,CAAE4qB,KAKRQ,GAAWb,EAASiB,aAAeH,EAAMrrB,GA7D5C,CA+DD,EAGAyrB,EAAUL,EACTE,WACA,WACC,IACCA,YACD,CAAE,MAAQ7Q,GAEJ3H,OAAOqX,SAASuB,eACpB5Y,OAAOqX,SAASuB,cAAejR,EAC9BgR,EAAQE,YAMLR,EAAQ,GAAKD,IAIZ5O,IAAYmM,UAChB4C,OAAOtlB,EACP/F,EAAO,CAAEya,IAGV8P,EAASqB,WAAYP,EAAMrrB,GAE7B,CACD,EAMGmrB,EACJM,KAKK3Y,OAAOqX,SAAS0B,eACpBJ,EAAQE,WAAa7Y,OAAOqX,SAAS0B,gBAEtC/mB,EAAOgnB,WAAYL,GAErB,CACD,CAEA,OAAO3Y,OAAOqX,UAAU,SAAUO,GAGjCN,EAAQ,GAAK,GAAIvC,IAChBe,QACC,EACA8B,EACA1Y,EAAYiZ,GACXA,EACA1C,SACDmC,EAASa,aAKXnB,EAAQ,GAAK,GAAIvC,IAChBe,QACC,EACA8B,EACA1Y,EAAY+Y,GACXA,EACAxC,WAKH6B,EAAQ,GAAK,GAAIvC,IAChBe,QACC,EACA8B,EACA1Y,EAAYgZ,GACXA,EACAvC,SAGJ,IAAIO,SACL,EAIAA,QAAS,SAAUtkB,GAClB,OAAc,MAAPA,EAAcoO,OAAO8B,OAAQlQ,EAAKskB,GAAYA,CACtD,GAEDuB,EAAW,CAAC,EAkEb,OA/DAzX,OAAOc,KAAMwW,GAAQ,SAAUvrB,EAAG8rB,GACjC,IAAItS,EAAOsS,EAAO,GACjBoB,EAAcpB,EAAO,GAKtB3B,EAAS2B,EAAO,IAAQtS,EAAKwP,IAGxBkE,GACJ1T,EAAKwP,KACJ,WAICwC,EAAQ0B,CACT,GAIA3B,EAAQ,EAAIvrB,GAAK,GAAImrB,QAIrBI,EAAQ,EAAIvrB,GAAK,GAAImrB,QAGrBI,EAAQ,GAAK,GAAIH,KAGjBG,EAAQ,GAAK,GAAIH,MAOnB5R,EAAKwP,IAAK8C,EAAO,GAAIf,MAKrBW,EAAUI,EAAO,IAAQ,WAExB,OADAJ,EAAUI,EAAO,GAAM,QAAUrZ,OAASiZ,OAAWxkB,EAAYuL,KAAMpP,WAChEoP,IACR,EAKAiZ,EAAUI,EAAO,GAAM,QAAWtS,EAAK6R,QACxC,IAGAlB,EAAQA,QAASuB,GAGZxoB,GACJA,EAAKyL,KAAM+c,EAAUA,GAIfA,CACR,EAGAyB,KAAM,SAAUC,GACf,IAGCC,EAAYhqB,UAAUnD,OAGtBF,EAAIqtB,EAGJC,EAAkBxtB,MAAOE,GACzButB,EAAgB3a,EAAMjE,KAAMtL,WAG5BmqB,EAAUvZ,OAAOqX,WAGjBmC,WAAa,SAAUztB,GACtB,OAAO,SAAUuE,GAChB+oB,EAAiBttB,GAAMyS,KACvB8a,EAAevtB,GAAMqD,UAAUnD,OAAS,EAAI0S,EAAMjE,KAAMtL,WAAckB,IAC5D8oB,GACTG,EAAQb,YAAaW,EAAiBC,EAExC,CACD,EAGD,GAAKF,GAAa,IACjBvD,WAAYsD,EAAaI,EAAQ1U,KAAM2U,WAAYztB,IAAM+pB,QAASyD,EAAQxD,QACxEqD,GAGuB,YAApBG,EAAQhC,SACZrY,EAAYoa,EAAevtB,IAAOutB,EAAevtB,GAAIqqB,OAErD,OAAOmD,EAAQnD,OAKjB,KAAQrqB,KACP8pB,WAAYyD,EAAevtB,GAAKytB,WAAYztB,GAAKwtB,EAAQxD,QAG1D,OAAOwD,EAAQrD,SAChB,IAMD,IAAIuD,EAAc,yDAElBzZ,OAAOqX,SAASuB,cAAgB,SAAUnW,EAAOiX,GAI3C1nB,EAAOc,SAAWd,EAAOc,QAAQC,MAAQ0P,GAASgX,EAAY5qB,KAAM4T,EAAMhJ,OAC9EzH,EAAOc,QAAQC,KAAM,8BAAgC0P,EAAMkX,QAASlX,EAAMiX,MAAOA,EAEnF,EAKA1Z,OAAO4Z,eAAiB,SAAUnX,GACjCzQ,EAAOgnB,YAAY,WAClB,MAAMvW,CACP,GACD,EAMA,IAAIoX,EAAY7Z,OAAOqX,WAkDvB,SAASyC,YACR3nB,EAAS4nB,oBAAqB,mBAAoBD,WAClD9nB,EAAO+nB,oBAAqB,OAAQD,WACpC9Z,OAAOmU,OACR,CApDAnU,OAAOG,GAAGgU,MAAQ,SAAUhU,GAY3B,OAVA0Z,EACEzD,KAAMjW,GAKN6Z,OAAO,SAAUvX,GACjBzC,OAAO4Z,eAAgBnX,EACxB,IAEMjE,IACR,EAEAwB,OAAO8B,OAAQ,CAGdU,SAAS,EAITyX,UAAW,EAGX9F,MAAO,SAAU+F,KAGF,IAATA,IAAkBla,OAAOia,UAAYja,OAAOwC,WAKjDxC,OAAOwC,SAAU,GAGH,IAAT0X,KAAmBla,OAAOia,UAAY,GAK3CJ,EAAUnB,YAAavmB,EAAU,CAAE6N,SACpC,IAGDA,OAAOmU,MAAMiC,KAAOyD,EAAUzD,KAaD,aAAxBjkB,EAASgoB,YACa,YAAxBhoB,EAASgoB,aAA6BhoB,EAASiI,gBAAgBggB,SAGjEpoB,EAAOgnB,WAAYhZ,OAAOmU,QAK1BhiB,EAASwY,iBAAkB,mBAAoBmP,WAG/C9nB,EAAO2Y,iBAAkB,OAAQmP,YAQlC,IAAIO,OAAS,SAAU3Z,EAAOP,EAAI6I,EAAK1Y,EAAOgqB,EAAWC,EAAUC,GAClE,IAAIzuB,EAAI,EACP0V,EAAMf,EAAMzU,OACZwuB,EAAc,MAAPzR,EAGR,GAAuB,WAAlBjJ,OAAQiJ,GAEZ,IAAMjd,KADNuuB,GAAY,EACDtR,EACVqR,OAAQ3Z,EAAOP,EAAIpU,EAAGid,EAAKjd,IAAK,EAAMwuB,EAAUC,QAI3C,QAAevnB,IAAV3C,IACXgqB,GAAY,EAENpb,EAAY5O,KACjBkqB,GAAM,GAGFC,IAGCD,GACJra,EAAGzF,KAAMgG,EAAOpQ,GAChB6P,EAAK,OAILsa,EAAOta,EACPA,EAAK,SAAUc,EAAM5R,EAAMiB,GAC1B,OAAOmqB,EAAK/f,KAAMsF,OAAQiB,GAAQ3Q,EACnC,IAIG6P,GACJ,KAAQpU,EAAI0V,EAAK1V,IAChBoU,EACCO,EAAO3U,GAAKid,EAAKwR,EAChBlqB,EACAA,EAAMoK,KAAMgG,EAAO3U,GAAKA,EAAGoU,EAAIO,EAAO3U,GAAKid,KAMhD,OAAKsR,EACG5Z,EAIH+Z,EACGta,EAAGzF,KAAMgG,GAGVe,EAAMtB,EAAIO,EAAO,GAAKsI,GAAQuR,CACtC,EAIIG,EAAY,QACfC,EAAa,YAGd,SAASC,WAAYC,EAAMC,GAC1B,OAAOA,EAAOC,aACf,CAKA,SAASC,UAAWC,GACnB,OAAOA,EAAO3sB,QAASosB,EAAW,OAAQpsB,QAASqsB,EAAYC,WAChE,CACA,IAAIM,WAAa,SAAUC,GAQ1B,OAA0B,IAAnBA,EAAM7nB,UAAqC,IAAnB6nB,EAAM7nB,YAAsB6nB,EAAM7nB,QAClE,EAKA,SAAS8nB,OACR5c,KAAK6D,QAAUrC,OAAOqC,QAAU+Y,KAAKC,KACtC,CAEAD,KAAKC,IAAM,EAEXD,KAAK9tB,UAAY,CAEhByb,MAAO,SAAUoS,GAGhB,IAAI7qB,EAAQ6qB,EAAO3c,KAAK6D,SA4BxB,OAzBM/R,IACLA,EAAQ,CAAC,EAKJ4qB,WAAYC,KAIXA,EAAM7nB,SACV6nB,EAAO3c,KAAK6D,SAAY/R,EAMxBlE,OAAOkvB,eAAgBH,EAAO3c,KAAK6D,QAAS,CAC3C/R,MAAOA,EACPirB,cAAc,MAMXjrB,CACR,EACAb,IAAK,SAAU0rB,EAAOzf,EAAMpL,GAC3B,IAAIH,EACH4Y,EAAQvK,KAAKuK,MAAOoS,GAIrB,GAAqB,iBAATzf,EACXqN,EAAOiS,UAAWtf,IAAWpL,OAM7B,IAAMH,KAAQuL,EACbqN,EAAOiS,UAAW7qB,IAAWuL,EAAMvL,GAGrC,OAAO4Y,CACR,EACA1Y,IAAK,SAAU8qB,EAAOnS,GACrB,YAAe/V,IAAR+V,EACNxK,KAAKuK,MAAOoS,GAGZA,EAAO3c,KAAK6D,UAAa8Y,EAAO3c,KAAK6D,SAAW2Y,UAAWhS,GAC7D,EACAqR,OAAQ,SAAUc,EAAOnS,EAAK1Y,GAa7B,YAAa2C,IAAR+V,GACCA,GAAsB,iBAARA,QAAgC/V,IAAV3C,EAElCkO,KAAKnO,IAAK8qB,EAAOnS,IASzBxK,KAAK/O,IAAK0rB,EAAOnS,EAAK1Y,QAIL2C,IAAV3C,EAAsBA,EAAQ0Y,EACtC,EACAzP,OAAQ,SAAU4hB,EAAOnS,GACxB,IAAIjd,EACHgd,EAAQoS,EAAO3c,KAAK6D,SAErB,QAAepP,IAAV8V,EAAL,CAIA,QAAa9V,IAAR+V,EAAoB,CAkBxBjd,GAXCid,EAJInd,MAAMC,QAASkd,GAIbA,EAAIhI,IAAKga,YAEfhS,EAAMgS,UAAWhS,MAIJD,EACZ,CAAEC,GACAA,EAAI5a,MAAOonB,IAAmB,IAG1BvpB,OAER,KAAQF,YACAgd,EAAOC,EAAKjd,GAErB,OAGakH,IAAR+V,GAAqBhJ,OAAO8C,cAAeiG,MAM1CoS,EAAM7nB,SACV6nB,EAAO3c,KAAK6D,cAAYpP,SAEjBkoB,EAAO3c,KAAK6D,SArCrB,CAwCD,EACAmZ,QAAS,SAAUL,GAClB,IAAIpS,EAAQoS,EAAO3c,KAAK6D,SACxB,YAAiBpP,IAAV8V,IAAwB/I,OAAO8C,cAAeiG,EACtD,GAED,IAAI0S,EAAW,IAAIL,KAEfM,EAAW,IAAIN,KAcfO,EAAS,gCACZC,EAAa,SA2Bd,SAASC,SAAU5a,EAAM+H,EAAKtN,GAC7B,IAAIjC,EAIJ,QAAcxG,IAATyI,GAAwC,IAAlBuF,EAAK3N,SAI/B,GAHAmG,EAAO,QAAUuP,EAAI1a,QAASstB,EAAY,OAAQ1tB,cAG7B,iBAFrBwN,EAAOuF,EAAKxO,aAAcgH,IAEM,CAC/B,IACCiC,EApCJ,SAASogB,QAASpgB,GACjB,MAAc,SAATA,GAIS,UAATA,IAIS,SAATA,EACG,KAIHA,KAAUA,EAAO,IACbA,EAGJigB,EAAO9sB,KAAM6M,GACVqgB,KAAKC,MAAOtgB,GAGbA,EACR,CAaWogB,CAASpgB,EACjB,CAAE,MAAQiM,GAAK,CAGf+T,EAASjsB,IAAKwR,EAAM+H,EAAKtN,EAC1B,MACCA,OAAOzI,EAGT,OAAOyI,CACR,CAEAsE,OAAO8B,OAAQ,CACd0Z,QAAS,SAAUva,GAClB,OAAOya,EAASF,QAASva,IAAUwa,EAASD,QAASva,EACtD,EAEAvF,KAAM,SAAUuF,EAAMxH,EAAMiC,GAC3B,OAAOggB,EAASrB,OAAQpZ,EAAMxH,EAAMiC,EACrC,EAEAugB,WAAY,SAAUhb,EAAMxH,GAC3BiiB,EAASniB,OAAQ0H,EAAMxH,EACxB,EAIAyiB,MAAO,SAAUjb,EAAMxH,EAAMiC,GAC5B,OAAO+f,EAASpB,OAAQpZ,EAAMxH,EAAMiC,EACrC,EAEAygB,YAAa,SAAUlb,EAAMxH,GAC5BgiB,EAASliB,OAAQ0H,EAAMxH,EACxB,IAGDuG,OAAOG,GAAG2B,OAAQ,CACjBpG,KAAM,SAAUsN,EAAK1Y,GACpB,IAAIvE,EAAG0N,EAAMiC,EACZuF,EAAOzC,KAAM,GACb+K,EAAQtI,GAAQA,EAAK7F,WAGtB,QAAanI,IAAR+V,EAAoB,CACxB,GAAKxK,KAAKvS,SACTyP,EAAOggB,EAASrrB,IAAK4Q,GAEE,IAAlBA,EAAK3N,WAAmBmoB,EAASprB,IAAK4Q,EAAM,iBAAmB,CAEnE,IADAlV,EAAIwd,EAAMtd,OACFF,KAIFwd,EAAOxd,IAEsB,KADjC0N,EAAO8P,EAAOxd,GAAI0N,MACRjL,QAAS,WAClBiL,EAAOuhB,UAAWvhB,EAAKkF,MAAO,IAC9Bkd,SAAU5a,EAAMxH,EAAMiC,EAAMjC,KAI/BgiB,EAAShsB,IAAKwR,EAAM,gBAAgB,EACrC,CAGD,OAAOvF,CACR,CAGA,MAAoB,iBAARsN,EACJxK,KAAKsC,MAAM,WACjB4a,EAASjsB,IAAK+O,KAAMwK,EACrB,IAGMqR,OAAQ7b,MAAM,SAAUlO,GAC9B,IAAIoL,EAOJ,GAAKuF,QAAkBhO,IAAV3C,EAKZ,YAAc2C,KADdyI,EAAOggB,EAASrrB,IAAK4Q,EAAM+H,UAQb/V,KADdyI,EAAOmgB,SAAU5a,EAAM+H,IALftN,OAWR,EAID8C,KAAKsC,MAAM,WAGV4a,EAASjsB,IAAK+O,KAAMwK,EAAK1Y,EAC1B,GACD,GAAG,KAAMA,EAAOlB,UAAUnD,OAAS,EAAG,MAAM,EAC7C,EAEAgwB,WAAY,SAAUjT,GACrB,OAAOxK,KAAKsC,MAAM,WACjB4a,EAASniB,OAAQiF,KAAMwK,EACxB,GACD,IAIDhJ,OAAO8B,OAAQ,CACd8U,MAAO,SAAU3V,EAAM3B,EAAM5D,GAC5B,IAAIkb,EAEJ,GAAK3V,EAYJ,OAXA3B,GAASA,GAAQ,MAAS,QAC1BsX,EAAQ6E,EAASprB,IAAK4Q,EAAM3B,GAGvB5D,KACEkb,GAAS/qB,MAAMC,QAAS4P,GAC7Bkb,EAAQ6E,EAASpB,OAAQpZ,EAAM3B,EAAMU,OAAOgD,UAAWtH,IAEvDkb,EAAM7oB,KAAM2N,IAGPkb,GAAS,EAElB,EAEAwF,QAAS,SAAUnb,EAAM3B,GACxBA,EAAOA,GAAQ,KAEf,IAAIsX,EAAQ5W,OAAO4W,MAAO3V,EAAM3B,GAC/B+c,EAAczF,EAAM3qB,OACpBkU,EAAKyW,EAAM1N,QACX3T,EAAQyK,OAAOsc,YAAarb,EAAM3B,GAMvB,eAAPa,IACJA,EAAKyW,EAAM1N,QACXmT,KAGIlc,IAIU,OAATb,GACJsX,EAAMxK,QAAS,qBAIT7W,EAAMgnB,KACbpc,EAAGzF,KAAMuG,GApBF,WACNjB,OAAOoc,QAASnb,EAAM3B,EACvB,GAkBqB/J,KAGhB8mB,GAAe9mB,GACpBA,EAAM0hB,MAAMH,MAEd,EAGAwF,YAAa,SAAUrb,EAAM3B,GAC5B,IAAI0J,EAAM1J,EAAO,aACjB,OAAOmc,EAASprB,IAAK4Q,EAAM+H,IAASyS,EAASpB,OAAQpZ,EAAM+H,EAAK,CAC/DiO,MAAOjX,OAAOqW,UAAW,eAAgBtB,KAAK,WAC7C0G,EAASliB,OAAQ0H,EAAM,CAAE3B,EAAO,QAAS0J,GAC1C,KAEF,IAGDhJ,OAAOG,GAAG2B,OAAQ,CACjB8U,MAAO,SAAUtX,EAAM5D,GACtB,IAAI8gB,EAAS,EAQb,MANqB,iBAATld,IACX5D,EAAO4D,EACPA,EAAO,KACPkd,KAGIptB,UAAUnD,OAASuwB,EAChBxc,OAAO4W,MAAOpY,KAAM,GAAKc,QAGjBrM,IAATyI,EACN8C,KACAA,KAAKsC,MAAM,WACV,IAAI8V,EAAQ5W,OAAO4W,MAAOpY,KAAMc,EAAM5D,GAGtCsE,OAAOsc,YAAa9d,KAAMc,GAEZ,OAATA,GAAgC,eAAfsX,EAAO,IAC5B5W,OAAOoc,QAAS5d,KAAMc,EAExB,GACF,EACA8c,QAAS,SAAU9c,GAClB,OAAOd,KAAKsC,MAAM,WACjBd,OAAOoc,QAAS5d,KAAMc,EACvB,GACD,EACAmd,WAAY,SAAUnd,GACrB,OAAOd,KAAKoY,MAAOtX,GAAQ,KAAM,GAClC,EAIA4W,QAAS,SAAU5W,EAAM1N,GACxB,IAAIwZ,EACHsR,EAAQ,EACRC,EAAQ3c,OAAOqX,WACf/K,EAAW9N,KACXzS,EAAIyS,KAAKvS,OACT6pB,QAAU,aACC4G,GACTC,EAAMjE,YAAapM,EAAU,CAAEA,GAEjC,EAQD,IANqB,iBAAThN,IACX1N,EAAM0N,EACNA,OAAOrM,GAERqM,EAAOA,GAAQ,KAEPvT,MACPqf,EAAMqQ,EAASprB,IAAKic,EAAUvgB,GAAKuT,EAAO,gBAC9B8L,EAAI6L,QACfyF,IACAtR,EAAI6L,MAAMlC,IAAKe,UAIjB,OADAA,UACO6G,EAAMzG,QAAStkB,EACvB,IAED,IAAIgrB,EAAO,sCAA0CC,OAEjDC,EAAU,IAAIluB,OAAQ,iBAAmBguB,EAAO,cAAe,KAG/DG,EAAY,CAAE,MAAO,QAAS,SAAU,QAExC3iB,EAAkBjI,EAASiI,gBAI1B4iB,WAAa,SAAU/b,GACzB,OAAOjB,OAAOyE,SAAUxD,EAAKrM,cAAeqM,EAC7C,EACAgc,EAAW,CAAEA,UAAU,GAOnB7iB,EAAgB8iB,cACpBF,WAAa,SAAU/b,GACtB,OAAOjB,OAAOyE,SAAUxD,EAAKrM,cAAeqM,IAC3CA,EAAKic,YAAaD,KAAehc,EAAKrM,aACxC,GAEF,IAAIuoB,mBAAqB,SAAUlc,EAAMoI,GAOvC,MAA8B,UAH9BpI,EAAOoI,GAAMpI,GAGDmc,MAAMC,SACM,KAAvBpc,EAAKmc,MAAMC,SAMXL,WAAY/b,IAEsB,SAAlCjB,OAAOsd,IAAKrc,EAAM,UACpB,EAID,SAASsc,UAAWtc,EAAM9Q,EAAMqtB,EAAYC,GAC3C,IAAIC,EAAUC,EACbC,EAAgB,GAChBC,EAAeJ,EACd,WACC,OAAOA,EAAM9T,KACd,EACA,WACC,OAAO3J,OAAOsd,IAAKrc,EAAM9Q,EAAM,GAChC,EACD2tB,EAAUD,IACVE,EAAOP,GAAcA,EAAY,KAASxd,OAAOge,UAAW7tB,GAAS,GAAK,MAG1E8tB,EAAgBhd,EAAK3N,WAClB0M,OAAOge,UAAW7tB,IAAmB,OAAT4tB,IAAkBD,IAChDhB,EAAQ3U,KAAMnI,OAAOsd,IAAKrc,EAAM9Q,IAElC,GAAK8tB,GAAiBA,EAAe,KAAQF,EAAO,CAYnD,IARAD,GAAoB,EAGpBC,EAAOA,GAAQE,EAAe,GAG9BA,GAAiBH,GAAW,EAEpBF,KAIP5d,OAAOod,MAAOnc,EAAM9Q,EAAM8tB,EAAgBF,IACnC,EAAIJ,IAAY,GAAMA,EAAQE,IAAiBC,GAAW,MAAW,IAC3EF,EAAgB,GAEjBK,GAAgCN,EAIjCM,GAAgC,EAChCje,OAAOod,MAAOnc,EAAM9Q,EAAM8tB,EAAgBF,GAG1CP,EAAaA,GAAc,EAC5B,CAeA,OAbKA,IACJS,GAAiBA,IAAkBH,GAAW,EAG9CJ,EAAWF,EAAY,GACtBS,GAAkBT,EAAY,GAAM,GAAMA,EAAY,IACrDA,EAAY,GACTC,IACJA,EAAMM,KAAOA,EACbN,EAAMvP,MAAQ+P,EACdR,EAAM9b,IAAM+b,IAGPA,CACR,CAGA,IAAIQ,EAAoB,CAAC,EAEzB,SAASC,kBAAmBld,GAC3B,IAAI+P,EACHjX,EAAMkH,EAAKrM,cACXsG,EAAW+F,EAAK/F,SAChBmiB,EAAUa,EAAmBhjB,GAE9B,OAAKmiB,IAILrM,EAAOjX,EAAIM,KAAKkD,YAAaxD,EAAIrF,cAAewG,IAChDmiB,EAAUrd,OAAOsd,IAAKtM,EAAM,WAE5BA,EAAK5X,WAAWC,YAAa2X,GAEZ,SAAZqM,IACJA,EAAU,SAEXa,EAAmBhjB,GAAamiB,EAEzBA,EACR,CAEA,SAASe,SAAU9R,EAAU+R,GAO5B,IANA,IAAIhB,EAASpc,EACZqd,EAAS,GACTzJ,EAAQ,EACR5oB,EAASqgB,EAASrgB,OAGX4oB,EAAQ5oB,EAAQ4oB,KACvB5T,EAAOqL,EAAUuI,IACNuI,QAIXC,EAAUpc,EAAKmc,MAAMC,QAChBgB,GAKa,SAAZhB,IACJiB,EAAQzJ,GAAU4G,EAASprB,IAAK4Q,EAAM,YAAe,KAC/Cqd,EAAQzJ,KACb5T,EAAKmc,MAAMC,QAAU,KAGK,KAAvBpc,EAAKmc,MAAMC,SAAkBF,mBAAoBlc,KACrDqd,EAAQzJ,GAAUsJ,kBAAmBld,KAGrB,SAAZoc,IACJiB,EAAQzJ,GAAU,OAGlB4G,EAAShsB,IAAKwR,EAAM,UAAWoc,KAMlC,IAAMxI,EAAQ,EAAGA,EAAQ5oB,EAAQ4oB,IACR,MAAnByJ,EAAQzJ,KACZvI,EAAUuI,GAAQuI,MAAMC,QAAUiB,EAAQzJ,IAI5C,OAAOvI,CACR,CAEAtM,OAAOG,GAAG2B,OAAQ,CACjBuc,KAAM,WACL,OAAOD,SAAU5f,MAAM,EACxB,EACA+f,KAAM,WACL,OAAOH,SAAU5f,KAClB,EACAggB,OAAQ,SAAUjH,GACjB,MAAsB,kBAAVA,EACJA,EAAQ/Y,KAAK6f,OAAS7f,KAAK+f,OAG5B/f,KAAKsC,MAAM,WACZqc,mBAAoB3e,MACxBwB,OAAQxB,MAAO6f,OAEfre,OAAQxB,MAAO+f,MAEjB,GACD,IAED,IAUEE,EACApT,EAXEqT,EAAiB,wBAEjBC,EAAW,iCAEXC,EAAc,qCAMhBH,EADctsB,EAASiD,yBACRmI,YAAapL,EAASuC,cAAe,SACpD2W,EAAQlZ,EAASuC,cAAe,UAM3B2G,aAAc,OAAQ,SAC5BgQ,EAAMhQ,aAAc,UAAW,WAC/BgQ,EAAMhQ,aAAc,OAAQ,KAE5BojB,EAAIlhB,YAAa8N,GAIjBpM,EAAQ4f,WAAaJ,EAAIpqB,WAAW,GAAOA,WAAW,GAAO+Z,UAAUgB,QAIvEqP,EAAI3iB,UAAY,yBAChBmD,EAAQ6f,iBAAmBL,EAAIpqB,WAAW,GAAO+Z,UAAU6E,aAK3DwL,EAAI3iB,UAAY,oBAChBmD,EAAQ8f,SAAWN,EAAIrQ,UAKxB,IAAI4Q,EAAU,CAKbC,MAAO,CAAE,EAAG,UAAW,YACvBC,IAAK,CAAE,EAAG,oBAAqB,uBAC/BC,GAAI,CAAE,EAAG,iBAAkB,oBAC3BC,GAAI,CAAE,EAAG,qBAAsB,yBAE/BC,SAAU,CAAE,EAAG,GAAI,KAYpB,SAASC,OAAQpf,EAASpC,GAIzB,IAAI6C,EAYJ,OATCA,OAD4C,IAAjCT,EAAQ/K,qBACb+K,EAAQ/K,qBAAsB2I,GAAO,UAEI,IAA7BoC,EAAQ0I,iBACpB1I,EAAQ0I,iBAAkB9K,GAAO,KAGjC,QAGM7K,IAAR6K,GAAqBA,GAAO5C,SAAUgF,EAASpC,GAC5CkC,OAAOY,MAAO,CAAEV,GAAWS,GAG5BA,CACR,CAIA,SAAS4e,cAAe7e,EAAO8e,GAI9B,IAHA,IAAIzzB,EAAI,EACP4D,EAAI+Q,EAAMzU,OAEHF,EAAI4D,EAAG5D,IACd0vB,EAAShsB,IACRiR,EAAO3U,GACP,cACCyzB,GAAe/D,EAASprB,IAAKmvB,EAAazzB,GAAK,cAGnD,CA7CAizB,EAAQ7mB,MAAQ6mB,EAAQS,MAAQT,EAAQU,SAAWV,EAAQW,QAAUX,EAAQC,MAC7ED,EAAQY,GAAKZ,EAAQI,GAGfngB,EAAQ8f,SACbC,EAAQa,SAAWb,EAAQD,OAAS,CAAE,EAAG,+BAAgC,cA2C1E,IAAI3Y,EAAQ,YAEZ,SAAS0Z,cAAepf,EAAOR,EAAS6f,EAASC,EAAWC,GAO3D,IANA,IAAIhf,EAAMmK,EAAKtN,EAAKoiB,EAAMC,EAAUze,EACnC7E,EAAWqD,EAAQ9K,yBACnBgrB,EAAQ,GACRr0B,EAAI,EACJ4D,EAAI+Q,EAAMzU,OAEHF,EAAI4D,EAAG5D,IAGd,IAFAkV,EAAOP,EAAO3U,KAEQ,IAATkV,EAGZ,GAAwB,WAAnBlB,OAAQkB,GAIZjB,OAAOY,MAAOwf,EAAOnf,EAAK3N,SAAW,CAAE2N,GAASA,QAG1C,GAAMmF,EAAMvX,KAAMoS,GAIlB,CAUN,IATAmK,EAAMA,GAAOvO,EAASU,YAAa2C,EAAQxL,cAAe,QAG1DoJ,GAAQ6gB,EAASxW,KAAMlH,IAAU,CAAE,GAAI,KAAQ,GAAI/S,cACnDgyB,EAAOlB,EAASlhB,IAASkhB,EAAQK,SACjCjU,EAAItP,UAAYokB,EAAM,GAAMlgB,OAAOqgB,cAAepf,GAASif,EAAM,GAGjExe,EAAIwe,EAAM,GACFxe,KACP0J,EAAMA,EAAIgD,UAKXpO,OAAOY,MAAOwf,EAAOhV,EAAI3Q,aAGzB2Q,EAAMvO,EAASW,YAGXrC,YAAc,EACnB,MA1BCilB,EAAMryB,KAAMmS,EAAQ1F,eAAgByG,IAkCvC,IAHApE,EAAS1B,YAAc,GAEvBpP,EAAI,EACMkV,EAAOmf,EAAOr0B,MAGvB,GAAKi0B,GAAahgB,OAAOkD,QAASjC,EAAM+e,IAAe,EACjDC,GACJA,EAAQlyB,KAAMkT,QAgBhB,GAXAkf,EAAWnD,WAAY/b,GAGvBmK,EAAMkU,OAAQziB,EAASU,YAAa0D,GAAQ,UAGvCkf,GACJZ,cAAenU,GAIX2U,EAEJ,IADAre,EAAI,EACMT,EAAOmK,EAAK1J,MAChBkd,EAAY/vB,KAAMoS,EAAK3B,MAAQ,KACnCygB,EAAQhyB,KAAMkT,GAMlB,OAAOpE,CACR,CAGA,IAAIyjB,EAAiB,sBAErB,SAASC,aACR,OAAO,CACR,CAEA,SAASC,cACR,OAAO,CACR,CAQA,SAASC,WAAYxf,EAAM3B,GAC1B,OAAS2B,IAMV,SAASyf,oBACR,IACC,OAAOvuB,EAAS6c,aACjB,CAAE,MAAQ2R,GAAQ,CACnB,CAVmBD,KAAqC,UAATphB,EAC/C,CAWA,SAASshB,GAAI3f,EAAM4f,EAAO5gB,EAAUvE,EAAMyE,EAAI2gB,GAC7C,IAAIC,EAAQzhB,EAGZ,GAAsB,iBAAVuhB,EAAqB,CAShC,IAAMvhB,IANmB,iBAAbW,IAGXvE,EAAOA,GAAQuE,EACfA,OAAWhN,GAEE4tB,EACbD,GAAI3f,EAAM3B,EAAMW,EAAUvE,EAAMmlB,EAAOvhB,GAAQwhB,GAEhD,OAAO7f,CACR,CAqBA,GAnBa,MAARvF,GAAsB,MAANyE,GAGpBA,EAAKF,EACLvE,EAAOuE,OAAWhN,GACD,MAANkN,IACc,iBAAbF,GAGXE,EAAKzE,EACLA,OAAOzI,IAIPkN,EAAKzE,EACLA,EAAOuE,EACPA,OAAWhN,KAGD,IAAPkN,EACJA,EAAKqgB,iBACC,IAAMrgB,EACZ,OAAOc,EAeR,OAZa,IAAR6f,IACJC,EAAS5gB,EACTA,EAAK,SAAU6gB,GAId,OADAhhB,SAASihB,IAAKD,GACPD,EAAOj0B,MAAO0R,KAAMpP,UAC5B,EAGA+Q,EAAGoD,KAAOwd,EAAOxd,OAAUwd,EAAOxd,KAAOvD,OAAOuD,SAE1CtC,EAAKH,MAAM,WACjBd,OAAOghB,MAAMjM,IAAKvW,KAAMqiB,EAAO1gB,EAAIzE,EAAMuE,EAC1C,GACD,CA6aA,SAASihB,eAAgB7X,EAAI/J,EAAMmhB,GAG5BA,GAQNhF,EAAShsB,IAAK4Z,EAAI/J,GAAM,GACxBU,OAAOghB,MAAMjM,IAAK1L,EAAI/J,EAAM,CAC3BgL,WAAW,EACXd,QAAS,SAAUwX,GAClB,IAAIG,EAAU3T,EACb4T,EAAQ3F,EAASprB,IAAKmO,KAAMc,GAE7B,GAAyB,EAAlB0hB,EAAMK,WAAmB7iB,KAAMc,IAKrC,GAAM8hB,EAAMn1B,QAuCE+T,OAAOghB,MAAM1I,QAAShZ,IAAU,CAAC,GAAIgiB,cAClDN,EAAMO,uBArBN,GAdAH,EAAQziB,EAAMjE,KAAMtL,WACpBqsB,EAAShsB,IAAK+O,KAAMc,EAAM8hB,GAK1BD,EAAWV,EAAYjiB,KAAMc,GAC7Bd,KAAMc,KAED8hB,KADL5T,EAASiO,EAASprB,IAAKmO,KAAMc,KACJ6hB,EACxB1F,EAAShsB,IAAK+O,KAAMc,GAAM,GAE1BkO,EAAS,CAAC,EAEN4T,IAAU5T,EAWd,OARAwT,EAAMQ,2BACNR,EAAMS,iBAOCjU,GAAUA,EAAOld,WAef8wB,EAAMn1B,SAGjBwvB,EAAShsB,IAAK+O,KAAMc,EAAM,CACzBhP,MAAO0P,OAAOghB,MAAMU,QAInB1hB,OAAO8B,OAAQsf,EAAO,GAAKphB,OAAO2hB,MAAMr0B,WACxC8zB,EAAMziB,MAAO,GACbH,QAKFwiB,EAAMQ,2BAER,UAjFkCvuB,IAA7BwoB,EAASprB,IAAKgZ,EAAI/J,IACtBU,OAAOghB,MAAMjM,IAAK1L,EAAI/J,EAAMihB,WAkF/B,CA9fAvgB,OAAOghB,MAAQ,CAEd3iB,OAAQ,CAAC,EAET0W,IAAK,SAAU9T,EAAM4f,EAAOrX,EAAS9N,EAAMuE,GAE1C,IAAI2hB,EAAaC,EAAazW,EAC7B0W,EAAQC,EAAGC,EACX1J,EAAS2J,EAAU3iB,EAAM4iB,EAAYC,EACrCC,EAAW3G,EAASprB,IAAK4Q,GAG1B,GAAMia,WAAYja,GAuClB,IAlCKuI,EAAQA,UAEZA,GADAoY,EAAcpY,GACQA,QACtBvJ,EAAW2hB,EAAY3hB,UAKnBA,GACJD,OAAOmL,KAAKG,gBAAiBlR,EAAiB6F,GAIzCuJ,EAAQjG,OACbiG,EAAQjG,KAAOvD,OAAOuD,SAIfue,EAASM,EAASN,UACzBA,EAASM,EAASN,OAAS11B,OAAOO,OAAQ,QAEnCk1B,EAAcO,EAASC,UAC9BR,EAAcO,EAASC,OAAS,SAAU1a,GAIzC,YAAyB,IAAX3H,QAA0BA,OAAOghB,MAAMsB,YAAc3a,EAAErI,KACpEU,OAAOghB,MAAMuB,SAASz1B,MAAOmU,EAAM7R,gBAAc6D,CACnD,GAKD8uB,GADAlB,GAAUA,GAAS,IAAKzyB,MAAOonB,IAAmB,CAAE,KAC1CvpB,OACF81B,KAEPziB,EAAO6iB,GADP/W,EAAMkV,EAAenY,KAAM0Y,EAAOkB,KAAS,IACpB,GACvBG,GAAe9W,EAAK,IAAO,IAAK5H,MAAO,KAAM5B,OAGvCtC,IAKNgZ,EAAUtY,OAAOghB,MAAM1I,QAAShZ,IAAU,CAAC,EAG3CA,GAASW,EAAWqY,EAAQgJ,aAAehJ,EAAQkK,WAAcljB,EAGjEgZ,EAAUtY,OAAOghB,MAAM1I,QAAShZ,IAAU,CAAC,EAG3C0iB,EAAYhiB,OAAO8B,OAAQ,CAC1BxC,KAAMA,EACN6iB,SAAUA,EACVzmB,KAAMA,EACN8N,QAASA,EACTjG,KAAMiG,EAAQjG,KACdtD,SAAUA,EACV0T,aAAc1T,GAAYD,OAAOqM,KAAKje,MAAMulB,aAAa9kB,KAAMoR,GAC/DqK,UAAW4X,EAAWvZ,KAAM,MAC1BiZ,IAGKK,EAAWH,EAAQxiB,OAC1B2iB,EAAWH,EAAQxiB,GAAS,IACnBmjB,cAAgB,EAGnBnK,EAAQoK,QACiD,IAA9DpK,EAAQoK,MAAMhoB,KAAMuG,EAAMvF,EAAMwmB,EAAYL,IAEvC5gB,EAAK0J,kBACT1J,EAAK0J,iBAAkBrL,EAAMuiB,IAK3BvJ,EAAQvD,MACZuD,EAAQvD,IAAIra,KAAMuG,EAAM+gB,GAElBA,EAAUxY,QAAQjG,OACvBye,EAAUxY,QAAQjG,KAAOiG,EAAQjG,OAK9BtD,EACJgiB,EAASpgB,OAAQogB,EAASQ,gBAAiB,EAAGT,GAE9CC,EAASl0B,KAAMi0B,GAIhBhiB,OAAOghB,MAAM3iB,OAAQiB,IAAS,EAGhC,EAGA/F,OAAQ,SAAU0H,EAAM4f,EAAOrX,EAASvJ,EAAU0iB,GAEjD,IAAIjhB,EAAGkhB,EAAWxX,EACjB0W,EAAQC,EAAGC,EACX1J,EAAS2J,EAAU3iB,EAAM4iB,EAAYC,EACrCC,EAAW3G,EAASD,QAASva,IAAUwa,EAASprB,IAAK4Q,GAEtD,GAAMmhB,IAAeN,EAASM,EAASN,QAAvC,CAOA,IADAC,GADAlB,GAAUA,GAAS,IAAKzyB,MAAOonB,IAAmB,CAAE,KAC1CvpB,OACF81B,KAMP,GAJAziB,EAAO6iB,GADP/W,EAAMkV,EAAenY,KAAM0Y,EAAOkB,KAAS,IACpB,GACvBG,GAAe9W,EAAK,IAAO,IAAK5H,MAAO,KAAM5B,OAGvCtC,EAAN,CAeA,IARAgZ,EAAUtY,OAAOghB,MAAM1I,QAAShZ,IAAU,CAAC,EAE3C2iB,EAAWH,EADXxiB,GAASW,EAAWqY,EAAQgJ,aAAehJ,EAAQkK,WAAcljB,IACpC,GAC7B8L,EAAMA,EAAK,IACV,IAAIxc,OAAQ,UAAYszB,EAAWvZ,KAAM,iBAAoB,WAG9Dia,EAAYlhB,EAAIugB,EAASh2B,OACjByV,KACPsgB,EAAYC,EAAUvgB,IAEfihB,GAAeR,IAAaH,EAAUG,UACzC3Y,GAAWA,EAAQjG,OAASye,EAAUze,MACtC6H,IAAOA,EAAIvc,KAAMmzB,EAAU1X,YAC3BrK,GAAYA,IAAa+hB,EAAU/hB,WACxB,OAAbA,IAAqB+hB,EAAU/hB,YAChCgiB,EAASpgB,OAAQH,EAAG,GAEfsgB,EAAU/hB,UACdgiB,EAASQ,gBAELnK,EAAQ/e,QACZ+e,EAAQ/e,OAAOmB,KAAMuG,EAAM+gB,IAOzBY,IAAcX,EAASh2B,SACrBqsB,EAAQuK,WACkD,IAA/DvK,EAAQuK,SAASnoB,KAAMuG,EAAMihB,EAAYE,EAASC,SAElDriB,OAAO8iB,YAAa7hB,EAAM3B,EAAM8iB,EAASC,eAGnCP,EAAQxiB,GAtChB,MAJC,IAAMA,KAAQwiB,EACb9hB,OAAOghB,MAAMznB,OAAQ0H,EAAM3B,EAAOuhB,EAAOkB,GAAKvY,EAASvJ,GAAU,GA8C/DD,OAAO8C,cAAegf,IAC1BrG,EAASliB,OAAQ0H,EAAM,gBA5DxB,CA8DD,EAEAshB,SAAU,SAAUQ,GAEnB,IAAIh3B,EAAG2V,EAAGf,EAAK8N,EAASuT,EAAWgB,EAClC91B,EAAO,IAAIrB,MAAOuD,UAAUnD,QAG5B+0B,EAAQhhB,OAAOghB,MAAMiC,IAAKF,GAE1Bd,GACCxG,EAASprB,IAAKmO,KAAM,WAAcpS,OAAOO,OAAQ,OAC/Cq0B,EAAM1hB,OAAU,GACnBgZ,EAAUtY,OAAOghB,MAAM1I,QAAS0I,EAAM1hB,OAAU,CAAC,EAKlD,IAFApS,EAAM,GAAM8zB,EAENj1B,EAAI,EAAGA,EAAIqD,UAAUnD,OAAQF,IAClCmB,EAAMnB,GAAMqD,UAAWrD,GAMxB,GAHAi1B,EAAMkC,eAAiB1kB,MAGlB8Z,EAAQ6K,cAA2D,IAA5C7K,EAAQ6K,YAAYzoB,KAAM8D,KAAMwiB,GAA5D,CASA,IAJAgC,EAAehjB,OAAOghB,MAAMiB,SAASvnB,KAAM8D,KAAMwiB,EAAOiB,GAGxDl2B,EAAI,GACM0iB,EAAUuU,EAAcj3B,QAAYi1B,EAAMoC,wBAInD,IAHApC,EAAMqC,cAAgB5U,EAAQxN,KAE9BS,EAAI,GACMsgB,EAAYvT,EAAQwT,SAAUvgB,QACtCsf,EAAMsC,iCAIDtC,EAAMuC,aAAsC,IAAxBvB,EAAU1X,YACnC0W,EAAMuC,WAAW10B,KAAMmzB,EAAU1X,aAEjC0W,EAAMgB,UAAYA,EAClBhB,EAAMtlB,KAAOsmB,EAAUtmB,UAKVzI,KAHb0N,IAAUX,OAAOghB,MAAM1I,QAAS0J,EAAUG,WAAc,CAAC,GAAIE,QAC5DL,EAAUxY,SAAU1c,MAAO2hB,EAAQxN,KAAM/T,MAGT,KAAzB8zB,EAAMxT,OAAS7M,KACrBqgB,EAAMS,iBACNT,EAAMO,oBAYX,OAJKjJ,EAAQkL,cACZlL,EAAQkL,aAAa9oB,KAAM8D,KAAMwiB,GAG3BA,EAAMxT,MAxCb,CAyCD,EAEAyU,SAAU,SAAUjB,EAAOiB,GAC1B,IAAIl2B,EAAGi2B,EAAWxV,EAAKiX,EAAiBC,EACvCV,EAAe,GACfP,EAAgBR,EAASQ,cACzB9Y,EAAMqX,EAAM9e,OAGb,GAAKugB,GAIJ9Y,EAAIrW,YAOc,UAAf0tB,EAAM1hB,MAAoB0hB,EAAM2C,QAAU,GAE7C,KAAQha,IAAQnL,KAAMmL,EAAMA,EAAIvQ,YAAcoF,KAI7C,GAAsB,IAAjBmL,EAAIrW,WAAoC,UAAf0tB,EAAM1hB,OAAqC,IAAjBqK,EAAInC,UAAsB,CAGjF,IAFAic,EAAkB,GAClBC,EAAmB,CAAC,EACd33B,EAAI,EAAGA,EAAI02B,EAAe12B,SAMEkH,IAA5BywB,EAFLlX,GAHAwV,EAAYC,EAAUl2B,IAGNkU,SAAW,OAG1ByjB,EAAkBlX,GAAQwV,EAAUrO,aACnC3T,OAAQwM,EAAKhO,MAAOqW,MAAOlL,IAAS,EACpC3J,OAAOmL,KAAMqB,EAAKhO,KAAM,KAAM,CAAEmL,IAAQ1d,QAErCy3B,EAAkBlX,IACtBiX,EAAgB11B,KAAMi0B,GAGnByB,EAAgBx3B,QACpB+2B,EAAaj1B,KAAM,CAAEkT,KAAM0I,EAAKsY,SAAUwB,GAE5C,CAUF,OALA9Z,EAAMnL,KACDikB,EAAgBR,EAASh2B,QAC7B+2B,EAAaj1B,KAAM,CAAEkT,KAAM0I,EAAKsY,SAAUA,EAAStjB,MAAO8jB,KAGpDO,CACR,EAEAY,QAAS,SAAUnqB,EAAMkC,GACxBvP,OAAOkvB,eAAgBtb,OAAO2hB,MAAMr0B,UAAWmM,EAAM,CACpDoqB,YAAY,EACZtI,cAAc,EAEdlrB,IAAK6O,EAAYvD,GAChB,WACC,GAAK6C,KAAKslB,cACT,OAAOnoB,EAAM6C,KAAKslB,cAEpB,EACA,WACC,GAAKtlB,KAAKslB,cACT,OAAOtlB,KAAKslB,cAAerqB,EAE7B,EAEDhK,IAAK,SAAUa,GACdlE,OAAOkvB,eAAgB9c,KAAM/E,EAAM,CAClCoqB,YAAY,EACZtI,cAAc,EACdwI,UAAU,EACVzzB,MAAOA,GAET,GAEF,EAEA2yB,IAAK,SAAUa,GACd,OAAOA,EAAe9jB,OAAOqC,SAC5ByhB,EACA,IAAI9jB,OAAO2hB,MAAOmC,EACpB,EAEAxL,QAAS,CACR0L,KAAM,CAGLC,UAAU,GAEXC,MAAO,CAGNxB,MAAO,SAAUhnB,GAIhB,IAAI2N,EAAK7K,MAAQ9C,EAWjB,OARKgjB,EAAe7vB,KAAMwa,EAAG/J,OAC5B+J,EAAG6a,OAAShpB,SAAUmO,EAAI,UAG1B6X,eAAgB7X,EAAI,QAASkX,aAIvB,CACR,EACAmB,QAAS,SAAUhmB,GAIlB,IAAI2N,EAAK7K,MAAQ9C,EAUjB,OAPKgjB,EAAe7vB,KAAMwa,EAAG/J,OAC5B+J,EAAG6a,OAAShpB,SAAUmO,EAAI,UAE1B6X,eAAgB7X,EAAI,UAId,CACR,EAIAgW,SAAU,SAAU2B,GACnB,IAAI9e,EAAS8e,EAAM9e,OACnB,OAAOwc,EAAe7vB,KAAMqT,EAAO5C,OAClC4C,EAAOgiB,OAAShpB,SAAUgH,EAAQ,UAClCuZ,EAASprB,IAAK6R,EAAQ,UACtBhH,SAAUgH,EAAQ,IACpB,GAGDiiB,aAAc,CACbX,aAAc,SAAUxC,QAID/tB,IAAjB+tB,EAAMxT,QAAwBwT,EAAM8C,gBACxC9C,EAAM8C,cAAcM,YAAcpD,EAAMxT,OAE1C,KAkGHxN,OAAO8iB,YAAc,SAAU7hB,EAAM3B,EAAM+iB,GAGrCphB,EAAK8Y,qBACT9Y,EAAK8Y,oBAAqBza,EAAM+iB,EAElC,EAEAriB,OAAO2hB,MAAQ,SAAUpiB,EAAK8kB,GAG7B,KAAQ7lB,gBAAgBwB,OAAO2hB,OAC9B,OAAO,IAAI3hB,OAAO2hB,MAAOpiB,EAAK8kB,GAI1B9kB,GAAOA,EAAID,MACfd,KAAKslB,cAAgBvkB,EACrBf,KAAKc,KAAOC,EAAID,KAIhBd,KAAK8lB,mBAAqB/kB,EAAIglB,uBACHtxB,IAAzBsM,EAAIglB,mBAGgB,IAApBhlB,EAAI6kB,YACL7D,WACAC,YAKDhiB,KAAK0D,OAAW3C,EAAI2C,QAAkC,IAAxB3C,EAAI2C,OAAO5O,SACxCiM,EAAI2C,OAAO9I,WACXmG,EAAI2C,OAEL1D,KAAK6kB,cAAgB9jB,EAAI8jB,cACzB7kB,KAAKgmB,cAAgBjlB,EAAIilB,eAIzBhmB,KAAKc,KAAOC,EAIR8kB,GACJrkB,OAAO8B,OAAQtD,KAAM6lB,GAItB7lB,KAAKimB,UAAYllB,GAAOA,EAAIklB,WAAa/f,KAAKggB,MAG9ClmB,KAAMwB,OAAOqC,UAAY,CAC1B,EAIArC,OAAO2hB,MAAMr0B,UAAY,CACxBuE,YAAamO,OAAO2hB,MACpB2C,mBAAoB9D,YACpB4C,qBAAsB5C,YACtB8C,8BAA+B9C,YAC/BmE,aAAa,EAEblD,eAAgB,WACf,IAAI9Z,EAAInJ,KAAKslB,cAEbtlB,KAAK8lB,mBAAqB/D,WAErB5Y,IAAMnJ,KAAKmmB,aACfhd,EAAE8Z,gBAEJ,EACAF,gBAAiB,WAChB,IAAI5Z,EAAInJ,KAAKslB,cAEbtlB,KAAK4kB,qBAAuB7C,WAEvB5Y,IAAMnJ,KAAKmmB,aACfhd,EAAE4Z,iBAEJ,EACAC,yBAA0B,WACzB,IAAI7Z,EAAInJ,KAAKslB,cAEbtlB,KAAK8kB,8BAAgC/C,WAEhC5Y,IAAMnJ,KAAKmmB,aACfhd,EAAE6Z,2BAGHhjB,KAAK+iB,iBACN,GAIDvhB,OAAOc,KAAM,CACZ8jB,QAAQ,EACRC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,SAAS,EACTC,QAAQ,EACRC,YAAY,EACZC,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,UAAU,EACVC,MAAM,EACN,MAAQ,EACR5lB,MAAM,EACN6lB,UAAU,EACVxc,KAAK,EACLyc,SAAS,EACT9B,QAAQ,EACR+B,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,aAAa,EACbC,SAAS,EACTC,SAAS,EACTC,eAAe,EACfC,WAAW,EACXC,SAAS,EACTC,OAAO,GACLtmB,OAAOghB,MAAM4C,SAEhB5jB,OAAOc,KAAM,CAAEylB,MAAO,UAAWC,KAAM,aAAc,SAAUlnB,EAAMgiB,GACpEthB,OAAOghB,MAAM1I,QAAShZ,GAAS,CAG9BojB,MAAO,WAQN,OAHAxB,eAAgB1iB,KAAMc,EAAMmhB,aAGrB,CACR,EACAiB,QAAS,WAMR,OAHAR,eAAgB1iB,KAAMc,IAGf,CACR,EAIA+f,SAAU,WACT,OAAO,CACR,EAEAiC,aAAcA,EAEhB,IAUAthB,OAAOc,KAAM,CACZ2lB,WAAY,YACZC,WAAY,WACZC,aAAc,cACdC,aAAc,eACZ,SAAUC,EAAM5D,GAClBjjB,OAAOghB,MAAM1I,QAASuO,GAAS,CAC9BvF,aAAc2B,EACdT,SAAUS,EAEVZ,OAAQ,SAAUrB,GACjB,IAAIrgB,EAEHmmB,EAAU9F,EAAMwD,cAChBxC,EAAYhB,EAAMgB,UASnB,OALM8E,IAAaA,IANTtoB,MAMgCwB,OAAOyE,SANvCjG,KAMyDsoB,MAClE9F,EAAM1hB,KAAO0iB,EAAUG,SACvBxhB,EAAMqhB,EAAUxY,QAAQ1c,MAAO0R,KAAMpP,WACrC4xB,EAAM1hB,KAAO2jB,GAEPtiB,CACR,EAEF,IAEAX,OAAOG,GAAG2B,OAAQ,CAEjB8e,GAAI,SAAUC,EAAO5gB,EAAUvE,EAAMyE,GACpC,OAAOygB,GAAIpiB,KAAMqiB,EAAO5gB,EAAUvE,EAAMyE,EACzC,EACA2gB,IAAK,SAAUD,EAAO5gB,EAAUvE,EAAMyE,GACrC,OAAOygB,GAAIpiB,KAAMqiB,EAAO5gB,EAAUvE,EAAMyE,EAAI,EAC7C,EACA8gB,IAAK,SAAUJ,EAAO5gB,EAAUE,GAC/B,IAAI6hB,EAAW1iB,EACf,GAAKuhB,GAASA,EAAMY,gBAAkBZ,EAAMmB,UAW3C,OARAA,EAAYnB,EAAMmB,UAClBhiB,OAAQ6gB,EAAMqC,gBAAiBjC,IAC9Be,EAAU1X,UACT0X,EAAUG,SAAW,IAAMH,EAAU1X,UACrC0X,EAAUG,SACXH,EAAU/hB,SACV+hB,EAAUxY,SAEJhL,KAER,GAAsB,iBAAVqiB,EAAqB,CAGhC,IAAMvhB,KAAQuhB,EACbriB,KAAKyiB,IAAK3hB,EAAMW,EAAU4gB,EAAOvhB,IAElC,OAAOd,IACR,CAUA,OATkB,IAAbyB,GAA0C,mBAAbA,IAGjCE,EAAKF,EACLA,OAAWhN,IAEA,IAAPkN,IACJA,EAAKqgB,aAEChiB,KAAKsC,MAAM,WACjBd,OAAOghB,MAAMznB,OAAQiF,KAAMqiB,EAAO1gB,EAAIF,EACvC,GACD,IAID,IAKC8mB,GAAe,wBAGfC,GAAW,oCACXC,GAAe,2CAGhB,SAASC,mBAAoBjmB,EAAMtM,GAClC,OAAKuG,SAAU+F,EAAM,UACpB/F,SAA+B,KAArBvG,EAAQrB,SAAkBqB,EAAUA,EAAQ6I,WAAY,OAE3DwC,OAAQiB,GAAOqT,SAAU,SAAW,IAGrCrT,CACR,CAGA,SAASkmB,cAAelmB,GAEvB,OADAA,EAAK3B,MAAyC,OAAhC2B,EAAKxO,aAAc,SAAsB,IAAMwO,EAAK3B,KAC3D2B,CACR,CACA,SAASmmB,cAAenmB,GAOvB,MAN2C,WAApCA,EAAK3B,MAAQ,IAAKX,MAAO,EAAG,GAClCsC,EAAK3B,KAAO2B,EAAK3B,KAAKX,MAAO,GAE7BsC,EAAKrH,gBAAiB,QAGhBqH,CACR,CAEA,SAASomB,eAAgB9nB,EAAK+nB,GAC7B,IAAIv7B,EAAG4D,EAAG2P,EAAgBioB,EAAUC,EAAU1F,EAE9C,GAAuB,IAAlBwF,EAAKh0B,SAAV,CAKA,GAAKmoB,EAASD,QAASjc,KAEtBuiB,EADWrG,EAASprB,IAAKkP,GACPuiB,QAKjB,IAAMxiB,KAFNmc,EAASliB,OAAQ+tB,EAAM,iBAETxF,EACb,IAAM/1B,EAAI,EAAG4D,EAAImyB,EAAQxiB,GAAOrT,OAAQF,EAAI4D,EAAG5D,IAC9CiU,OAAOghB,MAAMjM,IAAKuS,EAAMhoB,EAAMwiB,EAAQxiB,GAAQvT,IAO7C2vB,EAASF,QAASjc,KACtBgoB,EAAW7L,EAASrB,OAAQ9a,GAC5BioB,EAAWxnB,OAAO8B,OAAQ,CAAC,EAAGylB,GAE9B7L,EAASjsB,IAAK63B,EAAME,GAvBrB,CAyBD,CAGA,SAASC,SAAUloB,EAAK+nB,GACvB,IAAIpsB,EAAWosB,EAAKpsB,SAAShN,cAGX,UAAbgN,GAAwBwjB,EAAe7vB,KAAM0Q,EAAID,MACrDgoB,EAAKlY,QAAU7P,EAAI6P,QAGK,UAAblU,GAAqC,aAAbA,IACnCosB,EAAKrU,aAAe1T,EAAI0T,aAE1B,CAEA,SAASyU,SAAUC,EAAYz6B,EAAM6T,EAAUkf,GAG9C/yB,EAAO0R,EAAM1R,GAEb,IAAI2P,EAAUqE,EAAO6e,EAAS6H,EAAYzuB,EAAMY,EAC/ChO,EAAI,EACJ4D,EAAIg4B,EAAW17B,OACf47B,EAAWl4B,EAAI,EACfW,EAAQpD,EAAM,GACd46B,EAAkB5oB,EAAY5O,GAG/B,GAAKw3B,GACDn4B,EAAI,GAAsB,iBAAVW,IAChB2O,EAAQ4f,YAAcmI,GAASn4B,KAAMyB,GACxC,OAAOq3B,EAAW7mB,MAAM,SAAU+T,GACjC,IAAIb,EAAO2T,EAAWxmB,GAAI0T,GACrBiT,IACJ56B,EAAM,GAAMoD,EAAMoK,KAAM8D,KAAMqW,EAAOb,EAAKzjB,SAE3Cm3B,SAAU1T,EAAM9mB,EAAM6T,EAAUkf,EACjC,IAGD,GAAKtwB,IAEJuR,GADArE,EAAWijB,cAAe5yB,EAAMy6B,EAAY,GAAI/yB,eAAe,EAAO+yB,EAAY1H,IACjEziB,WAEmB,IAA/BX,EAASpC,WAAWxO,SACxB4Q,EAAWqE,GAIPA,GAAS+e,GAAU,CAOvB,IALA2H,GADA7H,EAAU/f,OAAOgB,IAAKse,OAAQziB,EAAU,UAAYsqB,gBAC/Bl7B,OAKbF,EAAI4D,EAAG5D,IACdoN,EAAO0D,EAEF9Q,IAAM87B,IACV1uB,EAAO6G,OAAOlQ,MAAOqJ,GAAM,GAAM,GAG5ByuB,GAIJ5nB,OAAOY,MAAOmf,EAAST,OAAQnmB,EAAM,YAIvC4H,EAASrG,KAAMitB,EAAY57B,GAAKoN,EAAMpN,GAGvC,GAAK67B,EAOJ,IANA7tB,EAAMgmB,EAASA,EAAQ9zB,OAAS,GAAI2I,cAGpCoL,OAAOgB,IAAK+e,EAASqH,eAGfr7B,EAAI,EAAGA,EAAI67B,EAAY77B,IAC5BoN,EAAO4mB,EAASh0B,GACX6yB,EAAY/vB,KAAMsK,EAAKmG,MAAQ,MAClCmc,EAASpB,OAAQlhB,EAAM,eACxB6G,OAAOyE,SAAU1K,EAAKZ,KAEjBA,EAAKoG,KAA8C,YAArCpG,EAAKmG,MAAQ,IAAKpR,cAG/B8R,OAAO+nB,WAAa5uB,EAAKsG,UAC7BO,OAAO+nB,SAAU5uB,EAAKoG,IAAK,CAC1BC,MAAOrG,EAAKqG,OAASrG,EAAK1G,aAAc,UACtCsH,GAGJ2F,QAASvG,EAAKgC,YAAY7M,QAAS24B,GAAc,IAAM9tB,EAAMY,GAKlE,CAGD,OAAO4tB,CACR,CAEA,SAASpuB,OAAQ0H,EAAMhB,EAAU+nB,GAKhC,IAJA,IAAI7uB,EACHinB,EAAQngB,EAAWD,OAAOiL,OAAQhL,EAAUgB,GAASA,EACrDlV,EAAI,EAE4B,OAAvBoN,EAAOinB,EAAOr0B,IAAeA,IAChCi8B,GAA8B,IAAlB7uB,EAAK7F,UACtB0M,OAAOioB,UAAW3I,OAAQnmB,IAGtBA,EAAKC,aACJ4uB,GAAYhL,WAAY7jB,IAC5BomB,cAAeD,OAAQnmB,EAAM,WAE9BA,EAAKC,WAAWC,YAAaF,IAI/B,OAAO8H,CACR,CAEAjB,OAAO8B,OAAQ,CACdue,cAAe,SAAU9vB,GACxB,OAAOA,CACR,EAEAT,MAAO,SAAUmR,EAAMinB,EAAeC,GACrC,IAAIp8B,EAAG4D,EAAGy4B,EAAaC,EACtBv4B,EAAQmR,EAAK5M,WAAW,GACxBi0B,EAAStL,WAAY/b,GAGtB,KAAMhC,EAAQ6f,gBAAsC,IAAlB7d,EAAK3N,UAAoC,KAAlB2N,EAAK3N,UAC3D0M,OAAOmT,SAAUlS,IAMnB,IAHAonB,EAAe/I,OAAQxvB,GAGjB/D,EAAI,EAAG4D,GAFby4B,EAAc9I,OAAQre,IAEOhV,OAAQF,EAAI4D,EAAG5D,IAC3C07B,SAAUW,EAAar8B,GAAKs8B,EAAct8B,IAK5C,GAAKm8B,EACJ,GAAKC,EAIJ,IAHAC,EAAcA,GAAe9I,OAAQre,GACrConB,EAAeA,GAAgB/I,OAAQxvB,GAEjC/D,EAAI,EAAG4D,EAAIy4B,EAAYn8B,OAAQF,EAAI4D,EAAG5D,IAC3Cs7B,eAAgBe,EAAar8B,GAAKs8B,EAAct8B,SAGjDs7B,eAAgBpmB,EAAMnR,GAWxB,OANAu4B,EAAe/I,OAAQxvB,EAAO,WACZ7D,OAAS,GAC1BszB,cAAe8I,GAAeC,GAAUhJ,OAAQre,EAAM,WAIhDnR,CACR,EAEAm4B,UAAW,SAAUvnB,GAKpB,IAJA,IAAIhF,EAAMuF,EAAM3B,EACfgZ,EAAUtY,OAAOghB,MAAM1I,QACvBvsB,EAAI,OAE6BkH,KAAxBgO,EAAOP,EAAO3U,IAAqBA,IAC5C,GAAKmvB,WAAYja,GAAS,CACzB,GAAOvF,EAAOuF,EAAMwa,EAASpZ,SAAc,CAC1C,GAAK3G,EAAKomB,OACT,IAAMxiB,KAAQ5D,EAAKomB,OACbxJ,EAAShZ,GACbU,OAAOghB,MAAMznB,OAAQ0H,EAAM3B,GAI3BU,OAAO8iB,YAAa7hB,EAAM3B,EAAM5D,EAAK2mB,QAOxCphB,EAAMwa,EAASpZ,cAAYpP,CAC5B,CACKgO,EAAMya,EAASrZ,WAInBpB,EAAMya,EAASrZ,cAAYpP,EAE7B,CAEF,IAGD+M,OAAOG,GAAG2B,OAAQ,CACjBymB,OAAQ,SAAUtoB,GACjB,OAAO1G,OAAQiF,KAAMyB,GAAU,EAChC,EAEA1G,OAAQ,SAAU0G,GACjB,OAAO1G,OAAQiF,KAAMyB,EACtB,EAEApP,KAAM,SAAUP,GACf,OAAO+pB,OAAQ7b,MAAM,SAAUlO,GAC9B,YAAiB2C,IAAV3C,EACN0P,OAAOnP,KAAM2N,MACbA,KAAKyY,QAAQnW,MAAM,WACK,IAAlBtC,KAAKlL,UAAoC,KAAlBkL,KAAKlL,UAAqC,IAAlBkL,KAAKlL,WACxDkL,KAAKrD,YAAc7K,EAErB,GACF,GAAG,KAAMA,EAAOlB,UAAUnD,OAC3B,EAEAu8B,OAAQ,WACP,OAAOd,SAAUlpB,KAAMpP,WAAW,SAAU6R,GACpB,IAAlBzC,KAAKlL,UAAoC,KAAlBkL,KAAKlL,UAAqC,IAAlBkL,KAAKlL,UAC3C4zB,mBAAoB1oB,KAAMyC,GAChC1D,YAAa0D,EAEtB,GACD,EAEAwnB,QAAS,WACR,OAAOf,SAAUlpB,KAAMpP,WAAW,SAAU6R,GAC3C,GAAuB,IAAlBzC,KAAKlL,UAAoC,KAAlBkL,KAAKlL,UAAqC,IAAlBkL,KAAKlL,SAAiB,CACzE,IAAI4O,EAASglB,mBAAoB1oB,KAAMyC,GACvCiB,EAAO3H,aAAc0G,EAAMiB,EAAO1E,WACnC,CACD,GACD,EAEAkrB,OAAQ,WACP,OAAOhB,SAAUlpB,KAAMpP,WAAW,SAAU6R,GACtCzC,KAAKpF,YACToF,KAAKpF,WAAWmB,aAAc0G,EAAMzC,KAEtC,GACD,EAEAmqB,MAAO,WACN,OAAOjB,SAAUlpB,KAAMpP,WAAW,SAAU6R,GACtCzC,KAAKpF,YACToF,KAAKpF,WAAWmB,aAAc0G,EAAMzC,KAAKsL,YAE3C,GACD,EAEAmN,MAAO,WAIN,IAHA,IAAIhW,EACHlV,EAAI,EAE2B,OAAtBkV,EAAOzC,KAAMzS,IAAeA,IACd,IAAlBkV,EAAK3N,WAGT0M,OAAOioB,UAAW3I,OAAQre,GAAM,IAGhCA,EAAK9F,YAAc,IAIrB,OAAOqD,IACR,EAEA1O,MAAO,SAAUo4B,EAAeC,GAI/B,OAHAD,EAAiC,MAAjBA,GAAgCA,EAChDC,EAAyC,MAArBA,EAA4BD,EAAgBC,EAEzD3pB,KAAKwC,KAAK,WAChB,OAAOhB,OAAOlQ,MAAO0O,KAAM0pB,EAAeC,EAC3C,GACD,EAEA53B,KAAM,SAAUD,GACf,OAAO+pB,OAAQ7b,MAAM,SAAUlO,GAC9B,IAAI2Q,EAAOzC,KAAM,IAAO,CAAC,EACxBzS,EAAI,EACJ4D,EAAI6O,KAAKvS,OAEV,QAAegH,IAAV3C,GAAyC,IAAlB2Q,EAAK3N,SAChC,OAAO2N,EAAKnF,UAIb,GAAsB,iBAAVxL,IAAuBy2B,GAAal4B,KAAMyB,KACpD0uB,GAAWL,EAASxW,KAAM7X,IAAW,CAAE,GAAI,KAAQ,GAAIpC,eAAkB,CAE1EoC,EAAQ0P,OAAOqgB,cAAe/vB,GAE9B,IACC,KAAQvE,EAAI4D,EAAG5D,IAIS,KAHvBkV,EAAOzC,KAAMzS,IAAO,CAAC,GAGXuH,WACT0M,OAAOioB,UAAW3I,OAAQre,GAAM,IAChCA,EAAKnF,UAAYxL,GAInB2Q,EAAO,CAGR,CAAE,MAAQ0G,GAAK,CAChB,CAEK1G,GACJzC,KAAKyY,QAAQuR,OAAQl4B,EAEvB,GAAG,KAAMA,EAAOlB,UAAUnD,OAC3B,EAEA28B,YAAa,WACZ,IAAI3I,EAAU,GAGd,OAAOyH,SAAUlpB,KAAMpP,WAAW,SAAU6R,GAC3C,IAAIrI,EAAS4F,KAAKpF,WAEb4G,OAAOkD,QAAS1E,KAAMyhB,GAAY,IACtCjgB,OAAOioB,UAAW3I,OAAQ9gB,OACrB5F,GACJA,EAAOiwB,aAAc5nB,EAAMzC,MAK9B,GAAGyhB,EACJ,IAGDjgB,OAAOc,KAAM,CACZgoB,SAAU,SACVC,UAAW,UACXxuB,aAAc,SACdyuB,YAAa,QACbC,WAAY,gBACV,SAAUxvB,EAAMyvB,GAClBlpB,OAAOG,GAAI1G,GAAS,SAAUwG,GAO7B,IANA,IAAIS,EACHC,EAAM,GACNwoB,EAASnpB,OAAQC,GACjBmB,EAAO+nB,EAAOl9B,OAAS,EACvBF,EAAI,EAEGA,GAAKqV,EAAMrV,IAClB2U,EAAQ3U,IAAMqV,EAAO5C,KAAOA,KAAK1O,OAAO,GACxCkQ,OAAQmpB,EAAQp9B,IAAOm9B,GAAYxoB,GAInC3S,EAAKjB,MAAO6T,EAAKD,EAAMrQ,OAGxB,OAAOmO,KAAKiC,UAAWE,EACxB,CACD,IACA,IAAIyoB,GAAY,IAAIx6B,OAAQ,KAAOguB,EAAO,kBAAmB,KAEzDyM,UAAY,SAAUpoB,GAKxB,IAAIskB,EAAOtkB,EAAKrM,cAAc6V,YAM9B,OAJM8a,GAASA,EAAK+D,SACnB/D,EAAOvzB,GAGDuzB,EAAKgE,iBAAkBtoB,EAC/B,EAEGuoB,KAAO,SAAUvoB,EAAMc,EAAShB,GACnC,IAAIJ,EAAKlH,EACRgwB,EAAM,CAAC,EAGR,IAAMhwB,KAAQsI,EACb0nB,EAAKhwB,GAASwH,EAAKmc,MAAO3jB,GAC1BwH,EAAKmc,MAAO3jB,GAASsI,EAAStI,GAM/B,IAAMA,KAHNkH,EAAMI,EAASrG,KAAMuG,GAGPc,EACbd,EAAKmc,MAAO3jB,GAASgwB,EAAKhwB,GAG3B,OAAOkH,CACR,EAGI+oB,GAAY,IAAI96B,OAAQmuB,EAAUpU,KAAM,KAAO,KAiJnD,SAASghB,OAAQ1oB,EAAMxH,EAAMmwB,GAC5B,IAAIC,EAAOC,EAAUC,EAAUppB,EAM9Byc,EAAQnc,EAAKmc,MAqCd,OAnCAwM,EAAWA,GAAYP,UAAWpoB,MAQpB,MAFbN,EAAMipB,EAASI,iBAAkBvwB,IAAUmwB,EAAUnwB,KAEjCujB,WAAY/b,KAC/BN,EAAMX,OAAOod,MAAOnc,EAAMxH,KAQrBwF,EAAQgrB,kBAAoBb,GAAUv6B,KAAM8R,IAAS+oB,GAAU76B,KAAM4K,KAG1EowB,EAAQzM,EAAMyM,MACdC,EAAW1M,EAAM0M,SACjBC,EAAW3M,EAAM2M,SAGjB3M,EAAM0M,SAAW1M,EAAM2M,SAAW3M,EAAMyM,MAAQlpB,EAChDA,EAAMipB,EAASC,MAGfzM,EAAMyM,MAAQA,EACdzM,EAAM0M,SAAWA,EACjB1M,EAAM2M,SAAWA,SAIJ92B,IAAR0N,EAINA,EAAM,GACNA,CACF,CAGA,SAASupB,aAAcC,EAAaC,GAGnC,MAAO,CACN/5B,IAAK,WACJ,IAAK85B,IASL,OAAS3rB,KAAKnO,IAAM+5B,GAASt9B,MAAO0R,KAAMpP,kBALlCoP,KAAKnO,GAMd,EAEF,EAnNA,WAIC,SAASg6B,oBAGR,GAAM5L,EAAN,CAIA6L,EAAUlN,MAAMmN,QAAU,+EAE1B9L,EAAIrB,MAAMmN,QACT,4HAGDnwB,EAAgBmD,YAAa+sB,GAAY/sB,YAAakhB,GAEtD,IAAI+L,EAAWx4B,EAAOu3B,iBAAkB9K,GACxCgM,EAAoC,OAAjBD,EAAS9f,IAG5BggB,EAAsE,KAA9CC,mBAAoBH,EAASI,YAIrDnM,EAAIrB,MAAMyN,MAAQ,MAClBC,EAA6D,KAAzCH,mBAAoBH,EAASK,OAIjDE,EAAgE,KAAzCJ,mBAAoBH,EAASX,OAMpDpL,EAAIrB,MAAM4N,SAAW,WACrBC,EAAiE,KAA9CN,mBAAoBlM,EAAIyM,YAAc,GAEzD9wB,EAAgBf,YAAaixB,GAI7B7L,EAAM,IApCN,CAqCD,CAEA,SAASkM,mBAAoBQ,GAC5B,OAAO7oB,KAAK8oB,MAAOC,WAAYF,GAChC,CAEA,IAAIV,EAAkBM,EAAsBE,EAAkBH,EAC7DQ,EAAyBZ,EACzBJ,EAAYn4B,EAASuC,cAAe,OACpC+pB,EAAMtsB,EAASuC,cAAe,OAGzB+pB,EAAIrB,QAMVqB,EAAIrB,MAAMmO,eAAiB,cAC3B9M,EAAIpqB,WAAW,GAAO+oB,MAAMmO,eAAiB,GAC7CtsB,EAAQusB,gBAA+C,gBAA7B/M,EAAIrB,MAAMmO,eAEpCvrB,OAAO8B,OAAQ7C,EAAS,CACvBwsB,kBAAmB,WAElB,OADApB,oBACOU,CACR,EACAd,eAAgB,WAEf,OADAI,oBACOS,CACR,EACAY,cAAe,WAEd,OADArB,oBACOI,CACR,EACAkB,mBAAoB,WAEnB,OADAtB,oBACOK,CACR,EACAkB,cAAe,WAEd,OADAvB,oBACOY,CACR,EAWAY,qBAAsB,WACrB,IAAI3zB,EAAOinB,EAAI2M,EAASC,EAmCxB,OAlCgC,MAA3BT,IACJpzB,EAAQ/F,EAASuC,cAAe,SAChCyqB,EAAKhtB,EAASuC,cAAe,MAC7Bo3B,EAAU35B,EAASuC,cAAe,OAElCwD,EAAMklB,MAAMmN,QAAU,2DACtBpL,EAAG/B,MAAMmN,QAAU,mBAKnBpL,EAAG/B,MAAM4O,OAAS,MAClBF,EAAQ1O,MAAM4O,OAAS,MAQvBF,EAAQ1O,MAAMC,QAAU,QAExBjjB,EACEmD,YAAarF,GACbqF,YAAa4hB,GACb5hB,YAAauuB,GAEfC,EAAU/5B,EAAOu3B,iBAAkBpK,GACnCmM,EAA4BW,SAAUF,EAAQC,OAAQ,IACrDC,SAAUF,EAAQG,eAAgB,IAClCD,SAAUF,EAAQI,kBAAmB,MAAWhN,EAAGiN,aAEpDhyB,EAAgBf,YAAanB,IAEvBozB,CACR,IAEA,CA1IF,GAsNA,IAAIe,GAAc,CAAE,SAAU,MAAO,MACpCC,GAAan6B,EAASuC,cAAe,OAAQ0oB,MAC7CmP,GAAc,CAAC,EAkBhB,SAASC,cAAe/yB,GACvB,IAAIgzB,EAAQzsB,OAAO0sB,SAAUjzB,IAAU8yB,GAAa9yB,GAEpD,OAAKgzB,IAGAhzB,KAAQ6yB,GACL7yB,EAED8yB,GAAa9yB,GAxBrB,SAASkzB,eAAgBlzB,GAMxB,IAHA,IAAImzB,EAAUnzB,EAAM,GAAIshB,cAAgBthB,EAAKkF,MAAO,GACnD5S,EAAIsgC,GAAYpgC,OAETF,KAEP,IADA0N,EAAO4yB,GAAatgC,GAAM6gC,KACbN,GACZ,OAAO7yB,CAGV,CAY8BkzB,CAAgBlzB,IAAUA,EACxD,CAGA,IAKCozB,GAAe,4BACfC,GAAc,MACdC,GAAU,CAAE/B,SAAU,WAAYgC,WAAY,SAAU3P,QAAS,SACjE4P,GAAqB,CACpBC,cAAe,IACfC,WAAY,OAGd,SAASC,kBAAmB7rB,EAAOjR,EAAO+8B,GAIzC,IAAIpzB,EAAU6iB,EAAQ3U,KAAM7X,GAC5B,OAAO2J,EAGNqI,KAAKgrB,IAAK,EAAGrzB,EAAS,IAAQozB,GAAY,KAAUpzB,EAAS,IAAO,MACpE3J,CACF,CAEA,SAASi9B,mBAAoBtsB,EAAMusB,EAAWC,EAAKC,EAAaC,EAAQC,GACvE,IAAI7hC,EAAkB,UAAdyhC,EAAwB,EAAI,EACnCK,EAAQ,EACRC,EAAQ,EAGT,GAAKL,KAAUC,EAAc,SAAW,WACvC,OAAO,EAGR,KAAQ3hC,EAAI,EAAGA,GAAK,EAGN,WAAR0hC,IACJK,GAAS9tB,OAAOsd,IAAKrc,EAAMwsB,EAAM1Q,EAAWhxB,IAAK,EAAM4hC,IAIlDD,GAmBQ,YAARD,IACJK,GAAS9tB,OAAOsd,IAAKrc,EAAM,UAAY8b,EAAWhxB,IAAK,EAAM4hC,IAIjD,WAARF,IACJK,GAAS9tB,OAAOsd,IAAKrc,EAAM,SAAW8b,EAAWhxB,GAAM,SAAS,EAAM4hC,MAtBvEG,GAAS9tB,OAAOsd,IAAKrc,EAAM,UAAY8b,EAAWhxB,IAAK,EAAM4hC,GAGhD,YAARF,EACJK,GAAS9tB,OAAOsd,IAAKrc,EAAM,SAAW8b,EAAWhxB,GAAM,SAAS,EAAM4hC,GAItEE,GAAS7tB,OAAOsd,IAAKrc,EAAM,SAAW8b,EAAWhxB,GAAM,SAAS,EAAM4hC,IAoCzE,OAhBMD,GAAeE,GAAe,IAInCE,GAASxrB,KAAKgrB,IAAK,EAAGhrB,KAAKyrB,KAC1B9sB,EAAM,SAAWusB,EAAW,GAAIzS,cAAgByS,EAAU7uB,MAAO,IACjEivB,EACAE,EACAD,EACA,MAIM,GAGDC,CACR,CAEA,SAASE,iBAAkB/sB,EAAMusB,EAAWK,GAG3C,IAAIF,EAAStE,UAAWpoB,GAKvBysB,IADmBzuB,EAAQwsB,qBAAuBoC,IAEE,eAAnD7tB,OAAOsd,IAAKrc,EAAM,aAAa,EAAO0sB,GACvCM,EAAmBP,EAEnB9tB,EAAM+pB,OAAQ1oB,EAAMusB,EAAWG,GAC/BO,EAAa,SAAWV,EAAW,GAAIzS,cAAgByS,EAAU7uB,MAAO,GAIzE,GAAKyqB,GAAUv6B,KAAM+Q,GAAQ,CAC5B,IAAMiuB,EACL,OAAOjuB,EAERA,EAAM,MACP,CAwCA,QAlCQX,EAAQwsB,qBAAuBiC,IAMrCzuB,EAAQ4sB,wBAA0B3wB,SAAU+F,EAAM,OAI3C,SAARrB,IAICyrB,WAAYzrB,IAA0D,WAAjDI,OAAOsd,IAAKrc,EAAM,WAAW,EAAO0sB,KAG1D1sB,EAAKktB,iBAAiBliC,SAEtByhC,EAAiE,eAAnD1tB,OAAOsd,IAAKrc,EAAM,aAAa,EAAO0sB,IAKpDM,EAAmBC,KAAcjtB,KAEhCrB,EAAMqB,EAAMitB,MAKdtuB,EAAMyrB,WAAYzrB,IAAS,GAI1B2tB,mBACCtsB,EACAusB,EACAK,IAAWH,EAAc,SAAW,WACpCO,EACAN,EAGA/tB,GAEE,IACL,CA8SA,SAASwuB,MAAOntB,EAAMc,EAAS5R,EAAMwR,EAAK0sB,GACzC,OAAO,IAAID,MAAM9gC,UAAU8S,KAAMa,EAAMc,EAAS5R,EAAMwR,EAAK0sB,EAC5D,CA9SAruB,OAAO8B,OAAQ,CAIdwsB,SAAU,CACTC,QAAS,CACRl+B,IAAK,SAAU4Q,EAAM2oB,GACpB,GAAKA,EAAW,CAGf,IAAIjpB,EAAMgpB,OAAQ1oB,EAAM,WACxB,MAAe,KAARN,EAAa,IAAMA,CAC3B,CACD,IAKFqd,UAAW,CACV,yBAA2B,EAC3B,aAAe,EACf,aAAe,EACf,UAAY,EACZ,YAAc,EACd,YAAc,EACd,UAAY,EACZ,YAAc,EACd,eAAiB,EACjB,iBAAmB,EACnB,SAAW,EACX,YAAc,EACd,cAAgB,EAChB,YAAc,EACd,SAAW,EACX,OAAS,EACT,SAAW,EACX,QAAU,EACV,QAAU,EACV,MAAQ,GAKT0O,SAAU,CAAC,EAGXtP,MAAO,SAAUnc,EAAMxH,EAAMnJ,EAAOu9B,GAGnC,GAAM5sB,GAA0B,IAAlBA,EAAK3N,UAAoC,IAAlB2N,EAAK3N,UAAmB2N,EAAKmc,MAAlE,CAKA,IAAIzc,EAAKrB,EAAM/J,EACdi5B,EAAWxT,UAAWvhB,GACtBg1B,EAAe3B,GAAYj+B,KAAM4K,GACjC2jB,EAAQnc,EAAKmc,MAad,GARMqR,IACLh1B,EAAO+yB,cAAegC,IAIvBj5B,EAAQyK,OAAOsuB,SAAU70B,IAAUuG,OAAOsuB,SAAUE,QAGrCv7B,IAAV3C,EA0CJ,OAAKiF,GAAS,QAASA,QACwBtC,KAA5C0N,EAAMpL,EAAMlF,IAAK4Q,GAAM,EAAO4sB,IAEzBltB,EAIDyc,EAAO3jB,GA7CA,YAHd6F,SAAchP,KAGcqQ,EAAMmc,EAAQ3U,KAAM7X,KAAaqQ,EAAK,KACjErQ,EAAQitB,UAAWtc,EAAMxH,EAAMkH,GAG/BrB,EAAO,UAIM,MAAThP,GAAiBA,GAAUA,IAOlB,WAATgP,GAAsBmvB,IAC1Bn+B,GAASqQ,GAAOA,EAAK,KAASX,OAAOge,UAAWwQ,GAAa,GAAK,OAI7DvvB,EAAQusB,iBAA6B,KAAVl7B,GAAiD,IAAjCmJ,EAAKjL,QAAS,gBAC9D4uB,EAAO3jB,GAAS,WAIXlE,GAAY,QAASA,QACsBtC,KAA9C3C,EAAQiF,EAAM9F,IAAKwR,EAAM3Q,EAAOu9B,MAE7BY,EACJrR,EAAMsR,YAAaj1B,EAAMnJ,GAEzB8sB,EAAO3jB,GAASnJ,GAtDnB,CAsED,EAEAgtB,IAAK,SAAUrc,EAAMxH,EAAMo0B,EAAOF,GACjC,IAAI/tB,EAAKY,EAAKjL,EACbi5B,EAAWxT,UAAWvhB,GA6BvB,OA5BgBqzB,GAAYj+B,KAAM4K,KAMjCA,EAAO+yB,cAAegC,KAIvBj5B,EAAQyK,OAAOsuB,SAAU70B,IAAUuG,OAAOsuB,SAAUE,KAGtC,QAASj5B,IACtBqK,EAAMrK,EAAMlF,IAAK4Q,GAAM,EAAM4sB,SAIjB56B,IAAR2M,IACJA,EAAM+pB,OAAQ1oB,EAAMxH,EAAMk0B,IAId,WAAR/tB,GAAoBnG,KAAQwzB,KAChCrtB,EAAMqtB,GAAoBxzB,IAIZ,KAAVo0B,GAAgBA,GACpBrtB,EAAM6qB,WAAYzrB,IACD,IAAViuB,GAAkBc,SAAUnuB,GAAQA,GAAO,EAAIZ,GAGhDA,CACR,IAGDI,OAAOc,KAAM,CAAE,SAAU,UAAW,SAAU2C,EAAI+pB,GACjDxtB,OAAOsuB,SAAUd,GAAc,CAC9Bn9B,IAAK,SAAU4Q,EAAM2oB,EAAUiE,GAC9B,GAAKjE,EAIJ,OAAOiD,GAAah+B,KAAMmR,OAAOsd,IAAKrc,EAAM,aAQxCA,EAAKktB,iBAAiBliC,QAAWgV,EAAK2tB,wBAAwB/E,MAIjEmE,iBAAkB/sB,EAAMusB,EAAWK,GAHnCrE,KAAMvoB,EAAM8rB,IAAS,WACpB,OAAOiB,iBAAkB/sB,EAAMusB,EAAWK,EAC3C,GAGH,EAEAp+B,IAAK,SAAUwR,EAAM3Q,EAAOu9B,GAC3B,IAAI5zB,EACH0zB,EAAStE,UAAWpoB,GAIpB4tB,GAAsB5vB,EAAQ2sB,iBACT,aAApB+B,EAAO3C,SAIR0C,GADkBmB,GAAsBhB,IAEY,eAAnD7tB,OAAOsd,IAAKrc,EAAM,aAAa,EAAO0sB,GACvCN,EAAWQ,EACVN,mBACCtsB,EACAusB,EACAK,EACAH,EACAC,GAED,EAqBF,OAjBKD,GAAemB,IACnBxB,GAAY/qB,KAAKyrB,KAChB9sB,EAAM,SAAWusB,EAAW,GAAIzS,cAAgByS,EAAU7uB,MAAO,IACjE0sB,WAAYsC,EAAQH,IACpBD,mBAAoBtsB,EAAMusB,EAAW,UAAU,EAAOG,GACtD,KAKGN,IAAcpzB,EAAU6iB,EAAQ3U,KAAM7X,KACb,QAA3B2J,EAAS,IAAO,QAElBgH,EAAKmc,MAAOoQ,GAAcl9B,EAC1BA,EAAQ0P,OAAOsd,IAAKrc,EAAMusB,IAGpBJ,kBAAmBnsB,EAAM3Q,EAAO+8B,EACxC,EAEF,IAEArtB,OAAOsuB,SAAS1D,WAAaV,aAAcjrB,EAAQ0sB,oBAClD,SAAU1qB,EAAM2oB,GACf,GAAKA,EACJ,OAASyB,WAAY1B,OAAQ1oB,EAAM,gBAClCA,EAAK2tB,wBAAwBE,KAC5BtF,KAAMvoB,EAAM,CAAE2pB,WAAY,IAAK,WAC9B,OAAO3pB,EAAK2tB,wBAAwBE,IACrC,KACE,IAEN,IAID9uB,OAAOc,KAAM,CACZiuB,OAAQ,GACRC,QAAS,GACTC,OAAQ,UACN,SAAUC,EAAQ78B,GACpB2N,OAAOsuB,SAAUY,EAAS78B,GAAW,CACpC88B,OAAQ,SAAU7+B,GAOjB,IANA,IAAIvE,EAAI,EACPqjC,EAAW,CAAC,EAGZC,EAAyB,iBAAV/+B,EAAqBA,EAAMkT,MAAO,KAAQ,CAAElT,GAEpDvE,EAAI,EAAGA,IACdqjC,EAAUF,EAASnS,EAAWhxB,GAAMsG,GACnCg9B,EAAOtjC,IAAOsjC,EAAOtjC,EAAI,IAAOsjC,EAAO,GAGzC,OAAOD,CACR,GAGe,WAAXF,IACJlvB,OAAOsuB,SAAUY,EAAS78B,GAAS5C,IAAM29B,kBAE3C,IAEAptB,OAAOG,GAAG2B,OAAQ,CACjBwb,IAAK,SAAU7jB,EAAMnJ,GACpB,OAAO+pB,OAAQ7b,MAAM,SAAUyC,EAAMxH,EAAMnJ,GAC1C,IAAIq9B,EAAQlsB,EACXT,EAAM,CAAC,EACPjV,EAAI,EAEL,GAAKF,MAAMC,QAAS2N,GAAS,CAI5B,IAHAk0B,EAAStE,UAAWpoB,GACpBQ,EAAMhI,EAAKxN,OAEHF,EAAI0V,EAAK1V,IAChBiV,EAAKvH,EAAM1N,IAAQiU,OAAOsd,IAAKrc,EAAMxH,EAAM1N,IAAK,EAAO4hC,GAGxD,OAAO3sB,CACR,CAEA,YAAiB/N,IAAV3C,EACN0P,OAAOod,MAAOnc,EAAMxH,EAAMnJ,GAC1B0P,OAAOsd,IAAKrc,EAAMxH,EACpB,GAAGA,EAAMnJ,EAAOlB,UAAUnD,OAAS,EACpC,IAOD+T,OAAOouB,MAAQA,MAEfA,MAAM9gC,UAAY,CACjBuE,YAAau8B,MACbhuB,KAAM,SAAUa,EAAMc,EAAS5R,EAAMwR,EAAK0sB,EAAQtQ,GACjDvf,KAAKyC,KAAOA,EACZzC,KAAKrO,KAAOA,EACZqO,KAAK6vB,OAASA,GAAUruB,OAAOquB,OAAOhP,SACtC7gB,KAAKuD,QAAUA,EACfvD,KAAK0P,MAAQ1P,KAAKkmB,IAAMlmB,KAAKmL,MAC7BnL,KAAKmD,IAAMA,EACXnD,KAAKuf,KAAOA,IAAU/d,OAAOge,UAAW7tB,GAAS,GAAK,KACvD,EACAwZ,IAAK,WACJ,IAAIpU,EAAQ64B,MAAMkB,UAAW9wB,KAAKrO,MAElC,OAAOoF,GAASA,EAAMlF,IACrBkF,EAAMlF,IAAKmO,MACX4vB,MAAMkB,UAAUjQ,SAAShvB,IAAKmO,KAChC,EACA+wB,IAAK,SAAUC,GACd,IAAIC,EACHl6B,EAAQ64B,MAAMkB,UAAW9wB,KAAKrO,MAoB/B,OAlBKqO,KAAKuD,QAAQ2tB,SACjBlxB,KAAKmxB,IAAMF,EAAQzvB,OAAOquB,OAAQ7vB,KAAK6vB,QACtCmB,EAAShxB,KAAKuD,QAAQ2tB,SAAWF,EAAS,EAAG,EAAGhxB,KAAKuD,QAAQ2tB,UAG9DlxB,KAAKmxB,IAAMF,EAAQD,EAEpBhxB,KAAKkmB,KAAQlmB,KAAKmD,IAAMnD,KAAK0P,OAAUuhB,EAAQjxB,KAAK0P,MAE/C1P,KAAKuD,QAAQ6tB,MACjBpxB,KAAKuD,QAAQ6tB,KAAKl1B,KAAM8D,KAAKyC,KAAMzC,KAAKkmB,IAAKlmB,MAGzCjJ,GAASA,EAAM9F,IACnB8F,EAAM9F,IAAK+O,MAEX4vB,MAAMkB,UAAUjQ,SAAS5vB,IAAK+O,MAExBA,IACR,GAGD4vB,MAAM9gC,UAAU8S,KAAK9S,UAAY8gC,MAAM9gC,UAEvC8gC,MAAMkB,UAAY,CACjBjQ,SAAU,CACThvB,IAAK,SAAUotB,GACd,IAAIjQ,EAIJ,OAA6B,IAAxBiQ,EAAMxc,KAAK3N,UACa,MAA5BmqB,EAAMxc,KAAMwc,EAAMttB,OAAoD,MAAlCstB,EAAMxc,KAAKmc,MAAOK,EAAMttB,MACrDstB,EAAMxc,KAAMwc,EAAMttB,OAO1Bqd,EAASxN,OAAOsd,IAAKG,EAAMxc,KAAMwc,EAAMttB,KAAM,MAGhB,SAAXqd,EAAwBA,EAAJ,CACvC,EACA/d,IAAK,SAAUguB,GAKTzd,OAAO6vB,GAAGD,KAAMnS,EAAMttB,MAC1B6P,OAAO6vB,GAAGD,KAAMnS,EAAMttB,MAAQstB,GACK,IAAxBA,EAAMxc,KAAK3N,WACtB0M,OAAOsuB,SAAU7Q,EAAMttB,OAC6B,MAAnDstB,EAAMxc,KAAKmc,MAAOoP,cAAe/O,EAAMttB,OAGxCstB,EAAMxc,KAAMwc,EAAMttB,MAASstB,EAAMiH,IAFjC1kB,OAAOod,MAAOK,EAAMxc,KAAMwc,EAAMttB,KAAMstB,EAAMiH,IAAMjH,EAAMM,KAI1D,IAMFqQ,MAAMkB,UAAUQ,UAAY1B,MAAMkB,UAAUS,WAAa,CACxDtgC,IAAK,SAAUguB,GACTA,EAAMxc,KAAK3N,UAAYmqB,EAAMxc,KAAK7H,aACtCqkB,EAAMxc,KAAMwc,EAAMttB,MAASstB,EAAMiH,IAEnC,GAGD1kB,OAAOquB,OAAS,CACf2B,OAAQ,SAAUC,GACjB,OAAOA,CACR,EACAC,MAAO,SAAUD,GAChB,MAAO,GAAM3tB,KAAK6tB,IAAKF,EAAI3tB,KAAK8tB,IAAO,CACxC,EACA/Q,SAAU,SAGXrf,OAAO6vB,GAAKzB,MAAM9gC,UAAU8S,KAG5BJ,OAAO6vB,GAAGD,KAAO,CAAC,EAKlB,IACCS,GAAOC,GACPC,GAAW,yBACXC,GAAO,cAER,SAASC,WACHH,MACqB,IAApBn+B,EAASu+B,QAAoB1+B,EAAO2+B,sBACxC3+B,EAAO2+B,sBAAuBF,UAE9Bz+B,EAAOgnB,WAAYyX,SAAUzwB,OAAO6vB,GAAGe,UAGxC5wB,OAAO6vB,GAAGgB,OAEZ,CAGA,SAASC,cAIR,OAHA9+B,EAAOgnB,YAAY,WAClBqX,QAAQp9B,CACT,IACSo9B,GAAQ3rB,KAAKggB,KACvB,CAGA,SAASqM,MAAOzxB,EAAM0xB,GACrB,IAAI1K,EACHv6B,EAAI,EACJwd,EAAQ,CAAEyiB,OAAQ1sB,GAKnB,IADA0xB,EAAeA,EAAe,EAAI,EAC1BjlC,EAAI,EAAGA,GAAK,EAAIilC,EAEvBznB,EAAO,UADP+c,EAAQvJ,EAAWhxB,KACSwd,EAAO,UAAY+c,GAAUhnB,EAO1D,OAJK0xB,IACJznB,EAAMglB,QAAUhlB,EAAMsgB,MAAQvqB,GAGxBiK,CACR,CAEA,SAAS0nB,YAAa3gC,EAAOH,EAAM+gC,GAKlC,IAJA,IAAIzT,EACHkK,GAAewJ,UAAUC,SAAUjhC,IAAU,IAAK3C,OAAQ2jC,UAAUC,SAAU,MAC9Evc,EAAQ,EACR5oB,EAAS07B,EAAW17B,OACb4oB,EAAQ5oB,EAAQ4oB,IACvB,GAAO4I,EAAQkK,EAAY9S,GAAQna,KAAMw2B,EAAW/gC,EAAMG,GAGzD,OAAOmtB,CAGV,CAmNA,SAAS0T,UAAWlwB,EAAMowB,EAAYtvB,GACrC,IAAIyL,EACH8jB,EACAzc,EAAQ,EACR5oB,EAASklC,UAAUI,WAAWtlC,OAC9BwrB,EAAWzX,OAAOqX,WAAWG,QAAQ,kBAG7BqZ,KAAK5vB,IACb,IACA4vB,KAAO,WACN,GAAKS,EACJ,OAAO,EAYR,IAVA,IAAIE,EAAcnB,IAASS,cAC1B1X,EAAY9W,KAAKgrB,IAAK,EAAG4D,EAAUO,UAAYP,EAAUxB,SAAW8B,GAKpEhC,EAAU,GADHpW,EAAY8X,EAAUxB,UAAY,GAEzC7a,EAAQ,EACR5oB,EAASilC,EAAUQ,OAAOzlC,OAEnB4oB,EAAQ5oB,EAAQ4oB,IACvBqc,EAAUQ,OAAQ7c,GAAQ0a,IAAKC,GAMhC,OAHA/X,EAASgB,WAAYxX,EAAM,CAAEiwB,EAAW1B,EAASpW,IAG5CoW,EAAU,GAAKvjC,EACZmtB,GAIFntB,GACLwrB,EAASgB,WAAYxX,EAAM,CAAEiwB,EAAW,EAAG,IAI5CzZ,EAASiB,YAAazX,EAAM,CAAEiwB,KACvB,EACR,EACAA,EAAYzZ,EAASvB,QAAS,CAC7BjV,KAAMA,EACNojB,MAAOrkB,OAAO8B,OAAQ,CAAC,EAAGuvB,GAC1BM,KAAM3xB,OAAO8B,QAAQ,EAAM,CAC1B8vB,cAAe,CAAC,EAChBvD,OAAQruB,OAAOquB,OAAOhP,UACpBtd,GACH8vB,mBAAoBR,EACpBS,gBAAiB/vB,EACjB0vB,UAAWpB,IAASS,cACpBpB,SAAU3tB,EAAQ2tB,SAClBgC,OAAQ,GACRT,YAAa,SAAU9gC,EAAMwR,GAC5B,IAAI8b,EAAQzd,OAAOouB,MAAOntB,EAAMiwB,EAAUS,KAAMxhC,EAAMwR,EACrDuvB,EAAUS,KAAKC,cAAezhC,IAAU+gC,EAAUS,KAAKtD,QAExD,OADA6C,EAAUQ,OAAO3jC,KAAM0vB,GAChBA,CACR,EACAlB,KAAM,SAAUwV,GACf,IAAIld,EAAQ,EAIX5oB,EAAS8lC,EAAUb,EAAUQ,OAAOzlC,OAAS,EAC9C,GAAKqlC,EACJ,OAAO9yB,KAGR,IADA8yB,GAAU,EACFzc,EAAQ5oB,EAAQ4oB,IACvBqc,EAAUQ,OAAQ7c,GAAQ0a,IAAK,GAUhC,OANKwC,GACJta,EAASgB,WAAYxX,EAAM,CAAEiwB,EAAW,EAAG,IAC3CzZ,EAASiB,YAAazX,EAAM,CAAEiwB,EAAWa,KAEzCta,EAASqB,WAAY7X,EAAM,CAAEiwB,EAAWa,IAElCvzB,IACR,IAED6lB,EAAQ6M,EAAU7M,MAInB,KA/HD,SAAS2N,WAAY3N,EAAOuN,GAC3B,IAAI/c,EAAOpb,EAAM40B,EAAQ/9B,EAAOiF,EAGhC,IAAMsf,KAASwP,EAed,GAbAgK,EAASuD,EADTn4B,EAAOuhB,UAAWnG,IAElBvkB,EAAQ+zB,EAAOxP,GACVhpB,MAAMC,QAASwE,KACnB+9B,EAAS/9B,EAAO,GAChBA,EAAQ+zB,EAAOxP,GAAUvkB,EAAO,IAG5BukB,IAAUpb,IACd4qB,EAAO5qB,GAASnJ,SACT+zB,EAAOxP,KAGftf,EAAQyK,OAAOsuB,SAAU70B,KACX,WAAYlE,EAMzB,IAAMsf,KALNvkB,EAAQiF,EAAM45B,OAAQ7+B,UACf+zB,EAAO5qB,GAICnJ,EACNukB,KAASwP,IAChBA,EAAOxP,GAAUvkB,EAAOukB,GACxB+c,EAAe/c,GAAUwZ,QAI3BuD,EAAen4B,GAAS40B,CAG3B,CA0FC2D,CAAY3N,EAAO6M,EAAUS,KAAKC,eAE1B/c,EAAQ5oB,EAAQ4oB,IAEvB,GADArH,EAAS2jB,UAAUI,WAAY1c,GAAQna,KAAMw2B,EAAWjwB,EAAMojB,EAAO6M,EAAUS,MAM9E,OAJKzyB,EAAYsO,EAAO+O,QACvBvc,OAAOsc,YAAa4U,EAAUjwB,KAAMiwB,EAAUS,KAAK/a,OAAQ2F,KAC1D/O,EAAO+O,KAAKhvB,KAAMigB,IAEbA,EAyBT,OArBAxN,OAAOgB,IAAKqjB,EAAO4M,YAAaC,GAE3BhyB,EAAYgyB,EAAUS,KAAKzjB,QAC/BgjB,EAAUS,KAAKzjB,MAAMxT,KAAMuG,EAAMiwB,GAIlCA,EACEnZ,SAAUmZ,EAAUS,KAAK5Z,UACzBlT,KAAMqsB,EAAUS,KAAK9sB,KAAMqsB,EAAUS,KAAKM,UAC1C9b,KAAM+a,EAAUS,KAAKxb,MACrBqB,OAAQ0Z,EAAUS,KAAKna,QAEzBxX,OAAO6vB,GAAGqC,MACTlyB,OAAO8B,OAAQ+uB,KAAM,CACpB5vB,KAAMA,EACNkxB,KAAMjB,EACNta,MAAOsa,EAAUS,KAAK/a,SAIjBsa,CACR,CAEAlxB,OAAOmxB,UAAYnxB,OAAO8B,OAAQqvB,UAAW,CAE5CC,SAAU,CACT,IAAK,CAAE,SAAUjhC,EAAMG,GACtB,IAAImtB,EAAQjf,KAAKyyB,YAAa9gC,EAAMG,GAEpC,OADAitB,UAAWE,EAAMxc,KAAM9Q,EAAM2sB,EAAQ3U,KAAM7X,GAASmtB,GAC7CA,CACR,IAGD2U,QAAS,SAAU/N,EAAOtjB,GACpB7B,EAAYmlB,IAChBtjB,EAAWsjB,EACXA,EAAQ,CAAE,MAEVA,EAAQA,EAAMj2B,MAAOonB,GAOtB,IAJA,IAAIrlB,EACH0kB,EAAQ,EACR5oB,EAASo4B,EAAMp4B,OAER4oB,EAAQ5oB,EAAQ4oB,IACvB1kB,EAAOk0B,EAAOxP,GACdsc,UAAUC,SAAUjhC,GAASghC,UAAUC,SAAUjhC,IAAU,GAC3DghC,UAAUC,SAAUjhC,GAAOic,QAASrL,EAEtC,EAEAwwB,WAAY,CA3Wb,SAASc,iBAAkBpxB,EAAMojB,EAAOsN,GACvC,IAAIxhC,EAAMG,EAAOkuB,EAAQjpB,EAAO+8B,EAASC,EAAWC,EAAgBnV,EACnEoV,EAAQ,UAAWpO,GAAS,WAAYA,EACxC8N,EAAO3zB,KACPqoB,EAAO,CAAC,EACRzJ,EAAQnc,EAAKmc,MACbsT,EAASzvB,EAAK3N,UAAY6pB,mBAAoBlc,GAC9CyxB,EAAWjX,EAASprB,IAAK4Q,EAAM,UA6BhC,IAAM9Q,KA1BAwhC,EAAK/a,QAEa,OADvBrhB,EAAQyK,OAAOsc,YAAarb,EAAM,OACvB0xB,WACVp9B,EAAMo9B,SAAW,EACjBL,EAAU/8B,EAAM0hB,MAAMH,KACtBvhB,EAAM0hB,MAAMH,KAAO,WACZvhB,EAAMo9B,UACXL,GAEF,GAED/8B,EAAMo9B,WAENR,EAAK3a,QAAQ,WAGZ2a,EAAK3a,QAAQ,WACZjiB,EAAMo9B,WACA3yB,OAAO4W,MAAO3V,EAAM,MAAOhV,QAChCsJ,EAAM0hB,MAAMH,MAEd,GACD,KAIauN,EAEb,GADA/zB,EAAQ+zB,EAAOl0B,GACVogC,GAAS1hC,KAAMyB,GAAU,CAG7B,UAFO+zB,EAAOl0B,GACdquB,EAASA,GAAoB,WAAVluB,EACdA,KAAYogC,EAAS,OAAS,QAAW,CAI7C,GAAe,SAAVpgC,IAAoBoiC,QAAiCz/B,IAArBy/B,EAAUviC,GAK9C,SAJAugC,GAAS,CAMX,CACA7J,EAAM12B,GAASuiC,GAAYA,EAAUviC,IAAU6P,OAAOod,MAAOnc,EAAM9Q,EACpE,CAKD,IADAoiC,GAAavyB,OAAO8C,cAAeuhB,MAChBrkB,OAAO8C,cAAe+jB,GA8DzC,IAAM12B,KAzDDsiC,GAA2B,IAAlBxxB,EAAK3N,WAMlBq+B,EAAKiB,SAAW,CAAExV,EAAMwV,SAAUxV,EAAMyV,UAAWzV,EAAM0V,WAIlC,OADvBN,EAAiBE,GAAYA,EAASrV,WAErCmV,EAAiB/W,EAASprB,IAAK4Q,EAAM,YAGrB,UADjBoc,EAAUrd,OAAOsd,IAAKrc,EAAM,cAEtBuxB,EACJnV,EAAUmV,GAIVpU,SAAU,CAAEnd,IAAQ,GACpBuxB,EAAiBvxB,EAAKmc,MAAMC,SAAWmV,EACvCnV,EAAUrd,OAAOsd,IAAKrc,EAAM,WAC5Bmd,SAAU,CAAEnd,OAKG,WAAZoc,GAAoC,iBAAZA,GAAgD,MAAlBmV,IACrB,SAAhCxyB,OAAOsd,IAAKrc,EAAM,WAGhBsxB,IACLJ,EAAKttB,MAAM,WACVuY,EAAMC,QAAUmV,CACjB,IACuB,MAAlBA,IACJnV,EAAUD,EAAMC,QAChBmV,EAA6B,SAAZnV,EAAqB,GAAKA,IAG7CD,EAAMC,QAAU,iBAKdsU,EAAKiB,WACTxV,EAAMwV,SAAW,SACjBT,EAAK3a,QAAQ,WACZ4F,EAAMwV,SAAWjB,EAAKiB,SAAU,GAChCxV,EAAMyV,UAAYlB,EAAKiB,SAAU,GACjCxV,EAAM0V,UAAYnB,EAAKiB,SAAU,EAClC,KAIDL,GAAY,EACE1L,EAGP0L,IACAG,EACC,WAAYA,IAChBhC,EAASgC,EAAShC,QAGnBgC,EAAWjX,EAASpB,OAAQpZ,EAAM,SAAU,CAAEoc,QAASmV,IAInDhU,IACJkU,EAAShC,QAAUA,GAIfA,GACJtS,SAAU,CAAEnd,IAAQ,GAKrBkxB,EAAKttB,MAAM,WASV,IAAM1U,KAJAugC,GACLtS,SAAU,CAAEnd,IAEbwa,EAASliB,OAAQ0H,EAAM,UACT4lB,EACb7mB,OAAOod,MAAOnc,EAAM9Q,EAAM02B,EAAM12B,GAElC,KAIDoiC,EAAYtB,YAAaP,EAASgC,EAAUviC,GAAS,EAAGA,EAAMgiC,GACtDhiC,KAAQuiC,IACfA,EAAUviC,GAASoiC,EAAUrkB,MACxBwiB,IACJ6B,EAAU5wB,IAAM4wB,EAAUrkB,MAC1BqkB,EAAUrkB,MAAQ,GAItB,GAmMC6kB,UAAW,SAAUhyB,EAAU0nB,GACzBA,EACJ0I,UAAUI,WAAWnlB,QAASrL,GAE9BowB,UAAUI,WAAWxjC,KAAMgT,EAE7B,IAGDf,OAAOgzB,MAAQ,SAAUA,EAAO3E,EAAQluB,GACvC,IAAI8yB,EAAMD,GAA0B,iBAAVA,EAAqBhzB,OAAO8B,OAAQ,CAAC,EAAGkxB,GAAU,CAC3Ef,SAAU9xB,IAAOA,GAAMkuB,GACtBnvB,EAAY8zB,IAAWA,EACxBtD,SAAUsD,EACV3E,OAAQluB,GAAMkuB,GAAUA,IAAWnvB,EAAYmvB,IAAYA,GAoC5D,OAhCKruB,OAAO6vB,GAAG5O,IACdgS,EAAIvD,SAAW,EAGc,iBAAjBuD,EAAIvD,WACVuD,EAAIvD,YAAY1vB,OAAO6vB,GAAGqD,OAC9BD,EAAIvD,SAAW1vB,OAAO6vB,GAAGqD,OAAQD,EAAIvD,UAGrCuD,EAAIvD,SAAW1vB,OAAO6vB,GAAGqD,OAAO7T,UAMjB,MAAb4T,EAAIrc,QAA+B,IAAdqc,EAAIrc,QAC7Bqc,EAAIrc,MAAQ,MAIbqc,EAAIxJ,IAAMwJ,EAAIhB,SAEdgB,EAAIhB,SAAW,WACT/yB,EAAY+zB,EAAIxJ,MACpBwJ,EAAIxJ,IAAI/uB,KAAM8D,MAGVy0B,EAAIrc,OACR5W,OAAOoc,QAAS5d,KAAMy0B,EAAIrc,MAE5B,EAEOqc,CACR,EAEAjzB,OAAOG,GAAG2B,OAAQ,CACjBqxB,OAAQ,SAAUH,EAAOI,EAAI/E,EAAQttB,GAGpC,OAAOvC,KAAKyM,OAAQkS,oBAAqBG,IAAK,UAAW,GAAIe,OAG3D1c,MAAM0xB,QAAS,CAAE9E,QAAS6E,GAAMJ,EAAO3E,EAAQttB,EAClD,EACAsyB,QAAS,SAAUljC,EAAM6iC,EAAO3E,EAAQttB,GACvC,IAAIkW,EAAQjX,OAAO8C,cAAe3S,GACjCmjC,EAAStzB,OAAOgzB,MAAOA,EAAO3E,EAAQttB,GACtCwyB,YAAc,WAGb,IAAIpB,EAAOhB,UAAW3yB,KAAMwB,OAAO8B,OAAQ,CAAC,EAAG3R,GAAQmjC,IAGlDrc,GAASwE,EAASprB,IAAKmO,KAAM,YACjC2zB,EAAK5V,MAAM,EAEb,EAID,OAFAgX,YAAYC,OAASD,YAEdtc,IAA0B,IAAjBqc,EAAO1c,MACtBpY,KAAKsC,KAAMyyB,aACX/0B,KAAKoY,MAAO0c,EAAO1c,MAAO2c,YAC5B,EACAhX,KAAM,SAAUjd,EAAMmd,EAAYsV,GACjC,IAAI0B,UAAY,SAAUl+B,GACzB,IAAIgnB,EAAOhnB,EAAMgnB,YACVhnB,EAAMgnB,KACbA,EAAMwV,EACP,EAWA,MATqB,iBAATzyB,IACXyyB,EAAUtV,EACVA,EAAand,EACbA,OAAOrM,GAEHwpB,GACJje,KAAKoY,MAAOtX,GAAQ,KAAM,IAGpBd,KAAKsC,MAAM,WACjB,IAAIsb,GAAU,EACbvH,EAAgB,MAARvV,GAAgBA,EAAO,aAC/Bo0B,EAAS1zB,OAAO0zB,OAChBh4B,EAAO+f,EAASprB,IAAKmO,MAEtB,GAAKqW,EACCnZ,EAAMmZ,IAAWnZ,EAAMmZ,GAAQ0H,MACnCkX,UAAW/3B,EAAMmZ,SAGlB,IAAMA,KAASnZ,EACTA,EAAMmZ,IAAWnZ,EAAMmZ,GAAQ0H,MAAQiU,GAAK3hC,KAAMgmB,IACtD4e,UAAW/3B,EAAMmZ,IAKpB,IAAMA,EAAQ6e,EAAOznC,OAAQ4oB,KACvB6e,EAAQ7e,GAAQ5T,OAASzC,MACnB,MAARc,GAAgBo0B,EAAQ7e,GAAQ+B,QAAUtX,IAE5Co0B,EAAQ7e,GAAQsd,KAAK5V,KAAMwV,GAC3B3V,GAAU,EACVsX,EAAO7xB,OAAQgT,EAAO,KAOnBuH,GAAY2V,GAChB/xB,OAAOoc,QAAS5d,KAAMc,EAExB,GACD,EACAk0B,OAAQ,SAAUl0B,GAIjB,OAHc,IAATA,IACJA,EAAOA,GAAQ,MAETd,KAAKsC,MAAM,WACjB,IAAI+T,EACHnZ,EAAO+f,EAASprB,IAAKmO,MACrBoY,EAAQlb,EAAM4D,EAAO,SACrB/J,EAAQmG,EAAM4D,EAAO,cACrBo0B,EAAS1zB,OAAO0zB,OAChBznC,EAAS2qB,EAAQA,EAAM3qB,OAAS,EAajC,IAVAyP,EAAK83B,QAAS,EAGdxzB,OAAO4W,MAAOpY,KAAMc,EAAM,IAErB/J,GAASA,EAAMgnB,MACnBhnB,EAAMgnB,KAAK7hB,KAAM8D,MAAM,GAIlBqW,EAAQ6e,EAAOznC,OAAQ4oB,KACvB6e,EAAQ7e,GAAQ5T,OAASzC,MAAQk1B,EAAQ7e,GAAQ+B,QAAUtX,IAC/Do0B,EAAQ7e,GAAQsd,KAAK5V,MAAM,GAC3BmX,EAAO7xB,OAAQgT,EAAO,IAKxB,IAAMA,EAAQ,EAAGA,EAAQ5oB,EAAQ4oB,IAC3B+B,EAAO/B,IAAW+B,EAAO/B,GAAQ2e,QACrC5c,EAAO/B,GAAQ2e,OAAO94B,KAAM8D,aAKvB9C,EAAK83B,MACb,GACD,IAGDxzB,OAAOc,KAAM,CAAE,SAAU,OAAQ,SAAU,SAAU2C,EAAIhK,GACxD,IAAIk6B,EAAQ3zB,OAAOG,GAAI1G,GACvBuG,OAAOG,GAAI1G,GAAS,SAAUu5B,EAAO3E,EAAQttB,GAC5C,OAAgB,MAATiyB,GAAkC,kBAAVA,EAC9BW,EAAM7mC,MAAO0R,KAAMpP,WACnBoP,KAAK60B,QAAStC,MAAOt3B,GAAM,GAAQu5B,EAAO3E,EAAQttB,EACpD,CACD,IAGAf,OAAOc,KAAM,CACZ8yB,UAAW7C,MAAO,QAClB8C,QAAS9C,MAAO,QAChB+C,YAAa/C,MAAO,UACpBgD,OAAQ,CAAExF,QAAS,QACnByF,QAAS,CAAEzF,QAAS,QACpB0F,WAAY,CAAE1F,QAAS,YACrB,SAAU90B,EAAM4qB,GAClBrkB,OAAOG,GAAI1G,GAAS,SAAUu5B,EAAO3E,EAAQttB,GAC5C,OAAOvC,KAAK60B,QAAShP,EAAO2O,EAAO3E,EAAQttB,EAC5C,CACD,IAEAf,OAAO0zB,OAAS,GAChB1zB,OAAO6vB,GAAGgB,KAAO,WAChB,IAAIqB,EACHnmC,EAAI,EACJ2nC,EAAS1zB,OAAO0zB,OAIjB,IAFArD,GAAQ3rB,KAAKggB,MAEL34B,EAAI2nC,EAAOznC,OAAQF,KAC1BmmC,EAAQwB,EAAQ3nC,OAGC2nC,EAAQ3nC,KAAQmmC,GAChCwB,EAAO7xB,OAAQ9V,IAAK,GAIhB2nC,EAAOznC,QACZ+T,OAAO6vB,GAAGtT,OAEX8T,QAAQp9B,CACT,EAEA+M,OAAO6vB,GAAGqC,MAAQ,SAAUA,GAC3BlyB,OAAO0zB,OAAO3lC,KAAMmkC,GACpBlyB,OAAO6vB,GAAG3hB,OACX,EAEAlO,OAAO6vB,GAAGe,SAAW,GACrB5wB,OAAO6vB,GAAG3hB,MAAQ,WACZoiB,KAILA,IAAa,EACbG,WACD,EAEAzwB,OAAO6vB,GAAGtT,KAAO,WAChB+T,GAAa,IACd,EAEAtwB,OAAO6vB,GAAGqD,OAAS,CAClBgB,KAAM,IACNC,KAAM,IAGN9U,SAAU,KAMXrf,OAAOG,GAAGi0B,MAAQ,SAAUC,EAAM/0B,GAIjC,OAHA+0B,EAAOr0B,OAAO6vB,IAAK7vB,OAAO6vB,GAAGqD,OAAQmB,IAAiBA,EACtD/0B,EAAOA,GAAQ,KAERd,KAAKoY,MAAOtX,GAAM,SAAUoI,EAAMnS,GACxC,IAAI++B,EAAUtiC,EAAOgnB,WAAYtR,EAAM2sB,GACvC9+B,EAAMgnB,KAAO,WACZvqB,EAAOuiC,aAAcD,EACtB,CACD,GACD,EAGA,WACC,IAAIjpB,EAAQlZ,EAASuC,cAAe,SAEnCu+B,EADS9gC,EAASuC,cAAe,UACpB6I,YAAapL,EAASuC,cAAe,WAEnD2W,EAAM/L,KAAO,WAIbL,EAAQu1B,QAA0B,KAAhBnpB,EAAM/a,MAIxB2O,EAAQw1B,YAAcxB,EAAI5jB,UAI1BhE,EAAQlZ,EAASuC,cAAe,UAC1BpE,MAAQ,IACd+a,EAAM/L,KAAO,QACbL,EAAQy1B,WAA6B,MAAhBrpB,EAAM/a,KAC1B,CArBF,GAwBA,IAAIqkC,GACHlrB,GAAazJ,OAAOqM,KAAK5C,WAE1BzJ,OAAOG,GAAG2B,OAAQ,CACjB3F,KAAM,SAAU1C,EAAMnJ,GACrB,OAAO+pB,OAAQ7b,KAAMwB,OAAO7D,KAAM1C,EAAMnJ,EAAOlB,UAAUnD,OAAS,EACnE,EAEA2oC,WAAY,SAAUn7B,GACrB,OAAO+E,KAAKsC,MAAM,WACjBd,OAAO40B,WAAYp2B,KAAM/E,EAC1B,GACD,IAGDuG,OAAO8B,OAAQ,CACd3F,KAAM,SAAU8E,EAAMxH,EAAMnJ,GAC3B,IAAIqQ,EAAKpL,EACRs/B,EAAQ5zB,EAAK3N,SAGd,GAAe,IAAVuhC,GAAyB,IAAVA,GAAyB,IAAVA,EAKnC,YAAkC,IAAtB5zB,EAAKxO,aACTuN,OAAO7P,KAAM8Q,EAAMxH,EAAMnJ,IAKlB,IAAVukC,GAAgB70B,OAAOmT,SAAUlS,KACrC1L,EAAQyK,OAAO80B,UAAWr7B,EAAKvL,iBAC5B8R,OAAOqM,KAAKje,MAAM2mC,KAAKlmC,KAAM4K,GAASk7B,QAAW1hC,SAGtCA,IAAV3C,EACW,OAAVA,OACJ0P,OAAO40B,WAAY3zB,EAAMxH,GAIrBlE,GAAS,QAASA,QACuBtC,KAA3C0N,EAAMpL,EAAM9F,IAAKwR,EAAM3Q,EAAOmJ,IACzBkH,GAGRM,EAAK5F,aAAc5B,EAAMnJ,EAAQ,IAC1BA,GAGHiF,GAAS,QAASA,GAA+C,QAApCoL,EAAMpL,EAAMlF,IAAK4Q,EAAMxH,IACjDkH,EAMM,OAHdA,EAAMX,OAAOmL,KAAKhP,KAAM8E,EAAMxH,SAGTxG,EAAY0N,EAClC,EAEAm0B,UAAW,CACVx1B,KAAM,CACL7P,IAAK,SAAUwR,EAAM3Q,GACpB,IAAM2O,EAAQy1B,YAAwB,UAAVpkC,GAC3B4K,SAAU+F,EAAM,SAAY,CAC5B,IAAIrB,EAAMqB,EAAK3Q,MAKf,OAJA2Q,EAAK5F,aAAc,OAAQ/K,GACtBsP,IACJqB,EAAK3Q,MAAQsP,GAEPtP,CACR,CACD,IAIFskC,WAAY,SAAU3zB,EAAM3Q,GAC3B,IAAImJ,EACH1N,EAAI,EAIJipC,EAAY1kC,GAASA,EAAMlC,MAAOonB,GAEnC,GAAKwf,GAA+B,IAAlB/zB,EAAK3N,SACtB,KAAUmG,EAAOu7B,EAAWjpC,MAC3BkV,EAAKrH,gBAAiBH,EAGzB,IAIDk7B,GAAW,CACVllC,IAAK,SAAUwR,EAAM3Q,EAAOmJ,GAQ3B,OAPe,IAAVnJ,EAGJ0P,OAAO40B,WAAY3zB,EAAMxH,GAEzBwH,EAAK5F,aAAc5B,EAAMA,GAEnBA,CACR,GAGDuG,OAAOc,KAAMd,OAAOqM,KAAKje,MAAM2mC,KAAKlY,OAAOzuB,MAAO,SAAU,SAAUqV,EAAIhK,GACzE,IAAIw7B,EAASxrB,GAAYhQ,IAAUuG,OAAOmL,KAAKhP,KAE/CsN,GAAYhQ,GAAS,SAAUwH,EAAMxH,EAAMoK,GAC1C,IAAIlD,EAAK0hB,EACR6S,EAAgBz7B,EAAKvL,cAYtB,OAVM2V,IAGLwe,EAAS5Y,GAAYyrB,GACrBzrB,GAAYyrB,GAAkBv0B,EAC9BA,EAAqC,MAA/Bs0B,EAAQh0B,EAAMxH,EAAMoK,GACzBqxB,EACA,KACDzrB,GAAYyrB,GAAkB7S,GAExB1hB,CACR,CACD,IAKA,IAAIw0B,GAAa,sCAChBC,GAAa,gBAyIb,SAASC,iBAAkB/kC,GAE1B,OADaA,EAAMlC,MAAOonB,IAAmB,IAC/B7M,KAAM,IACrB,CAGD,SAAS2sB,SAAUr0B,GAClB,OAAOA,EAAKxO,cAAgBwO,EAAKxO,aAAc,UAAa,EAC7D,CAEA,SAAS8iC,eAAgBjlC,GACxB,OAAKzE,MAAMC,QAASwE,GACZA,EAEc,iBAAVA,GACJA,EAAMlC,MAAOonB,IAEd,EACR,CAzJAxV,OAAOG,GAAG2B,OAAQ,CACjB3R,KAAM,SAAUsJ,EAAMnJ,GACrB,OAAO+pB,OAAQ7b,KAAMwB,OAAO7P,KAAMsJ,EAAMnJ,EAAOlB,UAAUnD,OAAS,EACnE,EAEAupC,WAAY,SAAU/7B,GACrB,OAAO+E,KAAKsC,MAAM,kBACVtC,KAAMwB,OAAOy1B,QAASh8B,IAAUA,EACxC,GACD,IAGDuG,OAAO8B,OAAQ,CACd3R,KAAM,SAAU8Q,EAAMxH,EAAMnJ,GAC3B,IAAIqQ,EAAKpL,EACRs/B,EAAQ5zB,EAAK3N,SAGd,GAAe,IAAVuhC,GAAyB,IAAVA,GAAyB,IAAVA,EAWnC,OAPe,IAAVA,GAAgB70B,OAAOmT,SAAUlS,KAGrCxH,EAAOuG,OAAOy1B,QAASh8B,IAAUA,EACjClE,EAAQyK,OAAOsvB,UAAW71B,SAGZxG,IAAV3C,EACCiF,GAAS,QAASA,QACuBtC,KAA3C0N,EAAMpL,EAAM9F,IAAKwR,EAAM3Q,EAAOmJ,IACzBkH,EAGCM,EAAMxH,GAASnJ,EAGpBiF,GAAS,QAASA,GAA+C,QAApCoL,EAAMpL,EAAMlF,IAAK4Q,EAAMxH,IACjDkH,EAGDM,EAAMxH,EACd,EAEA61B,UAAW,CACVngB,SAAU,CACT9e,IAAK,SAAU4Q,GAOd,IAAIy0B,EAAW11B,OAAOmL,KAAKhP,KAAM8E,EAAM,YAEvC,OAAKy0B,EACGzJ,SAAUyJ,EAAU,IAI3BP,GAAWtmC,KAAMoS,EAAK/F,WACtBk6B,GAAWvmC,KAAMoS,EAAK/F,WACtB+F,EAAKiO,KAEE,GAGA,CACT,IAIFumB,QAAS,CACR,IAAO,UACP,MAAS,eAYLx2B,EAAQw1B,cACbz0B,OAAOsvB,UAAUjgB,SAAW,CAC3Bhf,IAAK,SAAU4Q,GAId,IAAIrI,EAASqI,EAAK7H,WAIlB,OAHKR,GAAUA,EAAOQ,YACrBR,EAAOQ,WAAWkW,cAEZ,IACR,EACA7f,IAAK,SAAUwR,GAId,IAAIrI,EAASqI,EAAK7H,WACbR,IACJA,EAAO0W,cAEF1W,EAAOQ,YACXR,EAAOQ,WAAWkW,cAGrB,IAIFtP,OAAOc,KAAM,CACZ,WACA,WACA,YACA,cACA,cACA,UACA,UACA,SACA,cACA,oBACE,WACFd,OAAOy1B,QAASj3B,KAAKtQ,eAAkBsQ,IACxC,IA2BAwB,OAAOG,GAAG2B,OAAQ,CACjB6zB,SAAU,SAAUrlC,GACnB,IAAIslC,EAAS30B,EAAM0I,EAAKksB,EAAUC,EAAOp0B,EAAGq0B,EAC3ChqC,EAAI,EAEL,GAAKmT,EAAY5O,GAChB,OAAOkO,KAAKsC,MAAM,SAAUY,GAC3B1B,OAAQxB,MAAOm3B,SAAUrlC,EAAMoK,KAAM8D,KAAMkD,EAAG4zB,SAAU92B,OACzD,IAKD,IAFAo3B,EAAUL,eAAgBjlC,IAEbrE,OACZ,KAAUgV,EAAOzC,KAAMzS,MAItB,GAHA8pC,EAAWP,SAAUr0B,GACrB0I,EAAwB,IAAlB1I,EAAK3N,UAAoB,IAAM+hC,iBAAkBQ,GAAa,IAEzD,CAEV,IADAn0B,EAAI,EACMo0B,EAAQF,EAASl0B,MACrBiI,EAAInb,QAAS,IAAMsnC,EAAQ,KAAQ,IACvCnsB,GAAOmsB,EAAQ,KAMZD,KADLE,EAAaV,iBAAkB1rB,KAE9B1I,EAAK5F,aAAc,QAAS06B,EAE9B,CAIF,OAAOv3B,IACR,EAEAw3B,YAAa,SAAU1lC,GACtB,IAAIslC,EAAS30B,EAAM0I,EAAKksB,EAAUC,EAAOp0B,EAAGq0B,EAC3ChqC,EAAI,EAEL,GAAKmT,EAAY5O,GAChB,OAAOkO,KAAKsC,MAAM,SAAUY,GAC3B1B,OAAQxB,MAAOw3B,YAAa1lC,EAAMoK,KAAM8D,KAAMkD,EAAG4zB,SAAU92B,OAC5D,IAGD,IAAMpP,UAAUnD,OACf,OAAOuS,KAAKrC,KAAM,QAAS,IAK5B,IAFAy5B,EAAUL,eAAgBjlC,IAEbrE,OACZ,KAAUgV,EAAOzC,KAAMzS,MAMtB,GALA8pC,EAAWP,SAAUr0B,GAGrB0I,EAAwB,IAAlB1I,EAAK3N,UAAoB,IAAM+hC,iBAAkBQ,GAAa,IAEzD,CAEV,IADAn0B,EAAI,EACMo0B,EAAQF,EAASl0B,MAG1B,KAAQiI,EAAInb,QAAS,IAAMsnC,EAAQ,MAAS,GAC3CnsB,EAAMA,EAAIrb,QAAS,IAAMwnC,EAAQ,IAAK,KAMnCD,KADLE,EAAaV,iBAAkB1rB,KAE9B1I,EAAK5F,aAAc,QAAS06B,EAE9B,CAIF,OAAOv3B,IACR,EAEAy3B,YAAa,SAAU3lC,EAAO4lC,GAC7B,IAAI52B,SAAchP,EACjB6lC,EAAwB,WAAT72B,GAAqBzT,MAAMC,QAASwE,GAEpD,MAAyB,kBAAb4lC,GAA0BC,EAC9BD,EAAW13B,KAAKm3B,SAAUrlC,GAAUkO,KAAKw3B,YAAa1lC,GAGzD4O,EAAY5O,GACTkO,KAAKsC,MAAM,SAAU/U,GAC3BiU,OAAQxB,MAAOy3B,YACd3lC,EAAMoK,KAAM8D,KAAMzS,EAAGupC,SAAU92B,MAAQ03B,GACvCA,EAEF,IAGM13B,KAAKsC,MAAM,WACjB,IAAI+J,EAAW9e,EAAGioB,EAAMoiB,EAExB,GAAKD,EAOJ,IAJApqC,EAAI,EACJioB,EAAOhU,OAAQxB,MACf43B,EAAab,eAAgBjlC,GAEnBua,EAAYurB,EAAYrqC,MAG5BioB,EAAKqiB,SAAUxrB,GACnBmJ,EAAKgiB,YAAanrB,GAElBmJ,EAAK2hB,SAAU9qB,aAKI5X,IAAV3C,GAAgC,YAATgP,KAClCuL,EAAYyqB,SAAU92B,QAIrBid,EAAShsB,IAAK+O,KAAM,gBAAiBqM,GAOjCrM,KAAKnD,cACTmD,KAAKnD,aAAc,QAClBwP,IAAuB,IAAVva,EACZ,GACAmrB,EAASprB,IAAKmO,KAAM,kBAAqB,IAI9C,GACD,EAEA63B,SAAU,SAAUp2B,GACnB,IAAI4K,EAAW5J,EACdlV,EAAI,EAGL,IADA8e,EAAY,IAAM5K,EAAW,IACnBgB,EAAOzC,KAAMzS,MACtB,GAAuB,IAAlBkV,EAAK3N,WACP,IAAM+hC,iBAAkBC,SAAUr0B,IAAW,KAAMzS,QAASqc,IAAe,EAC7E,OAAO,EAIT,OAAO,CACR,IAMD,IAAIyrB,GAAU,MAEdt2B,OAAOG,GAAG2B,OAAQ,CACjBlC,IAAK,SAAUtP,GACd,IAAIiF,EAAOoL,EAAKmnB,EACf7mB,EAAOzC,KAAM,GAEd,OAAMpP,UAAUnD,QA0BhB67B,EAAkB5oB,EAAY5O,GAEvBkO,KAAKsC,MAAM,SAAU/U,GAC3B,IAAI6T,EAEmB,IAAlBpB,KAAKlL,WAWE,OANXsM,EADIkoB,EACEx3B,EAAMoK,KAAM8D,KAAMzS,EAAGiU,OAAQxB,MAAOoB,OAEpCtP,GAKNsP,EAAM,GAEoB,iBAARA,EAClBA,GAAO,GAEI/T,MAAMC,QAAS8T,KAC1BA,EAAMI,OAAOgB,IAAKpB,GAAK,SAAUtP,GAChC,OAAgB,MAATA,EAAgB,GAAKA,EAAQ,EACrC,MAGDiF,EAAQyK,OAAOu2B,SAAU/3B,KAAKc,OAAUU,OAAOu2B,SAAU/3B,KAAKtD,SAAShN,iBAGrD,QAASqH,QAA+CtC,IAApCsC,EAAM9F,IAAK+O,KAAMoB,EAAK,WAC3DpB,KAAKlO,MAAQsP,GAEf,KA3DMqB,GACJ1L,EAAQyK,OAAOu2B,SAAUt1B,EAAK3B,OAC7BU,OAAOu2B,SAAUt1B,EAAK/F,SAAShN,iBAG/B,QAASqH,QACgCtC,KAAvC0N,EAAMpL,EAAMlF,IAAK4Q,EAAM,UAElBN,EAMY,iBAHpBA,EAAMM,EAAK3Q,OAIHqQ,EAAIrS,QAASgoC,GAAS,IAIhB,MAAP31B,EAAc,GAAKA,OAG3B,CAsCF,IAGDX,OAAO8B,OAAQ,CACdy0B,SAAU,CACTxX,OAAQ,CACP1uB,IAAK,SAAU4Q,GAEd,IAAIrB,EAAMI,OAAOmL,KAAKhP,KAAM8E,EAAM,SAClC,OAAc,MAAPrB,EACNA,EAMAy1B,iBAAkBr1B,OAAOnP,KAAMoQ,GACjC,GAED+C,OAAQ,CACP3T,IAAK,SAAU4Q,GACd,IAAI3Q,EAAOyuB,EAAQhzB,EAClBgW,EAAUd,EAAKc,QACf8S,EAAQ5T,EAAKqO,cACbwR,EAAoB,eAAd7f,EAAK3B,KACXgf,EAASwC,EAAM,KAAO,GACtBwM,EAAMxM,EAAMjM,EAAQ,EAAI9S,EAAQ9V,OAUjC,IAPCF,EADI8oB,EAAQ,EACRyY,EAGAxM,EAAMjM,EAAQ,EAIX9oB,EAAIuhC,EAAKvhC,IAKhB,KAJAgzB,EAAShd,EAAShW,IAIJsjB,UAAYtjB,IAAM8oB,KAG7BkK,EAAOvX,YACLuX,EAAO3lB,WAAWoO,WACnBtM,SAAU6jB,EAAO3lB,WAAY,aAAiB,CAMjD,GAHA9I,EAAQ0P,OAAQ+e,GAASnf,MAGpBkhB,EACJ,OAAOxwB,EAIRguB,EAAOvwB,KAAMuC,EACd,CAGD,OAAOguB,CACR,EAEA7uB,IAAK,SAAUwR,EAAM3Q,GAMpB,IALA,IAAIkmC,EAAWzX,EACdhd,EAAUd,EAAKc,QACfuc,EAASte,OAAOgD,UAAW1S,GAC3BvE,EAAIgW,EAAQ9V,OAELF,OACPgzB,EAAShd,EAAShW,IAINsjB,SACXrP,OAAOkD,QAASlD,OAAOu2B,SAASxX,OAAO1uB,IAAK0uB,GAAUT,IAAY,KAElEkY,GAAY,GAUd,OAHMA,IACLv1B,EAAKqO,eAAiB,GAEhBgP,CACR,MAMHte,OAAOc,KAAM,CAAE,QAAS,aAAc,WACrCd,OAAOu2B,SAAU/3B,MAAS,CACzB/O,IAAK,SAAUwR,EAAM3Q,GACpB,GAAKzE,MAAMC,QAASwE,GACnB,OAAS2Q,EAAKmO,QAAUpP,OAAOkD,QAASlD,OAAQiB,GAAOrB,MAAOtP,IAAW,CAE3E,GAEK2O,EAAQu1B,UACbx0B,OAAOu2B,SAAU/3B,MAAOnO,IAAM,SAAU4Q,GACvC,OAAwC,OAAjCA,EAAKxO,aAAc,SAAqB,KAAOwO,EAAK3Q,KAC5D,EAEF,IAQA2O,EAAQw3B,QAAU,cAAezkC,EAGjC,IAAI0kC,GAAc,kCACjBC,wBAA0B,SAAUhvB,GACnCA,EAAE4Z,iBACH,EAEDvhB,OAAO8B,OAAQ9B,OAAOghB,MAAO,CAE5BU,QAAS,SAAUV,EAAOtlB,EAAMuF,EAAM21B,GAErC,IAAI7qC,EAAG4d,EAAKyB,EAAKyrB,EAAYC,EAAQzU,EAAQ/J,EAASye,EACrDC,EAAY,CAAE/1B,GAAQ9O,GACtBmN,EAAOR,EAAOpE,KAAMsmB,EAAO,QAAWA,EAAM1hB,KAAO0hB,EACnDkB,EAAapjB,EAAOpE,KAAMsmB,EAAO,aAAgBA,EAAM1W,UAAU9G,MAAO,KAAQ,GAKjF,GAHAmG,EAAMotB,EAAc3rB,EAAMnK,EAAOA,GAAQ9O,EAGlB,IAAlB8O,EAAK3N,UAAoC,IAAlB2N,EAAK3N,WAK5BojC,GAAY7nC,KAAMyQ,EAAOU,OAAOghB,MAAMsB,aAItChjB,EAAK9Q,QAAS,MAAS,IAG3B0zB,EAAa5iB,EAAKkE,MAAO,KACzBlE,EAAO4iB,EAAWhZ,QAClBgZ,EAAWtgB,QAEZk1B,EAASx3B,EAAK9Q,QAAS,KAAQ,GAAK,KAAO8Q,GAG3C0hB,EAAQA,EAAOhhB,OAAOqC,SACrB2e,EACA,IAAIhhB,OAAO2hB,MAAOriB,EAAuB,iBAAV0hB,GAAsBA,IAGhDK,UAAYuV,EAAe,EAAI,EACrC5V,EAAM1W,UAAY4X,EAAWvZ,KAAM,KACnCqY,EAAMuC,WAAavC,EAAM1W,UACxB,IAAI1b,OAAQ,UAAYszB,EAAWvZ,KAAM,iBAAoB,WAC7D,KAGDqY,EAAMxT,YAASva,EACT+tB,EAAM9e,SACX8e,EAAM9e,OAASjB,GAIhBvF,EAAe,MAARA,EACN,CAAEslB,GACFhhB,OAAOgD,UAAWtH,EAAM,CAAEslB,IAG3B1I,EAAUtY,OAAOghB,MAAM1I,QAAShZ,IAAU,CAAC,EACrCs3B,IAAgBte,EAAQoJ,UAAmD,IAAxCpJ,EAAQoJ,QAAQ50B,MAAOmU,EAAMvF,IAAtE,CAMA,IAAMk7B,IAAiBte,EAAQ2L,WAAa7kB,EAAU6B,GAAS,CAM9D,IAJA41B,EAAave,EAAQgJ,cAAgBhiB,EAC/Bo3B,GAAY7nC,KAAMgoC,EAAav3B,KACpCqK,EAAMA,EAAIvQ,YAEHuQ,EAAKA,EAAMA,EAAIvQ,WACtB49B,EAAUjpC,KAAM4b,GAChByB,EAAMzB,EAIFyB,KAAUnK,EAAKrM,eAAiBzC,IACpC6kC,EAAUjpC,KAAMqd,EAAIX,aAAeW,EAAI6rB,cAAgBjlC,EAEzD,CAIA,IADAjG,EAAI,GACM4d,EAAMqtB,EAAWjrC,QAAYi1B,EAAMoC,wBAC5C2T,EAAcptB,EACdqX,EAAM1hB,KAAOvT,EAAI,EAChB8qC,EACAve,EAAQkK,UAAYljB,GAGrB+iB,GAAW5G,EAASprB,IAAKsZ,EAAK,WAAcvd,OAAOO,OAAQ,OAAUq0B,EAAM1hB,OAC1Emc,EAASprB,IAAKsZ,EAAK,YAEnB0Y,EAAOv1B,MAAO6c,EAAKjO,IAIpB2mB,EAASyU,GAAUntB,EAAKmtB,KACTzU,EAAOv1B,OAASouB,WAAYvR,KAC1CqX,EAAMxT,OAAS6U,EAAOv1B,MAAO6c,EAAKjO,IACZ,IAAjBslB,EAAMxT,QACVwT,EAAMS,kBA8CT,OA1CAT,EAAM1hB,KAAOA,EAGPs3B,GAAiB5V,EAAMsD,sBAEpBhM,EAAQ+G,WACqC,IAApD/G,EAAQ+G,SAASvyB,MAAOkqC,EAAUnpC,MAAO6N,KACzCwf,WAAYja,IAIP61B,GAAU53B,EAAY+B,EAAM3B,MAAaF,EAAU6B,MAGvDmK,EAAMnK,EAAM61B,MAGX71B,EAAM61B,GAAW,MAIlB92B,OAAOghB,MAAMsB,UAAYhjB,EAEpB0hB,EAAMoC,wBACV2T,EAAYpsB,iBAAkBrL,EAAMq3B,yBAGrC11B,EAAM3B,KAED0hB,EAAMoC,wBACV2T,EAAYhd,oBAAqBza,EAAMq3B,yBAGxC32B,OAAOghB,MAAMsB,eAAYrvB,EAEpBmY,IACJnK,EAAM61B,GAAW1rB,IAMd4V,EAAMxT,MAvFb,CAwFD,EAIA0pB,SAAU,SAAU53B,EAAM2B,EAAM+f,GAC/B,IAAIrZ,EAAI3H,OAAO8B,OACd,IAAI9B,OAAO2hB,MACXX,EACA,CACC1hB,KAAMA,EACNqlB,aAAa,IAIf3kB,OAAOghB,MAAMU,QAAS/Z,EAAG,KAAM1G,EAChC,IAIDjB,OAAOG,GAAG2B,OAAQ,CAEjB4f,QAAS,SAAUpiB,EAAM5D,GACxB,OAAO8C,KAAKsC,MAAM,WACjBd,OAAOghB,MAAMU,QAASpiB,EAAM5D,EAAM8C,KACnC,GACD,EACA24B,eAAgB,SAAU73B,EAAM5D,GAC/B,IAAIuF,EAAOzC,KAAM,GACjB,GAAKyC,EACJ,OAAOjB,OAAOghB,MAAMU,QAASpiB,EAAM5D,EAAMuF,GAAM,EAEjD,IAYKhC,EAAQw3B,SACbz2B,OAAOc,KAAM,CAAEylB,MAAO,UAAWC,KAAM,aAAc,SAAUK,EAAM5D,GAGpE,IAAIzZ,QAAU,SAAUwX,GACvBhhB,OAAOghB,MAAMkW,SAAUjU,EAAKjC,EAAM9e,OAAQlC,OAAOghB,MAAMiC,IAAKjC,GAC7D,EAEAhhB,OAAOghB,MAAM1I,QAAS2K,GAAQ,CAC7BP,MAAO,WAIN,IAAI3oB,EAAMyE,KAAK5J,eAAiB4J,KAAKrM,UAAYqM,KAChD44B,EAAW3b,EAASpB,OAAQtgB,EAAKkpB,GAE5BmU,GACLr9B,EAAI4Q,iBAAkBkc,EAAMrd,SAAS,GAEtCiS,EAASpB,OAAQtgB,EAAKkpB,GAAOmU,GAAY,GAAM,EAChD,EACAvU,SAAU,WACT,IAAI9oB,EAAMyE,KAAK5J,eAAiB4J,KAAKrM,UAAYqM,KAChD44B,EAAW3b,EAASpB,OAAQtgB,EAAKkpB,GAAQ,EAEpCmU,EAKL3b,EAASpB,OAAQtgB,EAAKkpB,EAAKmU,IAJ3Br9B,EAAIggB,oBAAqB8M,EAAMrd,SAAS,GACxCiS,EAASliB,OAAQQ,EAAKkpB,GAKxB,EAEF,IAED,IAAIlU,GAAW/c,EAAO+c,SAElBvP,GAAQ,CAAE+D,KAAMmB,KAAKggB,OAErB2S,GAAS,KAKbr3B,OAAOs3B,SAAW,SAAU57B,GAC3B,IAAIzK,EAAKsmC,EACT,IAAM77B,GAAwB,iBAATA,EACpB,OAAO,KAKR,IACCzK,GAAM,IAAMe,EAAOmC,WAAcgG,gBAAiBuB,EAAM,WACzD,CAAE,MAAQiM,GAAK,CAYf,OAVA4vB,EAAkBtmC,GAAOA,EAAIkE,qBAAsB,eAAiB,GAC9DlE,IAAOsmC,GACZv3B,OAAOyC,MAAO,iBACb80B,EACCv3B,OAAOgB,IAAKu2B,EAAgB98B,YAAY,SAAU4O,GACjD,OAAOA,EAAGlO,WACX,IAAIwN,KAAM,MACVjN,IAGIzK,CACR,EAGA,IACCumC,GAAW,QACXC,GAAQ,SACRC,GAAkB,wCAClBC,GAAe,qCAEhB,SAASC,YAAa1I,EAAQt9B,EAAKimC,EAAa9iB,GAC/C,IAAItb,EAEJ,GAAK5N,MAAMC,QAAS8F,GAGnBoO,OAAOc,KAAMlP,GAAK,SAAU7F,EAAG2pB,GACzBmiB,GAAeL,GAAS3oC,KAAMqgC,GAGlCna,EAAKma,EAAQxZ,GAKbkiB,YACC1I,EAAS,KAAqB,iBAANxZ,GAAuB,MAALA,EAAY3pB,EAAI,IAAO,IACjE2pB,EACAmiB,EACA9iB,EAGH,SAEM,GAAM8iB,GAAiC,WAAlB93B,OAAQnO,GAUnCmjB,EAAKma,EAAQt9B,QAPb,IAAM6H,KAAQ7H,EACbgmC,YAAa1I,EAAS,IAAMz1B,EAAO,IAAK7H,EAAK6H,GAAQo+B,EAAa9iB,EAQrE,CAIA/U,OAAO83B,MAAQ,SAAU1yB,EAAGyyB,GAC3B,IAAI3I,EACH6I,EAAI,GACJhjB,IAAM,SAAU/L,EAAKgvB,GAGpB,IAAI1nC,EAAQ4O,EAAY84B,GACvBA,IACAA,EAEDD,EAAGA,EAAE9rC,QAAWgsC,mBAAoBjvB,GAAQ,IAC3CivB,mBAA6B,MAAT3nC,EAAgB,GAAKA,EAC3C,EAED,GAAU,MAAL8U,EACJ,MAAO,GAIR,GAAKvZ,MAAMC,QAASsZ,IAASA,EAAE9E,SAAWN,OAAOoC,cAAegD,GAG/DpF,OAAOc,KAAMsE,GAAG,WACf2P,IAAKvW,KAAK/E,KAAM+E,KAAKlO,MACtB,SAMA,IAAM4+B,KAAU9pB,EACfwyB,YAAa1I,EAAQ9pB,EAAG8pB,GAAU2I,EAAa9iB,KAKjD,OAAOgjB,EAAEpvB,KAAM,IAChB,EAEA3I,OAAOG,GAAG2B,OAAQ,CACjBo2B,UAAW,WACV,OAAOl4B,OAAO83B,MAAOt5B,KAAK25B,iBAC3B,EACAA,eAAgB,WACf,OAAO35B,KAAKwC,KAAK,WAGhB,IAAIsL,EAAWtM,OAAO7P,KAAMqO,KAAM,YAClC,OAAO8N,EAAWtM,OAAOgD,UAAWsJ,GAAa9N,IAClD,IAAIyM,QAAQ,WACX,IAAI3L,EAAOd,KAAKc,KAGhB,OAAOd,KAAK/E,OAASuG,OAAQxB,MAAO+U,GAAI,cACvCokB,GAAa9oC,KAAM2P,KAAKtD,YAAew8B,GAAgB7oC,KAAMyQ,KAC3Dd,KAAK4Q,UAAYsP,EAAe7vB,KAAMyQ,GAC1C,IAAI0B,KAAK,SAAUyC,EAAIxC,GACtB,IAAIrB,EAAMI,OAAQxB,MAAOoB,MAEzB,OAAY,MAAPA,EACG,KAGH/T,MAAMC,QAAS8T,GACZI,OAAOgB,IAAKpB,GAAK,SAAUA,GACjC,MAAO,CAAEnG,KAAMwH,EAAKxH,KAAMnJ,MAAOsP,EAAItR,QAASmpC,GAAO,QACtD,IAGM,CAAEh+B,KAAMwH,EAAKxH,KAAMnJ,MAAOsP,EAAItR,QAASmpC,GAAO,QACtD,IAAIpnC,KACL,IAID,IACC+nC,GAAM,OACNC,GAAQ,OACRC,GAAa,gBACbC,GAAW,6BAIXC,GAAa,iBACbC,GAAY,QAWZlH,GAAa,CAAC,EAOdmH,GAAa,CAAC,EAGdC,GAAW,KAAKnrC,OAAQ,KAGxBorC,GAAezmC,EAASuC,cAAe,KAKxC,SAASmkC,4BAA6BC,GAGrC,OAAO,SAAUC,EAAoB9pC,GAED,iBAAvB8pC,IACX9pC,EAAO8pC,EACPA,EAAqB,KAGtB,IAAIC,EACHjtC,EAAI,EACJktC,EAAYF,EAAmB7qC,cAAcE,MAAOonB,IAAmB,GAExE,GAAKtW,EAAYjQ,GAGhB,KAAU+pC,EAAWC,EAAWltC,MAGR,MAAlBitC,EAAU,IACdA,EAAWA,EAASr6B,MAAO,IAAO,KAChCm6B,EAAWE,GAAaF,EAAWE,IAAc,IAAK5sB,QAASnd,KAI/D6pC,EAAWE,GAAaF,EAAWE,IAAc,IAAKjrC,KAAMkB,EAIlE,CACD,CAGA,SAASiqC,8BAA+BJ,EAAW/2B,EAAS+vB,EAAiBqH,GAE5E,IAAIC,EAAY,CAAC,EAChBC,EAAqBP,IAAcJ,GAEpC,SAASY,QAASN,GACjB,IAAI3pB,EAcJ,OAbA+pB,EAAWJ,IAAa,EACxBh5B,OAAOc,KAAMg4B,EAAWE,IAAc,IAAI,SAAUnmC,EAAG0mC,GACtD,IAAIC,EAAsBD,EAAoBx3B,EAAS+vB,EAAiBqH,GACxE,MAAoC,iBAAxBK,GACVH,GAAqBD,EAAWI,GAKtBH,IACDhqB,EAAWmqB,QADf,GAHNz3B,EAAQk3B,UAAU7sB,QAASotB,GAC3BF,QAASE,IACF,EAIT,IACOnqB,CACR,CAEA,OAAOiqB,QAASv3B,EAAQk3B,UAAW,MAAUG,EAAW,MAASE,QAAS,IAC3E,CAKA,SAASG,WAAYv3B,EAAQ3C,GAC5B,IAAIyJ,EAAK7G,EACRu3B,EAAc15B,OAAO25B,aAAaD,aAAe,CAAC,EAEnD,IAAM1wB,KAAOzJ,OACQtM,IAAfsM,EAAKyJ,MACP0wB,EAAa1wB,GAAQ9G,EAAWC,IAAUA,EAAO,CAAC,IAAS6G,GAAQzJ,EAAKyJ,IAO5E,OAJK7G,GACJnC,OAAO8B,QAAQ,EAAMI,EAAQC,GAGvBD,CACR,CAhFA02B,GAAa1pB,KAAOH,GAASG,KAgP7BlP,OAAO8B,OAAQ,CAGd83B,OAAQ,EAGRC,aAAc,CAAC,EACfC,KAAM,CAAC,EAEPH,aAAc,CACbI,IAAKhrB,GAASG,KACd5P,KAAM,MACN06B,QAxRgB,4DAwRQnrC,KAAMkgB,GAASkrB,UACvC57B,QAAQ,EACR67B,aAAa,EACbC,OAAO,EACPC,YAAa,mDAcbC,QAAS,CACR,IAAK1B,GACL9nC,KAAM,aACNN,KAAM,YACNU,IAAK,4BACLqpC,KAAM,qCAGP/lB,SAAU,CACTtjB,IAAK,UACLV,KAAM,SACN+pC,KAAM,YAGPC,eAAgB,CACftpC,IAAK,cACLJ,KAAM,eACNypC,KAAM,gBAKPE,WAAY,CAGX,SAAUvsC,OAGV,aAAa,EAGb,YAAa8tB,KAAKC,MAGlB,WAAYhc,OAAOs3B,UAOpBoC,YAAa,CACZK,KAAK,EACL75B,SAAS,IAOXu6B,UAAW,SAAUv4B,EAAQw4B,GAC5B,OAAOA,EAGNjB,WAAYA,WAAYv3B,EAAQlC,OAAO25B,cAAgBe,GAGvDjB,WAAYz5B,OAAO25B,aAAcz3B,EACnC,EAEAy4B,cAAe9B,4BAA6BtH,IAC5CqJ,cAAe/B,4BAA6BH,IAG5CmC,KAAM,SAAUd,EAAKh4B,GAGA,iBAARg4B,IACXh4B,EAAUg4B,EACVA,OAAM9mC,GAIP8O,EAAUA,GAAW,CAAC,EAEtB,IAAI+4B,EAGHC,EAGAC,EACAC,EAGAC,EAGAC,EAGArhB,EAGAshB,EAGArvC,EAGAsvC,EAGAtD,EAAI/3B,OAAOy6B,UAAW,CAAC,EAAG14B,GAG1Bu5B,EAAkBvD,EAAE73B,SAAW63B,EAG/BwD,EAAqBxD,EAAE73B,UACpBo7B,EAAgBhoC,UAAYgoC,EAAgBh7B,QAC9CN,OAAQs7B,GACRt7B,OAAOghB,MAGRvJ,EAAWzX,OAAOqX,WAClBmkB,EAAmBx7B,OAAOqW,UAAW,eAGrColB,EAAa1D,EAAE0D,YAAc,CAAC,EAG9BC,EAAiB,CAAC,EAClBC,EAAsB,CAAC,EAGvBC,EAAW,WAGXzC,EAAQ,CACPhf,WAAY,EAGZ0hB,kBAAmB,SAAU7yB,GAC5B,IAAI5a,EACJ,GAAK0rB,EAAY,CAChB,IAAMmhB,EAEL,IADAA,EAAkB,CAAC,EACT7sC,EAAQmqC,GAASpwB,KAAM6yB,IAChCC,EAAiB7sC,EAAO,GAAIF,cAAgB,MACzC+sC,EAAiB7sC,EAAO,GAAIF,cAAgB,MAAS,IACrDV,OAAQY,EAAO,IAGpBA,EAAQ6sC,EAAiBjyB,EAAI9a,cAAgB,IAC9C,CACA,OAAgB,MAATE,EAAgB,KAAOA,EAAMua,KAAM,KAC3C,EAGAmzB,sBAAuB,WACtB,OAAOhiB,EAAYkhB,EAAwB,IAC5C,EAGAe,iBAAkB,SAAUtiC,EAAMnJ,GAMjC,OALkB,MAAbwpB,IACJrgB,EAAOkiC,EAAqBliC,EAAKvL,eAChCytC,EAAqBliC,EAAKvL,gBAAmBuL,EAC9CiiC,EAAgBjiC,GAASnJ,GAEnBkO,IACR,EAGAw9B,iBAAkB,SAAU18B,GAI3B,OAHkB,MAAbwa,IACJie,EAAEkE,SAAW38B,GAEPd,IACR,EAGAi9B,WAAY,SAAUz6B,GACrB,IAAIrB,EACJ,GAAKqB,EACJ,GAAK8Y,EAGJqf,EAAM3hB,OAAQxW,EAAKm4B,EAAM+C,cAIzB,IAAMv8B,KAAQqB,EACby6B,EAAY97B,GAAS,CAAE87B,EAAY97B,GAAQqB,EAAKrB,IAInD,OAAOnB,IACR,EAGA29B,MAAO,SAAUC,GAChB,IAAIC,EAAYD,GAAcR,EAK9B,OAJKd,GACJA,EAAUqB,MAAOE,GAElBx3B,KAAM,EAAGw3B,GACF79B,IACR,GAmBF,GAfAiZ,EAASvB,QAASijB,GAKlBpB,EAAEgC,MAAUA,GAAOhC,EAAEgC,KAAOhrB,GAASG,MAAS,IAC5C5gB,QAASmqC,GAAW1pB,GAASkrB,SAAW,MAG1ClC,EAAEz4B,KAAOyC,EAAQkU,QAAUlU,EAAQzC,MAAQy4B,EAAE9hB,QAAU8hB,EAAEz4B,KAGzDy4B,EAAEkB,WAAclB,EAAEiB,UAAY,KAAM9qC,cAAcE,MAAOonB,IAAmB,CAAE,IAGxD,MAAjBuiB,EAAEuE,YAAsB,CAC5BnB,EAAYhpC,EAASuC,cAAe,KAKpC,IACCymC,EAAUjsB,KAAO6oB,EAAEgC,IAInBoB,EAAUjsB,KAAOisB,EAAUjsB,KAC3B6oB,EAAEuE,YAAc1D,GAAaqB,SAAW,KAAOrB,GAAa2D,MAC3DpB,EAAUlB,SAAW,KAAOkB,EAAUoB,IACxC,CAAE,MAAQ50B,GAITowB,EAAEuE,aAAc,CACjB,CACD,CAWA,GARKvE,EAAEr8B,MAAQq8B,EAAEmC,aAAiC,iBAAXnC,EAAEr8B,OACxCq8B,EAAEr8B,KAAOsE,OAAO83B,MAAOC,EAAEr8B,KAAMq8B,EAAEF,cAIlCqB,8BAA+B3H,GAAYwG,EAAGh2B,EAASo3B,GAGlDrf,EACJ,OAAOqf,EA8ER,IAAMptC,KAzENqvC,EAAcp7B,OAAOghB,OAAS+W,EAAE15B,SAGQ,GAApB2B,OAAO45B,UAC1B55B,OAAOghB,MAAMU,QAAS,aAIvBqW,EAAEz4B,KAAOy4B,EAAEz4B,KAAKyb,cAGhBgd,EAAEyE,YAAchE,GAAW3pC,KAAMkpC,EAAEz4B,MAKnCy7B,EAAWhD,EAAEgC,IAAIzrC,QAAS+pC,GAAO,IAG3BN,EAAEyE,WAwBIzE,EAAEr8B,MAAQq8B,EAAEmC,aACoD,KAAzEnC,EAAEqC,aAAe,IAAK5rC,QAAS,uCACjCupC,EAAEr8B,KAAOq8B,EAAEr8B,KAAKpN,QAAS8pC,GAAK,OAvB9BiD,EAAWtD,EAAEgC,IAAIp7B,MAAOo8B,EAAS9uC,QAG5B8rC,EAAEr8B,OAAUq8B,EAAEmC,aAAiC,iBAAXnC,EAAEr8B,QAC1Cq/B,IAAc1D,GAAOxoC,KAAMksC,GAAa,IAAM,KAAQhD,EAAEr8B,YAGjDq8B,EAAEr8B,OAIO,IAAZq8B,EAAEhvB,QACNgyB,EAAWA,EAASzsC,QAASgqC,GAAY,MACzC+C,GAAahE,GAAOxoC,KAAMksC,GAAa,IAAM,KAAQ,KAASv7B,GAAM+D,OACnE83B,GAIFtD,EAAEgC,IAAMgB,EAAWM,GASftD,EAAE0E,aACDz8B,OAAO65B,aAAckB,IACzB5B,EAAM4C,iBAAkB,oBAAqB/7B,OAAO65B,aAAckB,IAE9D/6B,OAAO85B,KAAMiB,IACjB5B,EAAM4C,iBAAkB,gBAAiB/7B,OAAO85B,KAAMiB,MAKnDhD,EAAEr8B,MAAQq8B,EAAEyE,aAAgC,IAAlBzE,EAAEqC,aAAyBr4B,EAAQq4B,cACjEjB,EAAM4C,iBAAkB,eAAgBhE,EAAEqC,aAI3CjB,EAAM4C,iBACL,SACAhE,EAAEkB,UAAW,IAAOlB,EAAEsC,QAAStC,EAAEkB,UAAW,IAC3ClB,EAAEsC,QAAStC,EAAEkB,UAAW,KACA,MAArBlB,EAAEkB,UAAW,GAAc,KAAON,GAAW,WAAa,IAC7DZ,EAAEsC,QAAS,MAIFtC,EAAE2E,QACZvD,EAAM4C,iBAAkBhwC,EAAGgsC,EAAE2E,QAAS3wC,IAIvC,GAAKgsC,EAAE4E,cAC+C,IAAnD5E,EAAE4E,WAAWjiC,KAAM4gC,EAAiBnC,EAAOpB,IAAiBje,GAG9D,OAAOqf,EAAMgD,QAed,GAXAP,EAAW,QAGXJ,EAAiBzmB,IAAKgjB,EAAE9F,UACxBkH,EAAMt0B,KAAMkzB,EAAE6E,SACdzD,EAAMhjB,KAAM4hB,EAAEt1B,OAGdq4B,EAAY5B,8BAA+BR,GAAYX,EAAGh2B,EAASo3B,GAK5D,CASN,GARAA,EAAMhf,WAAa,EAGdihB,GACJG,EAAmB7Z,QAAS,WAAY,CAAEyX,EAAOpB,IAI7Cje,EACJ,OAAOqf,EAIHpB,EAAEoC,OAASpC,EAAEzD,QAAU,IAC3B4G,EAAelpC,EAAOgnB,YAAY,WACjCmgB,EAAMgD,MAAO,UACd,GAAGpE,EAAEzD,UAGN,IACCxa,GAAY,EACZghB,EAAU+B,KAAMnB,EAAgB72B,KACjC,CAAE,MAAQ8C,GAGT,GAAKmS,EACJ,MAAMnS,EAIP9C,MAAO,EAAG8C,EACX,CACD,MAlCC9C,MAAO,EAAG,gBAqCX,SAASA,KAAMq3B,EAAQY,EAAkBC,EAAWL,GACnD,IAAIM,EAAWJ,EAASn6B,EAAOw6B,EAAUC,EACxCd,EAAaU,EAGThjB,IAILA,GAAY,EAGPohB,GACJlpC,EAAOuiC,aAAc2G,GAKtBJ,OAAY7nC,EAGZ+nC,EAAwB0B,GAAW,GAGnCvD,EAAMhf,WAAa+hB,EAAS,EAAI,EAAI,EAGpCc,EAAYd,GAAU,KAAOA,EAAS,KAAkB,MAAXA,EAGxCa,IACJE,EA7lBJ,SAASE,oBAAqBpF,EAAGoB,EAAO4D,GAOvC,IALA,IAAIK,EAAI99B,EAAM+9B,EAAeC,EAC5B/oB,EAAWwjB,EAAExjB,SACb0kB,EAAYlB,EAAEkB,UAGY,MAAnBA,EAAW,IAClBA,EAAU/vB,aACEjW,IAAPmqC,IACJA,EAAKrF,EAAEkE,UAAY9C,EAAM0C,kBAAmB,iBAK9C,GAAKuB,EACJ,IAAM99B,KAAQiV,EACb,GAAKA,EAAUjV,IAAUiV,EAAUjV,GAAOzQ,KAAMuuC,GAAO,CACtDnE,EAAU7sB,QAAS9M,GACnB,KACD,CAKF,GAAK25B,EAAW,KAAO8D,EACtBM,EAAgBpE,EAAW,OACrB,CAGN,IAAM35B,KAAQy9B,EAAY,CACzB,IAAM9D,EAAW,IAAOlB,EAAEyC,WAAYl7B,EAAO,IAAM25B,EAAW,IAAQ,CACrEoE,EAAgB/9B,EAChB,KACD,CACMg+B,IACLA,EAAgBh+B,EAElB,CAGA+9B,EAAgBA,GAAiBC,CAClC,CAKA,GAAKD,EAIJ,OAHKA,IAAkBpE,EAAW,IACjCA,EAAU7sB,QAASixB,GAEbN,EAAWM,EAEpB,CAwiBeF,CAAqBpF,EAAGoB,EAAO4D,KAIrCC,GACLh9B,OAAOkD,QAAS,SAAU60B,EAAEkB,YAAe,GAC3Cj5B,OAAOkD,QAAS,OAAQ60B,EAAEkB,WAAc,IACxClB,EAAEyC,WAAY,eAAkB,WAAY,GAI7CyC,EA9iBH,SAASM,YAAaxF,EAAGkF,EAAU9D,EAAO6D,GACzC,IAAIQ,EAAOC,EAASC,EAAMtyB,EAAKoJ,EAC9BgmB,EAAa,CAAC,EAGdvB,EAAYlB,EAAEkB,UAAUt6B,QAGzB,GAAKs6B,EAAW,GACf,IAAMyE,KAAQ3F,EAAEyC,WACfA,EAAYkD,EAAKxvC,eAAkB6pC,EAAEyC,WAAYkD,GAOnD,IAHAD,EAAUxE,EAAU/vB,QAGZu0B,GAcP,GAZK1F,EAAEwC,eAAgBkD,KACtBtE,EAAOpB,EAAEwC,eAAgBkD,IAAcR,IAIlCzoB,GAAQwoB,GAAajF,EAAE4F,aAC5BV,EAAWlF,EAAE4F,WAAYV,EAAUlF,EAAEiB,WAGtCxkB,EAAOipB,EACPA,EAAUxE,EAAU/vB,QAKnB,GAAiB,MAAZu0B,EAEJA,EAAUjpB,OAGJ,GAAc,MAATA,GAAgBA,IAASipB,EAAU,CAM9C,KAHAC,EAAOlD,EAAYhmB,EAAO,IAAMipB,IAAajD,EAAY,KAAOiD,IAI/D,IAAMD,KAAShD,EAId,IADApvB,EAAMoyB,EAAMh6B,MAAO,MACT,KAAQi6B,IAGjBC,EAAOlD,EAAYhmB,EAAO,IAAMpJ,EAAK,KACpCovB,EAAY,KAAOpvB,EAAK,KACb,EAGG,IAATsyB,EACJA,EAAOlD,EAAYgD,IAGgB,IAAxBhD,EAAYgD,KACvBC,EAAUryB,EAAK,GACf6tB,EAAU7sB,QAAShB,EAAK,KAEzB,KACD,CAMH,IAAc,IAATsyB,EAGJ,GAAKA,GAAQ3F,EAAE6F,OACdX,EAAWS,EAAMT,QAEjB,IACCA,EAAWS,EAAMT,EAClB,CAAE,MAAQt1B,GACT,MAAO,CACN4P,MAAO,cACP9U,MAAOi7B,EAAO/1B,EAAI,sBAAwB6M,EAAO,OAASipB,EAE5D,CAGH,CAIF,MAAO,CAAElmB,MAAO,UAAW7b,KAAMuhC,EAClC,CAgdcM,CAAaxF,EAAGkF,EAAU9D,EAAO6D,GAGvCA,GAGCjF,EAAE0E,cACNS,EAAW/D,EAAM0C,kBAAmB,oBAEnC77B,OAAO65B,aAAckB,GAAamC,IAEnCA,EAAW/D,EAAM0C,kBAAmB,WAEnC77B,OAAO85B,KAAMiB,GAAamC,IAKZ,MAAXhB,GAA6B,SAAXnE,EAAEz4B,KACxB88B,EAAa,YAGS,MAAXF,EACXE,EAAa,eAIbA,EAAaa,EAAS1lB,MACtBqlB,EAAUK,EAASvhC,KAEnBshC,IADAv6B,EAAQw6B,EAASx6B,UAMlBA,EAAQ25B,GACHF,GAAWE,IACfA,EAAa,QACRF,EAAS,IACbA,EAAS,KAMZ/C,EAAM+C,OAASA,EACf/C,EAAMiD,YAAeU,GAAoBV,GAAe,GAGnDY,EACJvlB,EAASiB,YAAa4iB,EAAiB,CAAEsB,EAASR,EAAYjD,IAE9D1hB,EAASqB,WAAYwiB,EAAiB,CAAEnC,EAAOiD,EAAY35B,IAI5D02B,EAAMsC,WAAYA,GAClBA,OAAaxoC,EAERmoC,GACJG,EAAmB7Z,QAASsb,EAAY,cAAgB,YACvD,CAAE7D,EAAOpB,EAAGiF,EAAYJ,EAAUn6B,IAIpC+4B,EAAiBpkB,SAAUkkB,EAAiB,CAAEnC,EAAOiD,IAEhDhB,IACJG,EAAmB7Z,QAAS,eAAgB,CAAEyX,EAAOpB,MAG3C/3B,OAAO45B,QAChB55B,OAAOghB,MAAMU,QAAS,aAGzB,CAEA,OAAOyX,CACR,EAEA0E,QAAS,SAAU9D,EAAKr+B,EAAMqF,GAC7B,OAAOf,OAAO3P,IAAK0pC,EAAKr+B,EAAMqF,EAAU,OACzC,EAEA+8B,UAAW,SAAU/D,EAAKh5B,GACzB,OAAOf,OAAO3P,IAAK0pC,OAAK9mC,EAAW8N,EAAU,SAC9C,IAGDf,OAAOc,KAAM,CAAE,MAAO,SAAU,SAAU2C,EAAIwS,GAC7CjW,OAAQiW,GAAW,SAAU8jB,EAAKr+B,EAAMqF,EAAUzB,GAUjD,OAPKJ,EAAYxD,KAChB4D,EAAOA,GAAQyB,EACfA,EAAWrF,EACXA,OAAOzI,GAID+M,OAAO66B,KAAM76B,OAAO8B,OAAQ,CAClCi4B,IAAKA,EACLz6B,KAAM2W,EACN+iB,SAAU15B,EACV5D,KAAMA,EACNkhC,QAAS77B,GACPf,OAAOoC,cAAe23B,IAASA,GACnC,CACD,IAEA/5B,OAAO26B,eAAe,SAAU5C,GAC/B,IAAIhsC,EACJ,IAAMA,KAAKgsC,EAAE2E,QACa,iBAApB3wC,EAAEmC,gBACN6pC,EAAEqC,YAAcrC,EAAE2E,QAAS3wC,IAAO,GAGrC,IAGAiU,OAAO+nB,SAAW,SAAUgS,EAAKh4B,EAAShI,GACzC,OAAOiG,OAAO66B,KAAM,CACnBd,IAAKA,EAGLz6B,KAAM,MACN05B,SAAU,SACVjwB,OAAO,EACPoxB,OAAO,EACP97B,QAAQ,EAKRm8B,WAAY,CACX,cAAe,WAAY,GAE5BmD,WAAY,SAAUV,GACrBj9B,OAAO+C,WAAYk6B,EAAUl7B,EAAShI,EACvC,GAEF,EAGAiG,OAAOG,GAAG2B,OAAQ,CACjBi8B,QAAS,SAAUxtC,GAClB,IAAI2vB,EAyBJ,OAvBK1hB,KAAM,KACLU,EAAY3O,KAChBA,EAAOA,EAAKmK,KAAM8D,KAAM,KAIzB0hB,EAAOlgB,OAAQzP,EAAMiO,KAAM,GAAI5J,eAAgBuM,GAAI,GAAIrR,OAAO,GAEzD0O,KAAM,GAAIpF,YACd8mB,EAAK3lB,aAAciE,KAAM,IAG1B0hB,EAAKlf,KAAK,WAGT,IAFA,IAAIC,EAAOzC,KAEHyC,EAAK3G,mBACZ2G,EAAOA,EAAK3G,kBAGb,OAAO2G,CACR,IAAIunB,OAAQhqB,OAGNA,IACR,EAEAw/B,UAAW,SAAUztC,GACpB,OAAK2O,EAAY3O,GACTiO,KAAKsC,MAAM,SAAU/U,GAC3BiU,OAAQxB,MAAOw/B,UAAWztC,EAAKmK,KAAM8D,KAAMzS,GAC5C,IAGMyS,KAAKsC,MAAM,WACjB,IAAIkT,EAAOhU,OAAQxB,MAClB+V,EAAWP,EAAKO,WAEZA,EAAStoB,OACbsoB,EAASwpB,QAASxtC,GAGlByjB,EAAKwU,OAAQj4B,EAEf,GACD,EAEA2vB,KAAM,SAAU3vB,GACf,IAAI0tC,EAAiB/+B,EAAY3O,GAEjC,OAAOiO,KAAKsC,MAAM,SAAU/U,GAC3BiU,OAAQxB,MAAOu/B,QAASE,EAAiB1tC,EAAKmK,KAAM8D,KAAMzS,GAAMwE,EACjE,GACD,EAEA2tC,OAAQ,SAAUj+B,GAIjB,OAHAzB,KAAK5F,OAAQqH,GAAW8T,IAAK,QAASjT,MAAM,WAC3Cd,OAAQxB,MAAOoqB,YAAapqB,KAAK/D,WAClC,IACO+D,IACR,IAIDwB,OAAOqM,KAAK1G,QAAQ+qB,OAAS,SAAUzvB,GACtC,OAAQjB,OAAOqM,KAAK1G,QAAQw4B,QAASl9B,EACtC,EACAjB,OAAOqM,KAAK1G,QAAQw4B,QAAU,SAAUl9B,GACvC,SAAWA,EAAKiqB,aAAejqB,EAAKmrB,cAAgBnrB,EAAKktB,iBAAiBliC,OAC3E,EAKA+T,OAAO25B,aAAayE,IAAM,WACzB,IACC,OAAO,IAAIpsC,EAAOqsC,cACnB,CAAE,MAAQ12B,GAAK,CAChB,EAEA,IAAI22B,GAAmB,CAGrB,EAAG,IAIH,KAAM,KAEPC,GAAev+B,OAAO25B,aAAayE,MAEpCn/B,EAAQu/B,OAASD,IAAkB,oBAAqBA,GACxDt/B,EAAQ47B,KAAO0D,KAAiBA,GAEhCv+B,OAAO46B,eAAe,SAAU74B,GAC/B,IAAIhB,EAAU09B,EAGd,GAAKx/B,EAAQu/B,MAAQD,KAAiBx8B,EAAQu6B,YAC7C,MAAO,CACNO,KAAM,SAAUH,EAASzK,GACxB,IAAIlmC,EACHqyC,EAAMr8B,EAAQq8B,MAWf,GATAA,EAAIM,KACH38B,EAAQzC,KACRyC,EAAQg4B,IACRh4B,EAAQo4B,MACRp4B,EAAQ48B,SACR58B,EAAQ4N,UAIJ5N,EAAQ68B,UACZ,IAAM7yC,KAAKgW,EAAQ68B,UAClBR,EAAKryC,GAAMgW,EAAQ68B,UAAW7yC,GAmBhC,IAAMA,KAdDgW,EAAQk6B,UAAYmC,EAAIpC,kBAC5BoC,EAAIpC,iBAAkBj6B,EAAQk6B,UAQzBl6B,EAAQu6B,aAAgBI,EAAS,sBACtCA,EAAS,oBAAuB,kBAItBA,EACV0B,EAAIrC,iBAAkBhwC,EAAG2wC,EAAS3wC,IAInCgV,EAAW,SAAUzB,GACpB,OAAO,WACDyB,IACJA,EAAW09B,EAAgBL,EAAIS,OAC9BT,EAAIU,QAAUV,EAAIW,QAAUX,EAAIY,UAC/BZ,EAAIa,mBAAqB,KAEb,UAAT3/B,EACJ8+B,EAAIjC,QACgB,UAAT78B,EAKgB,iBAAf8+B,EAAIlC,OACfjK,EAAU,EAAG,SAEbA,EAGCmM,EAAIlC,OACJkC,EAAIhC,YAINnK,EACCqM,GAAkBF,EAAIlC,SAAYkC,EAAIlC,OACtCkC,EAAIhC,WAK+B,UAAjCgC,EAAIc,cAAgB,SACM,iBAArBd,EAAIe,aACV,CAAEC,OAAQhB,EAAInB,UACd,CAAEpsC,KAAMutC,EAAIe,cACbf,EAAItC,yBAIR,CACD,EAGAsC,EAAIS,OAAS99B,IACb09B,EAAgBL,EAAIU,QAAUV,EAAIY,UAAYj+B,EAAU,cAKnC9N,IAAhBmrC,EAAIW,QACRX,EAAIW,QAAUN,EAEdL,EAAIa,mBAAqB,WAGA,IAAnBb,EAAIjkB,YAMRnoB,EAAOgnB,YAAY,WACbjY,GACJ09B,GAEF,GAEF,EAID19B,EAAWA,EAAU,SAErB,IAGCq9B,EAAIvB,KAAM96B,EAAQy6B,YAAcz6B,EAAQrG,MAAQ,KACjD,CAAE,MAAQiM,GAGT,GAAK5G,EACJ,MAAM4G,CAER,CACD,EAEAw0B,MAAO,WACDp7B,GACJA,GAEF,EAGH,IAMAf,OAAO26B,eAAe,SAAU5C,GAC1BA,EAAEuE,cACNvE,EAAExjB,SAAS1U,QAAS,EAEtB,IAGAG,OAAOy6B,UAAW,CACjBJ,QAAS,CACRx6B,OAAQ,6FAGT0U,SAAU,CACT1U,OAAQ,2BAET26B,WAAY,CACX,cAAe,SAAU3pC,GAExB,OADAmP,OAAO+C,WAAYlS,GACZA,CACR,KAKFmP,OAAO26B,cAAe,UAAU,SAAU5C,QACxB9kC,IAAZ8kC,EAAEhvB,QACNgvB,EAAEhvB,OAAQ,GAENgvB,EAAEuE,cACNvE,EAAEz4B,KAAO,MAEX,IAGAU,OAAO46B,cAAe,UAAU,SAAU7C,GAIxC,IAAIl4B,EAAQkB,EADb,GAAKg3B,EAAEuE,aAAevE,EAAEsH,YAEvB,MAAO,CACNxC,KAAM,SAAUhqC,EAAGo/B,GAClBpyB,EAASG,OAAQ,YACf7D,KAAM47B,EAAEsH,aAAe,CAAC,GACxBlvC,KAAM,CAAEmvC,QAASvH,EAAEwH,cAAehgC,IAAKw4B,EAAEgC,MACzCnZ,GAAI,aAAc7f,EAAW,SAAUy+B,GACvC3/B,EAAOtG,SACPwH,EAAW,KACNy+B,GACJvN,EAAuB,UAAbuN,EAAIlgC,KAAmB,IAAM,IAAKkgC,EAAIlgC,KAElD,GAGDnN,EAAS2N,KAAKvC,YAAasC,EAAQ,GACpC,EACAs8B,MAAO,WACDp7B,GACJA,GAEF,EAGH,IAKA,IAqGK1G,GArGDolC,GAAe,GAClBC,GAAS,oBAGV1/B,OAAOy6B,UAAW,CACjBkF,MAAO,WACPC,cAAe,WACd,IAAI7+B,EAAW0+B,GAAa5xC,OAAWmS,OAAOqC,QAAU,IAAQ7C,GAAM+D,OAEtE,OADA/E,KAAMuC,IAAa,EACZA,CACR,IAIDf,OAAO26B,cAAe,cAAc,SAAU5C,EAAG8H,EAAkB1G,GAElE,IAAI2G,EAAcC,EAAaC,EAC9BC,GAAuB,IAAZlI,EAAE4H,QAAqBD,GAAO7wC,KAAMkpC,EAAEgC,KAChD,MACkB,iBAAXhC,EAAEr8B,MAE6C,KADnDq8B,EAAEqC,aAAe,IACjB5rC,QAAS,sCACXkxC,GAAO7wC,KAAMkpC,EAAEr8B,OAAU,QAI5B,GAAKukC,GAAiC,UAArBlI,EAAEkB,UAAW,GA8D7B,OA3DA6G,EAAe/H,EAAE6H,cAAgB1gC,EAAY64B,EAAE6H,eAC9C7H,EAAE6H,gBACF7H,EAAE6H,cAGEK,EACJlI,EAAGkI,GAAalI,EAAGkI,GAAW3xC,QAASoxC,GAAQ,KAAOI,IAC/B,IAAZ/H,EAAE4H,QACb5H,EAAEgC,MAAS1C,GAAOxoC,KAAMkpC,EAAEgC,KAAQ,IAAM,KAAQhC,EAAE4H,MAAQ,IAAMG,GAIjE/H,EAAEyC,WAAY,eAAkB,WAI/B,OAHMwF,GACLhgC,OAAOyC,MAAOq9B,EAAe,mBAEvBE,EAAmB,EAC3B,EAGAjI,EAAEkB,UAAW,GAAM,OAGnB8G,EAAc/tC,EAAQ8tC,GACtB9tC,EAAQ8tC,GAAiB,WACxBE,EAAoB5wC,SACrB,EAGA+pC,EAAM3hB,QAAQ,gBAGQvkB,IAAhB8sC,EACJ//B,OAAQhO,GAASwjC,WAAYsK,GAI7B9tC,EAAQ8tC,GAAiBC,EAIrBhI,EAAG+H,KAGP/H,EAAE6H,cAAgBC,EAAiBD,cAGnCH,GAAa1xC,KAAM+xC,IAIfE,GAAqB9gC,EAAY6gC,IACrCA,EAAaC,EAAmB,IAGjCA,EAAoBD,OAAc9sC,CACnC,IAGO,QAET,IAUAgM,EAAQzJ,qBACH6E,GAAOlI,EAAS8C,eAAeO,mBAAoB,IAAK6E,MACvDyB,UAAY,6BACiB,IAA3BzB,GAAKI,WAAWxO,QAQxB+T,OAAOkU,UAAY,SAAUxY,EAAMwE,EAASggC,GAC3C,MAAqB,iBAATxkC,EACJ,IAEgB,kBAAZwE,IACXggC,EAAchgC,EACdA,GAAU,GAKLA,IAIAjB,EAAQzJ,qBAMZya,GALA/P,EAAU/N,EAAS8C,eAAeO,mBAAoB,KAKvCd,cAAe,SACzBwa,KAAO/c,EAAS4c,SAASG,KAC9BhP,EAAQJ,KAAKvC,YAAa0S,IAE1B/P,EAAU/N,GAKZ4tB,GAAWmgB,GAAe,IAD1BC,EAASvsB,EAAWzL,KAAMzM,IAKlB,CAAEwE,EAAQxL,cAAeyrC,EAAQ,MAGzCA,EAASrgB,cAAe,CAAEpkB,GAAQwE,EAAS6f,GAEtCA,GAAWA,EAAQ9zB,QACvB+T,OAAQ+f,GAAUxmB,SAGZyG,OAAOY,MAAO,GAAIu/B,EAAO1lC,cAlChC,IAAIwV,EAAMkwB,EAAQpgB,CAmCnB,EAMA/f,OAAOG,GAAG6jB,KAAO,SAAU+V,EAAKqG,EAAQr/B,GACvC,IAAId,EAAUX,EAAM29B,EACnBjpB,EAAOxV,KACPyiB,EAAM8Y,EAAIvrC,QAAS,KAsDpB,OApDKyyB,GAAO,IACXhhB,EAAWo1B,iBAAkB0E,EAAIp7B,MAAOsiB,IACxC8Y,EAAMA,EAAIp7B,MAAO,EAAGsiB,IAIhB/hB,EAAYkhC,IAGhBr/B,EAAWq/B,EACXA,OAASntC,GAGEmtC,GAA4B,iBAAXA,IAC5B9gC,EAAO,QAIH0U,EAAK/nB,OAAS,GAClB+T,OAAO66B,KAAM,CACZd,IAAKA,EAKLz6B,KAAMA,GAAQ,MACd05B,SAAU,OACVt9B,KAAM0kC,IACHv7B,MAAM,SAAUs6B,GAGnBlC,EAAW7tC,UAEX4kB,EAAKzjB,KAAM0P,EAIVD,OAAQ,SAAUwoB,OAAQxoB,OAAOkU,UAAWirB,IAAiBh0B,KAAMlL,GAGnEk/B,EAKF,IAAI3nB,OAAQzW,GAAY,SAAUo4B,EAAO+C,GACxCloB,EAAKlT,MAAM,WACVC,EAASjU,MAAO0R,KAAMy+B,GAAY,CAAE9D,EAAMgG,aAAcjD,EAAQ/C,GACjE,GACD,GAGM36B,IACR,EAKAwB,OAAOqM,KAAK1G,QAAQ06B,SAAW,SAAUp/B,GACxC,OAAOjB,OAAOsB,KAAMtB,OAAO0zB,QAAQ,SAAUvzB,GAC5C,OAAOc,IAASd,EAAGc,IACpB,IAAIhV,MACL,EAKA+T,OAAOsgC,OAAS,CACfC,UAAW,SAAUt/B,EAAMc,EAAShW,GACnC,IAAIy0C,EAAaC,EAASC,EAAWC,EAAQC,EAAWC,EACvD7V,EAAWhrB,OAAOsd,IAAKrc,EAAM,YAC7B6/B,EAAU9gC,OAAQiB,GAClBojB,EAAQ,CAAC,EAGQ,WAAb2G,IACJ/pB,EAAKmc,MAAM4N,SAAW,YAGvB4V,EAAYE,EAAQR,SACpBI,EAAY1gC,OAAOsd,IAAKrc,EAAM,OAC9B4/B,EAAa7gC,OAAOsd,IAAKrc,EAAM,SACI,aAAb+pB,GAAwC,UAAbA,KAC9C0V,EAAYG,GAAaryC,QAAS,SAAY,GAMhDmyC,GADAH,EAAcM,EAAQ9V,YACDtgB,IACrB+1B,EAAUD,EAAY1R,OAGtB6R,EAAStV,WAAYqV,IAAe,EACpCD,EAAUpV,WAAYwV,IAAgB,GAGlC3hC,EAAY6C,KAGhBA,EAAUA,EAAQrH,KAAMuG,EAAMlV,EAAGiU,OAAO8B,OAAQ,CAAC,EAAG8+B,KAGjC,MAAf7+B,EAAQ2I,MACZ2Z,EAAM3Z,IAAQ3I,EAAQ2I,IAAMk2B,EAAUl2B,IAAQi2B,GAE1B,MAAhB5+B,EAAQ+sB,OACZzK,EAAMyK,KAAS/sB,EAAQ+sB,KAAO8R,EAAU9R,KAAS2R,GAG7C,UAAW1+B,EACfA,EAAQg/B,MAAMrmC,KAAMuG,EAAMojB,GAG1Byc,EAAQxjB,IAAK+G,EAEf,GAGDrkB,OAAOG,GAAG2B,OAAQ,CAGjBw+B,OAAQ,SAAUv+B,GAGjB,GAAK3S,UAAUnD,OACd,YAAmBgH,IAAZ8O,EACNvD,KACAA,KAAKsC,MAAM,SAAU/U,GACpBiU,OAAOsgC,OAAOC,UAAW/hC,KAAMuD,EAAShW,EACzC,IAGF,IAAIi1C,EAAMC,EACThgC,EAAOzC,KAAM,GAEd,OAAMyC,EAQAA,EAAKktB,iBAAiBliC,QAK5B+0C,EAAO//B,EAAK2tB,wBACZqS,EAAMhgC,EAAKrM,cAAc6V,YAClB,CACNC,IAAKs2B,EAAKt2B,IAAMu2B,EAAIC,YACpBpS,KAAMkS,EAAKlS,KAAOmS,EAAIE,cARf,CAAEz2B,IAAK,EAAGokB,KAAM,QATxB,CAmBD,EAIA9D,SAAU,WACT,GAAMxsB,KAAM,GAAZ,CAIA,IAAI4iC,EAAcd,EAAQvmC,EACzBkH,EAAOzC,KAAM,GACb6iC,EAAe,CAAE32B,IAAK,EAAGokB,KAAM,GAGhC,GAAwC,UAAnC9uB,OAAOsd,IAAKrc,EAAM,YAGtBq/B,EAASr/B,EAAK2tB,4BAER,CAON,IANA0R,EAAS9hC,KAAK8hC,SAIdvmC,EAAMkH,EAAKrM,cACXwsC,EAAengC,EAAKmgC,cAAgBrnC,EAAIK,gBAChCgnC,IACLA,IAAiBrnC,EAAIM,MAAQ+mC,IAAiBrnC,EAAIK,kBACT,WAA3C4F,OAAOsd,IAAK8jB,EAAc,aAE1BA,EAAeA,EAAahoC,WAExBgoC,GAAgBA,IAAiBngC,GAAkC,IAA1BmgC,EAAa9tC,YAG1D+tC,EAAerhC,OAAQohC,GAAed,UACzB51B,KAAO1K,OAAOsd,IAAK8jB,EAAc,kBAAkB,GAChEC,EAAavS,MAAQ9uB,OAAOsd,IAAK8jB,EAAc,mBAAmB,GAEpE,CAGA,MAAO,CACN12B,IAAK41B,EAAO51B,IAAM22B,EAAa32B,IAAM1K,OAAOsd,IAAKrc,EAAM,aAAa,GACpE6tB,KAAMwR,EAAOxR,KAAOuS,EAAavS,KAAO9uB,OAAOsd,IAAKrc,EAAM,cAAc,GArCzE,CAuCD,EAYAmgC,aAAc,WACb,OAAO5iC,KAAKwC,KAAK,WAGhB,IAFA,IAAIogC,EAAe5iC,KAAK4iC,aAEhBA,GAA2D,WAA3CphC,OAAOsd,IAAK8jB,EAAc,aACjDA,EAAeA,EAAaA,aAG7B,OAAOA,GAAgBhnC,CACxB,GACD,IAID4F,OAAOc,KAAM,CAAEivB,WAAY,cAAeD,UAAW,gBAAiB,SAAU7Z,EAAQ9lB,GACvF,IAAIua,EAAM,gBAAkBva,EAE5B6P,OAAOG,GAAI8V,GAAW,SAAUrW,GAC/B,OAAOya,OAAQ7b,MAAM,SAAUyC,EAAMgV,EAAQrW,GAG5C,IAAIqhC,EAOJ,GANK7hC,EAAU6B,GACdggC,EAAMhgC,EACuB,IAAlBA,EAAK3N,WAChB2tC,EAAMhgC,EAAKwJ,kBAGCxX,IAAR2M,EACJ,OAAOqhC,EAAMA,EAAK9wC,GAAS8Q,EAAMgV,GAG7BgrB,EACJA,EAAIK,SACF52B,EAAYu2B,EAAIE,YAAVvhC,EACP8K,EAAM9K,EAAMqhC,EAAIC,aAIjBjgC,EAAMgV,GAAWrW,CAEnB,GAAGqW,EAAQrW,EAAKxQ,UAAUnD,OAC3B,CACD,IAQA+T,OAAOc,KAAM,CAAE,MAAO,SAAU,SAAU2C,EAAItT,GAC7C6P,OAAOsuB,SAAUn+B,GAAS+5B,aAAcjrB,EAAQysB,eAC/C,SAAUzqB,EAAM2oB,GACf,GAAKA,EAIJ,OAHAA,EAAWD,OAAQ1oB,EAAM9Q,GAGlBi5B,GAAUv6B,KAAM+6B,GACtB5pB,OAAQiB,GAAO+pB,WAAY76B,GAAS,KACpCy5B,CAEH,GAEF,IAIA5pB,OAAOc,KAAM,CAAEygC,OAAQ,SAAUC,MAAO,UAAW,SAAU/nC,EAAM6F,GAClEU,OAAOc,KAAM,CACZkuB,QAAS,QAAUv1B,EACnB9E,QAAS2K,EACT,GAAI,QAAU7F,IACZ,SAAUgoC,EAAcC,GAG1B1hC,OAAOG,GAAIuhC,GAAa,SAAU3S,EAAQz+B,GACzC,IAAIgqB,EAAYlrB,UAAUnD,SAAYw1C,GAAkC,kBAAX1S,GAC5DlB,EAAQ4T,KAA6B,IAAX1S,IAA6B,IAAVz+B,EAAiB,SAAW,UAE1E,OAAO+pB,OAAQ7b,MAAM,SAAUyC,EAAM3B,EAAMhP,GAC1C,IAAIyJ,EAEJ,OAAKqF,EAAU6B,GAGyB,IAAhCygC,EAASlzC,QAAS,SACxByS,EAAM,QAAUxH,GAChBwH,EAAK9O,SAASiI,gBAAiB,SAAWX,GAIrB,IAAlBwH,EAAK3N,UACTyG,EAAMkH,EAAK7G,gBAIJkI,KAAKgrB,IACXrsB,EAAK5G,KAAM,SAAWZ,GAAQM,EAAK,SAAWN,GAC9CwH,EAAK5G,KAAM,SAAWZ,GAAQM,EAAK,SAAWN,GAC9CM,EAAK,SAAWN,UAIDxG,IAAV3C,EAGN0P,OAAOsd,IAAKrc,EAAM3B,EAAMuuB,GAGxB7tB,OAAOod,MAAOnc,EAAM3B,EAAMhP,EAAOu9B,EACnC,GAAGvuB,EAAMgb,EAAYyU,OAAS97B,EAAWqnB,EAC1C,CACD,GACD,IAGAta,OAAOc,KAAM,CACZ,YACA,WACA,eACA,YACA,cACA,aACE,SAAU2C,EAAInE,GAChBU,OAAOG,GAAIb,GAAS,SAAUa,GAC7B,OAAO3B,KAAKoiB,GAAIthB,EAAMa,EACvB,CACD,IAKAH,OAAOG,GAAG2B,OAAQ,CAEjBvU,KAAM,SAAUszB,EAAOnlB,EAAMyE,GAC5B,OAAO3B,KAAKoiB,GAAIC,EAAO,KAAMnlB,EAAMyE,EACpC,EACAwhC,OAAQ,SAAU9gB,EAAO1gB,GACxB,OAAO3B,KAAKyiB,IAAKJ,EAAO,KAAM1gB,EAC/B,EAEAyhC,SAAU,SAAU3hC,EAAU4gB,EAAOnlB,EAAMyE,GAC1C,OAAO3B,KAAKoiB,GAAIC,EAAO5gB,EAAUvE,EAAMyE,EACxC,EACA0hC,WAAY,SAAU5hC,EAAU4gB,EAAO1gB,GAGtC,OAA4B,IAArB/Q,UAAUnD,OAChBuS,KAAKyiB,IAAKhhB,EAAU,MACpBzB,KAAKyiB,IAAKJ,EAAO5gB,GAAY,KAAME,EACrC,EAEA2hC,MAAO,SAAUC,EAAQC,GACxB,OAAOxjC,KAAKioB,WAAYsb,GAASrb,WAAYsb,GAASD,EACvD,IAGD/hC,OAAOc,KACN,wLAE4D0C,MAAO,MACnE,SAAUC,EAAIhK,GAGbuG,OAAOG,GAAI1G,GAAS,SAAUiC,EAAMyE,GACnC,OAAO/Q,UAAUnD,OAAS,EACzBuS,KAAKoiB,GAAInnB,EAAM,KAAMiC,EAAMyE,GAC3B3B,KAAKkjB,QAASjoB,EAChB,CACD,IAQD,IAAIoM,GAAQ,qCAMZ7F,OAAOiiC,MAAQ,SAAU9hC,EAAID,GAC5B,IAAIkL,EAAKle,EAAM+0C,EAUf,GARwB,iBAAZ/hC,IACXkL,EAAMjL,EAAID,GACVA,EAAUC,EACVA,EAAKiL,GAKAlM,EAAYiB,GAalB,OARAjT,EAAOyR,EAAMjE,KAAMtL,UAAW,GAC9B6yC,EAAQ,WACP,OAAO9hC,EAAGrT,MAAOoT,GAAW1B,KAAMtR,EAAKM,OAAQmR,EAAMjE,KAAMtL,YAC5D,EAGA6yC,EAAM1+B,KAAOpD,EAAGoD,KAAOpD,EAAGoD,MAAQvD,OAAOuD,OAElC0+B,CACR,EAEAjiC,OAAOkiC,UAAY,SAAUC,GACvBA,EACJniC,OAAOia,YAEPja,OAAOmU,OAAO,EAEhB,EACAnU,OAAOlU,QAAUD,MAAMC,QACvBkU,OAAOoiC,UAAYrmB,KAAKC,MACxBhc,OAAO9E,SAAWA,SAClB8E,OAAOd,WAAaA,EACpBc,OAAOZ,SAAWA,EAClBY,OAAOgb,UAAYA,UACnBhb,OAAOV,KAAOS,OAEdC,OAAO0kB,IAAMhgB,KAAKggB,IAElB1kB,OAAOqiC,UAAY,SAAUzwC,GAK5B,IAAI0N,EAAOU,OAAOV,KAAM1N,GACxB,OAAkB,WAAT0N,GAA8B,WAATA,KAK5BgjC,MAAO1wC,EAAMy5B,WAAYz5B,GAC5B,EAEAoO,OAAOtR,KAAO,SAAUmC,GACvB,OAAe,MAARA,EACN,IACEA,EAAO,IAAKvC,QAASuX,GAAO,GAChC,OAoBE,KAFqB,EAAF,WACnB,OAAO7F,MACP,UAFiB,OAEjB,aAMF,IAGCuiC,GAAUvwC,EAAOgO,OAGjBwiC,GAAKxwC,EAAOywC,EAwBb,OAtBAziC,OAAO0iC,WAAa,SAAUvgC,GAS7B,OARKnQ,EAAOywC,IAAMziC,SACjBhO,EAAOywC,EAAID,IAGPrgC,GAAQnQ,EAAOgO,SAAWA,SAC9BhO,EAAOgO,OAASuiC,IAGVviC,MACR,OAKyB,IAAbvB,IACXzM,EAAOgO,OAAShO,EAAOywC,EAAIziC,QAMrBA,MACP,MC/nVI2iC,EAA2B,CAAC,EAGhC,SAASC,oBAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqB5vC,IAAjB6vC,EACH,OAAOA,EAAap3C,QAGrB,IAAID,EAASk3C,EAAyBE,GAAY,CAGjDn3C,QAAS,CAAC,GAOX,OAHAq3C,EAAoBF,GAAUnoC,KAAKjP,EAAOC,QAASD,EAAQA,EAAOC,QAASk3C,qBAGpEn3C,EAAOC,OACf,CCrBAk3C,oBAAoBnvB,EAAKhoB,IACxB,IAAIwpC,EAASxpC,GAAUA,EAAOu3C,WAC7B,IAAOv3C,EAAiB,QACxB,IAAM,EAEP,OADAm3C,oBAAoBK,EAAEhO,EAAQ,CAAE7vB,EAAG6vB,IAC5BA,CAAM,ECLd2N,oBAAoBK,EAAI,CAACv3C,EAASw3C,KACjC,IAAI,IAAIl6B,KAAOk6B,EACXN,oBAAoBO,EAAED,EAAYl6B,KAAS45B,oBAAoBO,EAAEz3C,EAASsd,IAC5E5c,OAAOkvB,eAAe5vB,EAASsd,EAAK,CAAE6a,YAAY,EAAMxzB,IAAK6yC,EAAWl6B,IAE1E,ECND45B,oBAAoBO,EAAI,CAACvxC,EAAKzB,IAAU/D,OAAOkB,UAAUnB,eAAeuO,KAAK9I,EAAKzB,gFCAnE,MAAMizC,aACjBvxC,YAAYwxC,GACR7kC,KAAKrL,KAAOkwC,EACZ7kC,KAAKmlB,OAAS93B,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,0BACpDpK,KAAK8kC,KAAOz3C,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,wBAClDpK,KAAK+kC,qBACT,CACAA,sBACI/kC,KAAKmlB,OAAOh2B,SAAS61C,IACjBA,EAAc74B,iBAAiB,QAASnM,KAAKggB,OAAOjxB,KAAKiR,MAAM,GAEvE,CACAggB,OAAOilB,GACHjlC,KAAKklC,mBACLllC,KAAKrL,KAAKwwC,UAAUnlB,OAAO,qBAC/B,CACAklB,mBACI,MAAME,EAAWplC,KAAKrL,KAAK0wC,cAAc,oBACnCC,EAAYtlC,KAAKrL,KAAK0wC,cAAc,kBACtCD,GACAA,EAASD,UAAUr1C,QAAQ,kBAAmB,iBAE9Cw1C,GACAA,EAAUH,UAAUr1C,QAAQ,gBAAiB,kBAErD,ECzBW,MAAMy1C,WACjBlyC,YAAYwxC,EAAOW,EAAmBC,EAAgBC,GAClD1lC,KAAKrL,KAAOkwC,EACZ7kC,KAAKkjB,QAAU71B,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiBo7B,IACrDxlC,KAAK2lC,cAAgBF,EACrBzlC,KAAK+kC,sBACL/kC,KAAK4lC,WAAWF,EACpB,CACAX,sBACI/kC,KAAKkjB,QAAQ/zB,SAAS61C,IAClBA,EAAc74B,iBAAiB,QAASnM,KAAKggB,OAAOjxB,KAAKiR,MAAM,GAEvE,CACA4lC,WAAWF,GACQ1lC,KAAKrL,KAAK0wC,cAAc,mBAChCxoC,aAAa,gBAAiBpN,OAAOi2C,IACxCA,IAEA1lC,KAAKrL,KAAKwwC,UAAU5uB,IAAI,aACxBvW,KAAKklC,mBAEb,CACAllB,SACIhgB,KAAKklC,mBACLllC,KAAKrL,KAAKwwC,UAAUnlB,OAAO,aAC3BhgB,KAAK6lC,sBACT,CACAA,uBACI,MAAMC,EAAS9lC,KAAKrL,KAAK0wC,cAAc,mBACjCzU,EAAW5wB,KAAKrL,KAAKwwC,UAAUl/B,SAAS,aAE9C,GADA6/B,EAAOjpC,aAAa,gBAAiBpN,OAAOmhC,IACV,mBAAvB5wB,KAAK2lC,cAA8B,CAC1C,MAAMI,EAAc/lC,KAAKrL,KAAKV,aAAa,YAC3C+L,KAAK2lC,cAAcI,EAAanV,EACpC,CACJ,CACAsU,mBACI,MAAME,EAAWplC,KAAKrL,KAAK0wC,cAAc,2BACnCC,EAAYtlC,KAAKrL,KAAK0wC,cAAc,yBACtCD,GACAA,EAASD,UAAUr1C,QAAQ,yBAA0B,wBAErDw1C,GACAA,EAAUH,UAAUr1C,QAAQ,uBAAwB,yBAE5D,EC7CJ,MACA,aADegC,GAAUA,QCazB,gCAZiC,CAACq3B,EAAY6c,IACtC,aAAM7c,GACC,KAEJ6c,EAAKhhC,MAAM,KAAKihC,QAAO,CAACn0C,EAAOukB,IAC9B,aAAMvkB,GACC,KAGJA,EAAMukB,IACd8S,GC4BP,8BAvB+B,CAACA,EAAY6c,EAAMl0C,KAC9Cq3B,EAAmC,iBAAfA,EAA0BA,EAAa,CAAC,EAC5D,MAAM7e,EAAOjd,MAAMC,QAAQ04C,GAAQA,EAAOA,EAAKhhC,MAAM,KACrD,IAAIkhC,EAAc/c,EAClB,IAAK,IAAI57B,EAAI,EAAGA,EAAI+c,EAAK7c,OAAS,EAAGF,IAAK,CACtC,MAAMid,EAAMF,EAAK/c,GACjB,IAEC24C,EAAY17B,KACR5c,OAAOkB,UAAUnB,eAAeuO,KAAKgqC,EAAa17B,GAAM,CACzD,MAAM27B,EAAU77B,EAAK/c,EAAI,GACnB64C,EAAW,oBAAoB/1C,KAAK81C,GAE1CD,EAAY17B,GAAO47B,EAAW,GAAK,CAAC,CACxC,CAEAF,EAAcA,EAAY17B,EAC9B,CAIA,OADA07B,EAFkB57B,EAAKA,EAAK7c,OAAS,IAEZqE,EAClBq3B,CAAU,EC/Bfkd,EAAc,iBAEdC,WAAa,KACjB,MAAMC,EAAUC,aAAaC,QAAQJ,GAC/BK,EAAcnpB,KAAKC,MAAM+oB,GAC/B,OAAOI,aAAMD,GAAe,CAAC,EAAIA,CAAjC,EAGIE,gBAAmBZ,IACvB,MAAMO,EAAUD,aAEhB,OADoBO,gCAAyBN,EAASP,EACtD,EAGIc,gBAAkB,CAACd,EAAMl0C,KAC7B,MAAMy0C,EAAUD,aACVS,EAAqBC,8BAAuBT,EAASP,EAAMl0C,GAC5D60C,aAAMI,IACTP,aAAaS,QAAQZ,EAAa9oB,KAAK2pB,UAAUH,GAClD,ECvBGI,EAAa,gCACJ,MAAMC,UACjB/zC,YAAYwxC,GACR7kC,KAAKrL,KAAOkwC,EACZ7kC,KAAKmlB,OAAS93B,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,sBACpDpK,KAAKqnC,MAAQh6C,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,qBACnDpK,KAAKsnC,kBAAoBtnC,KAAKunC,wBAC9BvnC,KAAK+kC,sBACD/kC,KAAKqnC,OACLrnC,KAAKwnC,wBAEb,CACAA,yBACIxnC,KAAKqnC,MAAMl4C,SAASs4C,IAChB,MAAMC,EAAsBD,EAAOr9B,iBAAiB,sBAC9Cu9B,EAAW3nC,KAAKsnC,kBACtBI,EAAoBv4C,SAASy4C,IACzB,MAAM7B,EAAc6B,EAAmB3zC,aAAa,YAC9C4zC,GAAgBF,EAASG,SAAS/B,GACxC,IAAIR,WAAWqC,EAAoB,0BAA2B5nC,KAAK+nC,yBAAyBh5C,KAAKiR,MAAO6nC,EAAa,GACvH,GAEV,CACA9C,sBACI/kC,KAAKmlB,OAAOh2B,SAAS61C,IACjBA,EAAc74B,iBAAiB,QAASnM,KAAKggB,OAAOjxB,KAAKiR,MAAM,GAEvE,CACAunC,wBACI,MAAMS,EAAcpB,gBAAgBO,GACpC,OAAO95C,MAAMC,QAAQ06C,GAAeA,EAAc,EACtD,CACAC,wBACQ56C,MAAMC,QAAQ0S,KAAKsnC,oBACnBR,gBAAgBK,EAAYnnC,KAAKsnC,kBAEzC,CACAS,yBAAyBhC,EAAamC,GAC9BloC,KAAKsnC,kBAAkBQ,SAAS/B,KAA6B,IAAbmC,IAChDloC,KAAKsnC,kBAAoBtnC,KAAKsnC,kBAAkB76B,QAAQ9L,GAASA,IAASolC,KAEzE/lC,KAAKsnC,kBAAkBQ,SAAS/B,KAA6B,IAAbmC,GACjDloC,KAAKsnC,kBAAkB/3C,KAAKw2C,GAEhC/lC,KAAKioC,uBACT,CACAjoB,OAAOilB,GACHjlC,KAAKmlB,OAAOh2B,SAAS61C,IACjBA,EAAcG,UAAUnlB,OAAO,eAAe,IAElDrsB,SAASkI,KAAKspC,UAAUnlB,OAAO,uBACnC,ECnDJ,MAAMmoB,GAAoBxB,aAAMnzC,OAAO40C,SAASC,eAgChD,mBA9Ba,KACP1B,aAAMnzC,OAAO40C,WACf50C,OAAO40C,QAAU,CAAC,GAGhBzB,aAAMnzC,OAAO40C,QAAQC,iBACvB70C,OAAO40C,QAAQC,cAAgB,CAAC,GAIlC,MAAMC,EAAY30C,SAAS0xC,cAAc,0BACpCsB,aAAM2B,KACT90C,OAAO40C,QAAQC,cAAcE,SAAWD,EAAUr0C,aAAa,QAChE,EAiBH,kBAdauW,GACN29B,EAIEtB,gCAAyBrzC,OAAO40C,QAAQC,cAAe79B,GAHrD,+DCrBX,MAUA,eAViBjZ,GACS,iBAAXA,EACkB,IAAlBA,EAAO9D,SAEd,aAAM8D,KAGD3D,OAAO46C,sBAAsBj3C,GAAQ9D,SACzCG,OAAO66C,oBAAoBl3C,GAAQ9D,OCRtCi7C,EAAY,CACdzkC,MAAO,QACP0kC,KAAM,OACNC,GAAI,UACJC,QAAS,UACTC,OAAQ,QCFG,MAAMC,QACjB11C,YAAY21C,EAAUC,GAClBjpC,KAAKmb,QAAU,KACfnb,KAAK8rB,UAAYmd,EACjBjpC,KAAKuD,QAAUylC,EACfhpC,KAAK4lC,aACL5lC,KAAK+kC,qBACT,CACAa,aACI,MAAMsD,EAAehjC,KAAKggB,MACpBijB,EAAYrlC,KAAKslC,MAAMF,EAAe,MACtC,MAAEG,EAAK,QAAEluB,EAAO,KAAEra,EAAI,YAAEwoC,GAAgBtpC,KAAKuD,QAG7CgmC,EDVU,EAACzoC,EAAMuoC,EAAOluB,EAASquB,KAC3C,MAAMC,GAAc,eAAQtuB,GACtByc,EAAa,CAAC,6BACd0R,GAAe,aAAME,IAAUA,EAC/B,iDACA,GACN,IAAIE,EAAc,GAKlB,OAJID,IACAC,EAAc,oCAAoCvuB,UAClDyc,EAAWroC,KAAK,eAEb,yDACyCm5C,EAAU5nC,gCACxC4nC,EAAU5nC,mBAC3BwoC,wBACY1R,EAAWztB,KAAK,0DACYk/B,oBACvCK,iCAGJ,ECV4BC,CAAgB7oC,EAFhB,aAAmBuoC,GACjB,aAAmBluB,GACiCmuB,GACtEM,EAAwBj2C,SAASuC,cAAc,OACrD0zC,EAAsBtsC,UAAYisC,EAClC,MAAMM,EAAiBD,EAAsB9tC,kBAC7C+tC,EAAehgC,GAAK,6BAA+Bs/B,EACnDnpC,KAAKmb,QAAU0uB,EACf7pC,KAAK8rB,UAAU/sB,YAAY8qC,GAC3B7pC,KAAK8pC,oBAAoBD,GACzB7pC,KAAK+pC,uBAAuBF,EAChC,CACAE,uBAAuB5uB,GACnB,MAAM6uB,EAAiB7uB,EAAQkqB,cAAc,+BACxC,aAAM2E,IACPA,EAAe7E,UAAUl/B,SAAS,eAClC+jC,EAAe79B,iBAAiB,QAASnM,KAAKggB,OAAOjxB,KAAKiR,MAElE,CACA8pC,oBAAoB3uB,GAChB,MAAMmuB,EAAcnuB,EAAQkqB,cAAc,sBACrC,aAAMiE,IACPA,EAAYn9B,iBAAiB,QAASnM,KAAKwpC,MAAMz6C,KAAKiR,MAE9D,CACA+kC,sBACI,MAAMjP,EAAU91B,KAAKuD,QAAQuyB,QACzBA,EAAU,GACVtb,WAAWxa,KAAKwpC,MAAMz6C,KAAKiR,MAAO81B,EAE1C,CACA0T,QACS,aAAMxpC,KAAKmb,WACZnb,KAAKmb,QAAQgqB,UAAU5uB,IAAI,YAC3BiE,YAAW,KACPxa,KAAKmb,QAAQpgB,QAAQ,GACtB,KAEX,CACAilB,SACI,GAAI,aAAMhgB,KAAKmb,SACX,OAEJ,MAAM6uB,EAAiBhqC,KAAKmb,QAAQkqB,cAAc,8BAC7C,aAAM2E,IACPA,EAAe7E,UAAUnlB,OAAO,WAExC,EC7DJ,MAAMiqB,EAAiB,CACnBzd,SAAU,wBACVsJ,QAAS,IACTh1B,KAAM,QAEK,MAAMopC,MACjB72C,cACI2M,KAAK8rB,UAAYn4B,SAASiW,eAAe,+BACzC5J,KAAK4lC,YACT,CACAA,aACI,GAAI,aAAM5lC,KAAK8rB,WAAY,CACvB,MAAMqe,EAAuBx2C,SAASiW,eAAe,oBAChD,aAAMugC,KACPnqC,KAAK8rB,UAAYn4B,SAASuC,cAAc,OACxC8J,KAAK8rB,UAAUjiB,GAAK,8BACpBsgC,EAAqBprC,YAAYiB,KAAK8rB,WAE9C,CACJ,CAOA39B,OAAOoV,GACH,MAAM6mC,EAAex8C,OAAOy8C,OAAOz8C,OAAOy8C,OAAO,CAAC,EAAGJ,GAAiB1mC,GACjE,aAAM6mC,EAAa5d,WACpBxsB,KAAK8rB,UAAUqZ,UAAU5uB,IAAI6zB,EAAa5d,UAE9C,IAAIuc,QAAQqB,EAAcpqC,KAAK8rB,UACnC,CAOAwe,cAAc/mC,GAEV,GAAI,aAAMvD,KAAKipC,YAAa,EACV,IAAIiB,OACZ/7C,OAAOoV,EACjB,MAGIvD,KAAKuqC,QAAQhnC,EAErB,CAMA+mC,mBAEqBj9C,MAAMK,KAAKsS,KAAKipC,WAAWhtC,YACnC9M,SAAS06C,IACT,aAAMA,KACPA,EAAe1E,UAAU5uB,IAAI,YAC7BiE,YAAW,KACPqvB,EAAe9uC,QAAQ,GACxB,KACP,GAER,ECjEJ,MAAMyvC,EAAe,CAAC,KAAM,OAAQ,SAAU,UAAW,SAEnDC,oBAAsB,CAACpB,EAAOluB,EAASra,EAAM4pC,KACjD,MAAMnnC,EAAU,CAAE8lC,MAAOA,EAAOluB,QAASA,KAAYuvB,GACjDF,EAAa1C,SAAShnC,KACxByC,EAAQzC,KAAOA,GAGjBopC,MAAM/7C,OAAOoV,EAAb,EASIqlC,GAAMS,IACVoB,oBAAoBpB,EAAO,GAAI,KAA/B,EASIV,KAAQU,IACZoB,oBAAoBpB,EAAO,GAAI,OAA/B,EASIP,OAAUO,IACdoB,oBAAoBpB,EAAO,GAAI,SAA/B,EAUIR,QAAU,CAACQ,EAAOluB,KACtBsvB,oBAAoBpB,EAAOluB,EAAS,UAAW,CAC7C2a,QAAS,EACTwT,aAAa,GAFf,EAaIrlC,MAAQ,CAAColC,EAAOluB,KACpBsvB,oBAAoBpB,EAAOluB,EAAS,QAAS,CAC3C2a,QAAS,EACTwT,aAAa,GAFf,EAWIqB,MAAQ,KACZT,MAAMU,WAAN,EAGIhpC,kBAAO,KACP+kC,aAAMnzC,OAAO40C,WACf50C,OAAO40C,QAAU,CAAC,GAGhBzB,aAAMnzC,OAAO40C,QAAQyC,gBACvBr3C,OAAO40C,QAAQyC,aAAe,CAC5BjpC,KAAMA,kBACNgnC,GACAD,KACAG,OACAD,QACA5kC,MACA0mC,QAIkBt9C,MAAMK,KAC1BiG,SAASyW,iBAAiB,kCAEdjb,SAAS27C,IACrB,MAAMhqC,EAAOgqC,EAAoB72C,aAAa,aACxCo1C,EAAQyB,EAAoBnuC,YAElC8tC,oBAAoBpB,EAAO,GAAIvoC,EAA/B,GAJF,EAQF,GAAiBc,KAAF,kBAAQgnC,GAAID,KAAMG,OAAQD,QAAS5kC,MAAO0mC,OC7G1C,SAAS13C,QAAQG,GAa9B,OATEH,QADoB,mBAAXC,QAAoD,iBAApBA,OAAOC,SACtC,SAASF,QAAQG,GACzB,cAAcA,CAChB,EAEU,SAASH,QAAQG,GACzB,OAAOA,GAAyB,mBAAXF,QAAyBE,EAAIC,cAAgBH,QAAUE,IAAQF,OAAOpE,UAAY,gBAAkBsE,CAC3H,EAGKH,QAAQG,EACjB,CCde,SAAS23C,gBAAgB33C,EAAKoX,EAAK1Y,GAYhD,OAXI0Y,KAAOpX,EACTxF,OAAOkvB,eAAe1pB,EAAKoX,EAAK,CAC9B1Y,MAAOA,EACPuzB,YAAY,EACZtI,cAAc,EACdwI,UAAU,IAGZnyB,EAAIoX,GAAO1Y,EAGNsB,CACT,CCZe,SAAS43C,cAActnC,GACpC,IAAK,IAAInW,EAAI,EAAGA,EAAIqD,UAAUnD,OAAQF,IAAK,CACzC,IAAI8wB,EAAyB,MAAhBztB,UAAUrD,GAAaK,OAAOgD,UAAUrD,IAAM,CAAC,EACxD09C,EAAUr9C,OAAO0c,KAAK+T,GAEkB,mBAAjCzwB,OAAO46C,wBAChByC,EAAUA,EAAQj8C,OAAOpB,OAAO46C,sBAAsBnqB,GAAQ5R,QAAO,SAAUy+B,GAC7E,OAAOt9C,OAAOI,yBAAyBqwB,EAAQ6sB,GAAK7lB,UACtD,MAGF4lB,EAAQ97C,SAAQ,SAAUqb,GACxB,gBAAe9G,EAAQ8G,EAAK6T,EAAO7T,GACrC,GACF,CAEA,OAAO9G,CACT,CClBe,SAASynC,gBAAgBC,EAAUC,GAChD,KAAMD,aAAoBC,GACxB,MAAM,IAAI76C,UAAU,oCAExB,CCJA,SAAS86C,kBAAkB5nC,EAAQmiB,GACjC,IAAK,IAAIt4B,EAAI,EAAGA,EAAIs4B,EAAMp4B,OAAQF,IAAK,CACrC,IAAIg+C,EAAa1lB,EAAMt4B,GACvBg+C,EAAWlmB,WAAakmB,EAAWlmB,aAAc,EACjDkmB,EAAWxuB,cAAe,EACtB,UAAWwuB,IAAYA,EAAWhmB,UAAW,GACjD33B,OAAOkvB,eAAepZ,EAAQ6nC,EAAW/gC,IAAK+gC,EAChD,CACF,CAEe,SAASC,aAAaH,EAAaI,EAAYC,GAG5D,OAFID,GAAYH,kBAAkBD,EAAYv8C,UAAW28C,GACrDC,GAAaJ,kBAAkBD,EAAaK,GACzCL,CACT,CCde,SAASM,uBAAuBn2B,GAC7C,QAAa,IAATA,EACF,MAAM,IAAIo2B,eAAe,6DAG3B,OAAOp2B,CACT,CCJe,SAASq2B,2BAA2Br2B,EAAMtZ,GACvD,OAAIA,GAA2B,WAAlBjJ,QAAQiJ,IAAsC,mBAATA,EAI3C,uBAAsBsZ,GAHpBtZ,CAIX,CCRe,SAAS4vC,gBAAgBnH,GAItC,OAHAmH,gBAAkBl+C,OAAOC,eAAiBD,OAAOG,eAAiB,SAAS+9C,gBAAgBnH,GACzF,OAAOA,EAAEoH,WAAan+C,OAAOG,eAAe42C,EAC9C,EACOmH,gBAAgBnH,EACzB,CCLe,SAASqH,gBAAgBrH,EAAGlT,GAMzC,OALAua,gBAAkBp+C,OAAOC,gBAAkB,SAASm+C,gBAAgBrH,EAAGlT,GAErE,OADAkT,EAAEoH,UAAYta,EACPkT,CACT,EAEOqH,gBAAgBrH,EAAGlT,EAC5B,CCNe,SAASwa,UAAUC,EAAUC,GAC1C,GAA0B,mBAAfA,GAA4C,OAAfA,EACtC,MAAM,IAAI37C,UAAU,sDAGtB07C,EAASp9C,UAAYlB,OAAOO,OAAOg+C,GAAcA,EAAWr9C,UAAW,CACrEuE,YAAa,CACXvB,MAAOo6C,EACP3mB,UAAU,EACVxI,cAAc,KAGdovB,GAAY,gBAAeD,EAAUC,EAC3C,CCLA,IAAIC,EAAgB,CAClBtrC,KAAM,SACNurC,IAAK,SAASA,IAAI39C,GAChBsR,KAAKssC,OAAO,MAAO59C,EACrB,EACA6F,KAAM,SAASA,KAAK7F,GAClBsR,KAAKssC,OAAO,OAAQ59C,EACtB,EACAuV,MAAO,SAASA,MAAMvV,GACpBsR,KAAKssC,OAAO,QAAS59C,EACvB,EACA49C,OAAQ,SAASA,OAAOxrC,EAAMpS,GACxB4F,SAAWA,QAAQwM,IAAOxM,QAAQwM,GAAMxS,MAAMgG,QAAS5F,EAC7D,GAiFE69C,EAAa,IA9EJ,WACX,SAASC,OAAOC,GACd,IAAIlpC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAEnFu6C,gBAAgBnrC,KAAMwsC,QAEtBxsC,KAAK4B,KAAK6qC,EAAgBlpC,EAC5B,CAoEA,OAlEAioC,aAAagB,OAAQ,CAAC,CACpBhiC,IAAK,OACL1Y,MAAO,SAAS8P,KAAK6qC,GACnB,IAAIlpC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EACnFoP,KAAK0wB,OAASntB,EAAQmtB,QAAU,WAChC1wB,KAAK0sC,OAASD,GAAkBL,EAChCpsC,KAAKuD,QAAUA,EACfvD,KAAK2sC,MAAQppC,EAAQopC,KACvB,GACC,CACDniC,IAAK,WACL1Y,MAAO,SAAS86C,SAASrW,GACvBv2B,KAAK2sC,MAAQpW,CACf,GACC,CACD/rB,IAAK,MACL1Y,MAAO,SAASu6C,MACd,IAAK,IAAI17C,EAAOC,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMsD,GAAOE,EAAO,EAAGA,EAAOF,EAAME,IAC/EnC,EAAKmC,GAAQD,UAAUC,GAGzB,OAAOmP,KAAKoP,QAAQ1gB,EAAM,MAAO,IAAI,EACvC,GACC,CACD8b,IAAK,OACL1Y,MAAO,SAASyC,OACd,IAAK,IAAIzD,EAAQF,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMyD,GAAQC,EAAQ,EAAGA,EAAQD,EAAOC,IACpFrC,EAAKqC,GAASH,UAAUG,GAG1B,OAAOiP,KAAKoP,QAAQ1gB,EAAM,OAAQ,IAAI,EACxC,GACC,CACD8b,IAAK,QACL1Y,MAAO,SAASmS,QACd,IAAK,IAAI4oC,EAAQj8C,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMw/C,GAAQC,EAAQ,EAAGA,EAAQD,EAAOC,IACpFp+C,EAAKo+C,GAASl8C,UAAUk8C,GAG1B,OAAO9sC,KAAKoP,QAAQ1gB,EAAM,QAAS,GACrC,GACC,CACD8b,IAAK,YACL1Y,MAAO,SAASi7C,YACd,IAAK,IAAIC,EAAQp8C,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAM2/C,GAAQC,EAAQ,EAAGA,EAAQD,EAAOC,IACpFv+C,EAAKu+C,GAASr8C,UAAUq8C,GAG1B,OAAOjtC,KAAKoP,QAAQ1gB,EAAM,OAAQ,wBAAwB,EAC5D,GACC,CACD8b,IAAK,UACL1Y,MAAO,SAASsd,QAAQ1gB,EAAMw+C,EAAKxc,EAAQyc,GACzC,OAAIA,IAAcntC,KAAK2sC,MAAc,MACd,iBAAZj+C,EAAK,KAAiBA,EAAK,GAAK,GAAGM,OAAO0hC,GAAQ1hC,OAAOgR,KAAK0wB,OAAQ,KAAK1hC,OAAON,EAAK,KAC3FsR,KAAK0sC,OAAOQ,GAAKx+C,GAC1B,GACC,CACD8b,IAAK,SACL1Y,MAAO,SAAS3D,OAAOi/C,GACrB,OAAO,IAAIZ,OAAOxsC,KAAK0sC,OAAQ1B,cAAc,CAAC,EAAG,CAC/Cta,OAAQ,GAAG1hC,OAAOgR,KAAK0wB,OAAQ,KAAK1hC,OAAOo+C,EAAY,MACtDptC,KAAKuD,SACV,KAGKipC,MACT,CA5Ea,IAgFTa,EAAe,WACjB,SAASA,eACPlC,gBAAgBnrC,KAAMqtC,cAEtBrtC,KAAKstC,UAAY,CAAC,CACpB,CAoDA,OAlDA9B,aAAa6B,aAAc,CAAC,CAC1B7iC,IAAK,KACL1Y,MAAO,SAASswB,GAAGkB,EAAQiqB,GACzB,IAAIC,EAAQxtC,KAOZ,OALAsjB,EAAOte,MAAM,KAAK7V,SAAQ,SAAUqzB,GAClCgrB,EAAMF,UAAU9qB,GAASgrB,EAAMF,UAAU9qB,IAAU,GAEnDgrB,EAAMF,UAAU9qB,GAAOjzB,KAAKg+C,EAC9B,IACOvtC,IACT,GACC,CACDwK,IAAK,MACL1Y,MAAO,SAAS2wB,IAAID,EAAO+qB,GACpBvtC,KAAKstC,UAAU9qB,KAEf+qB,EAKLvtC,KAAKstC,UAAU9qB,GAASxiB,KAAKstC,UAAU9qB,GAAO/V,QAAO,SAAUtb,GAC7D,OAAOA,IAAMo8C,CACf,WANSvtC,KAAKstC,UAAU9qB,GAO1B,GACC,CACDhY,IAAK,OACL1Y,MAAO,SAAS27C,KAAKjrB,GACnB,IAAK,IAAI7xB,EAAOC,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMsD,EAAO,EAAIA,EAAO,EAAI,GAAIE,EAAO,EAAGA,EAAOF,EAAME,IAClGnC,EAAKmC,EAAO,GAAKD,UAAUC,GAGzBmP,KAAKstC,UAAU9qB,IACJ,GAAGxzB,OAAOgR,KAAKstC,UAAU9qB,IAC/BrzB,SAAQ,SAAUu+C,GACvBA,EAASp/C,WAAM,EAAQI,EACzB,IAGEsR,KAAKstC,UAAU,MACH,GAAGt+C,OAAOgR,KAAKstC,UAAU,MAE/Bn+C,SAAQ,SAAUu+C,GACxBA,EAASp/C,MAAMo/C,EAAU,CAAClrB,GAAOxzB,OAAON,GAC1C,GAEJ,KAGK2+C,YACT,CA1DmB,GA4DnB,SAASlvB,QACP,IAAIwvB,EACAC,EACAl2B,EAAU,IAAIm2B,SAAQ,SAAUv2B,EAASC,GAC3Co2B,EAAMr2B,EACNs2B,EAAMr2B,CACR,IAGA,OAFAG,EAAQJ,QAAUq2B,EAClBj2B,EAAQH,OAASq2B,EACVl2B,CACT,CACA,SAASo2B,WAAWv8C,GAClB,OAAc,MAAVA,EAAuB,GACpB,GAAKA,CACd,CAOA,SAASw8C,cAAcx8C,EAAQy0C,EAAMgI,GACnC,SAASC,SAASzjC,GAChB,OAAOA,GAAOA,EAAIxa,QAAQ,QAAU,EAAIwa,EAAI1a,QAAQ,OAAQ,KAAO0a,CACrE,CAEA,SAAS0jC,uBACP,OAAQ38C,GAA4B,iBAAXA,CAC3B,CAIA,IAFA,IAAI2pB,EAAwB,iBAAT8qB,EAAoB,GAAGh3C,OAAOg3C,GAAQA,EAAKhhC,MAAM,KAE7DkW,EAAMztB,OAAS,GAAG,CACvB,GAAIygD,uBAAwB,MAAO,CAAC,EACpC,IAAI1jC,EAAMyjC,SAAS/yB,EAAMxQ,UACpBnZ,EAAOiZ,IAAQwjC,IAAOz8C,EAAOiZ,GAAO,IAAIwjC,GAG3Cz8C,EADE3D,OAAOkB,UAAUnB,eAAeuO,KAAK3K,EAAQiZ,GACtCjZ,EAAOiZ,GAEP,CAAC,CAEd,CAEA,OAAI0jC,uBAA+B,CAAC,EAC7B,CACL96C,IAAK7B,EACL48C,EAAGF,SAAS/yB,EAAMxQ,SAEtB,CAEA,SAAS0jC,QAAQ78C,EAAQy0C,EAAMkC,GAC7B,IAAImG,EAAiBN,cAAcx8C,EAAQy0C,EAAMp4C,QACvCygD,EAAej7C,IACjBi7C,EAAeF,GAEdjG,CACX,CAUA,SAASoG,QAAQ/8C,EAAQy0C,GACvB,IAAIuI,EAAkBR,cAAcx8C,EAAQy0C,GACxC5yC,EAAMm7C,EAAgBn7C,IACtB+6C,EAAII,EAAgBJ,EAExB,GAAK/6C,EACL,OAAOA,EAAI+6C,EACb,CACA,SAASK,oBAAoBtxC,EAAMuxC,EAAajkC,GAC9C,IAAI1Y,EAAQw8C,QAAQpxC,EAAMsN,GAE1B,YAAc/V,IAAV3C,EACKA,EAGFw8C,QAAQG,EAAajkC,EAC9B,CACA,SAASkkC,WAAWhrC,EAAQ2a,EAAQswB,GAClC,IAAK,IAAIh9C,KAAQ0sB,EACF,cAAT1sB,GAAiC,gBAATA,IACtBA,KAAQ+R,EACkB,iBAAjBA,EAAO/R,IAAsB+R,EAAO/R,aAAiBlC,QAAkC,iBAAjB4uB,EAAO1sB,IAAsB0sB,EAAO1sB,aAAiBlC,OAChIk/C,IAAWjrC,EAAO/R,GAAQ0sB,EAAO1sB,IAErC+8C,WAAWhrC,EAAO/R,GAAO0sB,EAAO1sB,GAAOg9C,GAGzCjrC,EAAO/R,GAAQ0sB,EAAO1sB,IAK5B,OAAO+R,CACT,CACA,SAASkrC,YAAYC,GACnB,OAAOA,EAAI/+C,QAAQ,sCAAuC,OAC5D,CACA,IAAIg/C,EAAa,CACf,IAAK,QACL,IAAK,OACL,IAAK,OACL,IAAK,SACL,IAAK,QACL,IAAK,UAEP,SAAS,eAAO5xC,GACd,MAAoB,iBAATA,EACFA,EAAKpN,QAAQ,cAAc,SAAUypC,GAC1C,OAAOuV,EAAWvV,EACpB,IAGKr8B,CACT,CACA,IAAI6xC,EAA2B,oBAAXv7C,QAA0BA,OAAOw7C,WAAax7C,OAAOw7C,UAAUC,WAAaz7C,OAAOw7C,UAAUC,UAAUj/C,QAAQ,SAAW,EAE1Ik/C,EAAgB,SAAUC,GAG5B,SAASD,cAAchyC,GACrB,IAAIswC,EAEAjqC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAChFw+C,GAAI,CAAC,eACLC,UAAW,eAkBb,OAfAlE,gBAAgBnrC,KAAMkvC,eAEtB1B,EAAQ3B,2BAA2B7rC,KAAM8rC,gBAAgBoD,eAAehzC,KAAK8D,OAEzE+uC,GACF1B,EAAanxC,KAAKyvC,uBAAuB6B,IAG3CA,EAAMtwC,KAAOA,GAAQ,CAAC,EACtBswC,EAAMjqC,QAAUA,OAEmB9O,IAA/B+4C,EAAMjqC,QAAQ+rC,eAChB9B,EAAMjqC,QAAQ+rC,aAAe,KAGxB9B,CACT,CAkIA,OA5JAvB,UAAUiD,cAAeC,GA4BzB3D,aAAa0D,cAAe,CAAC,CAC3B1kC,IAAK,gBACL1Y,MAAO,SAASy9C,cAAcH,GACxBpvC,KAAKuD,QAAQ6rC,GAAGp/C,QAAQo/C,GAAM,GAChCpvC,KAAKuD,QAAQ6rC,GAAG7/C,KAAK6/C,EAEzB,GACC,CACD5kC,IAAK,mBACL1Y,MAAO,SAAS09C,iBAAiBJ,GAC/B,IAAI/4B,EAAQrW,KAAKuD,QAAQ6rC,GAAGp/C,QAAQo/C,GAEhC/4B,GAAS,GACXrW,KAAKuD,QAAQ6rC,GAAG/rC,OAAOgT,EAAO,EAElC,GACC,CACD7L,IAAK,cACL1Y,MAAO,SAAS29C,YAAYC,EAAKN,EAAI5kC,GACnC,IAAIjH,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC/E0+C,OAAwC76C,IAAzB8O,EAAQ+rC,aAA6B/rC,EAAQ+rC,aAAetvC,KAAKuD,QAAQ+rC,aACxFtJ,EAAO,CAAC0J,EAAKN,GAQjB,OAPI5kC,GAAsB,iBAARA,IAAkBw7B,EAAOA,EAAKh3C,OAAOwb,IACnDA,GAAsB,iBAARA,IAAkBw7B,EAAOA,EAAKh3C,OAAOsgD,EAAe9kC,EAAIxF,MAAMsqC,GAAgB9kC,IAE5FklC,EAAI1/C,QAAQ,MAAQ,IACtBg2C,EAAO0J,EAAI1qC,MAAM,MAGZspC,QAAQtuC,KAAK9C,KAAM8oC,EAC5B,GACC,CACDx7B,IAAK,cACL1Y,MAAO,SAAS69C,YAAYD,EAAKN,EAAI5kC,EAAK1Y,GACxC,IAAIyR,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAChFg/C,QAAQ,GAENN,EAAetvC,KAAKuD,QAAQ+rC,kBACX76C,IAAjB66C,IAA4BA,EAAe,KAC/C,IAAItJ,EAAO,CAAC0J,EAAKN,GACb5kC,IAAKw7B,EAAOA,EAAKh3C,OAAOsgD,EAAe9kC,EAAIxF,MAAMsqC,GAAgB9kC,IAEjEklC,EAAI1/C,QAAQ,MAAQ,IAEtB8B,EAAQs9C,EACRA,GAFApJ,EAAO0J,EAAI1qC,MAAM,MAEP,IAGZhF,KAAKuvC,cAAcH,GACnBhB,QAAQpuC,KAAK9C,KAAM8oC,EAAMl0C,GACpByR,EAAQqsC,QAAQ5vC,KAAKytC,KAAK,QAASiC,EAAKN,EAAI5kC,EAAK1Y,EACxD,GACC,CACD0Y,IAAK,eACL1Y,MAAO,SAAS+9C,aAAaH,EAAKN,EAAIU,GACpC,IAAIvsC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAChFg/C,QAAQ,GAGV,IAAK,IAAItmC,KAAKwmC,EACgB,iBAAjBA,EAAUxmC,IAAqE,mBAAlD1b,OAAOkB,UAAU+P,SAASvQ,MAAMwhD,EAAUxmC,KAA0BtJ,KAAK2vC,YAAYD,EAAKN,EAAI9lC,EAAGwmC,EAAUxmC,GAAI,CACrJsmC,QAAQ,IAIPrsC,EAAQqsC,QAAQ5vC,KAAKytC,KAAK,QAASiC,EAAKN,EAAIU,EACnD,GACC,CACDtlC,IAAK,oBACL1Y,MAAO,SAASi+C,kBAAkBL,EAAKN,EAAIU,EAAWnsC,EAAMgrC,GAC1D,IAAIprC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAChFg/C,QAAQ,GAEN5J,EAAO,CAAC0J,EAAKN,GAEbM,EAAI1/C,QAAQ,MAAQ,IAEtB2T,EAAOmsC,EACPA,EAAYV,EACZA,GAHApJ,EAAO0J,EAAI1qC,MAAM,MAGP,IAGZhF,KAAKuvC,cAAcH,GACnB,IAAIY,EAAO1B,QAAQtuC,KAAK9C,KAAM8oC,IAAS,CAAC,EAEpCriC,EACF+qC,WAAWsB,EAAMF,EAAWnB,GAE5BqB,EAAOhF,cAAc,CAAC,EAAGgF,EAAMF,GAGjC1B,QAAQpuC,KAAK9C,KAAM8oC,EAAMgK,GACpBzsC,EAAQqsC,QAAQ5vC,KAAKytC,KAAK,QAASiC,EAAKN,EAAIU,EACnD,GACC,CACDtlC,IAAK,uBACL1Y,MAAO,SAASm+C,qBAAqBP,EAAKN,GACpCpvC,KAAKkwC,kBAAkBR,EAAKN,WACvBpvC,KAAK9C,KAAKwyC,GAAKN,GAGxBpvC,KAAKwvC,iBAAiBJ,GACtBpvC,KAAKytC,KAAK,UAAWiC,EAAKN,EAC5B,GACC,CACD5kC,IAAK,oBACL1Y,MAAO,SAASo+C,kBAAkBR,EAAKN,GACrC,YAAqC36C,IAA9BuL,KAAKyvC,YAAYC,EAAKN,EAC/B,GACC,CACD5kC,IAAK,oBACL1Y,MAAO,SAASq+C,kBAAkBT,EAAKN,GAErC,OADKA,IAAIA,EAAKpvC,KAAKuD,QAAQ8rC,WACW,OAAlCrvC,KAAKuD,QAAQ6sC,iBAAkCpF,cAAc,CAAC,EAAG,CAAC,EAAGhrC,KAAKyvC,YAAYC,EAAKN,IACxFpvC,KAAKyvC,YAAYC,EAAKN,EAC/B,GACC,CACD5kC,IAAK,oBACL1Y,MAAO,SAASu+C,kBAAkBX,GAChC,OAAO1vC,KAAK9C,KAAKwyC,EACnB,GACC,CACDllC,IAAK,SACL1Y,MAAO,SAASw+C,SACd,OAAOtwC,KAAK9C,IACd,KAGKgyC,aACT,CA9JoB,CA8JlB7B,GAEEkD,EAAgB,CAClBC,WAAY,CAAC,EACbC,iBAAkB,SAASA,iBAAiBxjD,GAC1C+S,KAAKwwC,WAAWvjD,EAAOgO,MAAQhO,CACjC,EACA42B,OAAQ,SAASA,OAAO2sB,EAAY1+C,EAAO0Y,EAAKjH,EAASmtC,GACvD,IAAIlD,EAAQxtC,KAKZ,OAHAwwC,EAAWrhD,SAAQ,SAAUwhD,GACvBnD,EAAMgD,WAAWG,KAAY7+C,EAAQ07C,EAAMgD,WAAWG,GAAWx2B,QAAQroB,EAAO0Y,EAAKjH,EAASmtC,GACpG,IACO5+C,CACT,GAGE8+C,EAAmB,CAAC,EAEpBC,EAAa,SAAU1B,GAGzB,SAAS0B,WAAWC,GAClB,IAAItD,EAEAjqC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAkBnF,OAhBAu6C,gBAAgBnrC,KAAM6wC,YAEtBrD,EAAQ3B,2BAA2B7rC,KAAM8rC,gBAAgB+E,YAAY30C,KAAK8D,OAEtE+uC,GACF1B,EAAanxC,KAAKyvC,uBAAuB6B,IA1S/C,SAAShqC,KAAKoD,EAAG2yB,EAAGhW,GAClB3c,EAAEzX,SAAQ,SAAUma,GACdiwB,EAAEjwB,KAAIia,EAAEja,GAAKiwB,EAAEjwB,GACrB,GACF,CAySI9F,CAAK,CAAC,gBAAiB,gBAAiB,iBAAkB,eAAgB,mBAAoB,aAAc,SAAUstC,EAAUnF,uBAAuB6B,IACvJA,EAAMjqC,QAAUA,OAEmB9O,IAA/B+4C,EAAMjqC,QAAQ+rC,eAChB9B,EAAMjqC,QAAQ+rC,aAAe,KAG/B9B,EAAMd,OAASH,EAAWp+C,OAAO,cAC1Bq/C,CACT,CAoVA,OA5WAvB,UAAU4E,WAAY1B,GA0BtB3D,aAAaqF,WAAY,CAAC,CACxBrmC,IAAK,iBACL1Y,MAAO,SAASi/C,eAAerB,GACzBA,IAAK1vC,KAAKgxC,SAAWtB,EAC3B,GACC,CACDllC,IAAK,SACL1Y,MAAO,SAASm/C,OAAOzmC,GACrB,IAAIjH,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAChFsgD,cAAe,CAAC,GAEdC,EAAWnxC,KAAKsX,QAAQ9M,EAAKjH,GACjC,OAAO4tC,QAA6B18C,IAAjB08C,EAASxD,GAC9B,GACC,CACDnjC,IAAK,iBACL1Y,MAAO,SAASs/C,eAAe5mC,EAAKjH,GAClC,IAAI8tC,OAAsC58C,IAAxB8O,EAAQ8tC,YAA4B9tC,EAAQ8tC,YAAcrxC,KAAKuD,QAAQ8tC,iBACrE58C,IAAhB48C,IAA2BA,EAAc,KAC7C,IAAI/B,OAAwC76C,IAAzB8O,EAAQ+rC,aAA6B/rC,EAAQ+rC,aAAetvC,KAAKuD,QAAQ+rC,aACxF5rB,EAAangB,EAAQ6rC,IAAMpvC,KAAKuD,QAAQ8rC,UAE5C,GAAIgC,GAAe7mC,EAAIxa,QAAQqhD,IAAgB,EAAG,CAChD,IAAI/nC,EAAIkB,EAAI5a,MAAMoQ,KAAKsxC,aAAaC,eAEpC,GAAIjoC,GAAKA,EAAE7b,OAAS,EAClB,MAAO,CACL+c,IAAKA,EACLkZ,WAAYA,GAIhB,IAAImN,EAAQrmB,EAAIxF,MAAMqsC,IAClBA,IAAgB/B,GAAgB+B,IAAgB/B,GAAgBtvC,KAAKuD,QAAQ6rC,GAAGp/C,QAAQ6gC,EAAM,KAAO,KAAGnN,EAAamN,EAAMnmB,SAC/HF,EAAMqmB,EAAM1mB,KAAKmlC,EACnB,CAGA,MAD0B,iBAAf5rB,IAAyBA,EAAa,CAACA,IAC3C,CACLlZ,IAAKA,EACLkZ,WAAYA,EAEhB,GACC,CACDlZ,IAAK,YACL1Y,MAAO,SAAS0/C,UAAUlnC,EAAM/G,EAASkuC,GACvC,IAAIC,EAAS1xC,KAOb,GALyB,WAArB/M,QAAQsQ,IAAyBvD,KAAKuD,QAAQouC,mCAChDpuC,EAAUvD,KAAKuD,QAAQouC,iCAAiC/gD,YAGrD2S,IAASA,EAAU,CAAC,GACrB+G,QAAqC,MAAO,GAC3Cjd,MAAMC,QAAQgd,KAAOA,EAAO,CAAC7a,OAAO6a,KACzC,IAAIglC,OAAwC76C,IAAzB8O,EAAQ+rC,aAA6B/rC,EAAQ+rC,aAAetvC,KAAKuD,QAAQ+rC,aAExFsC,EAAuB5xC,KAAKoxC,eAAe9mC,EAAKA,EAAK7c,OAAS,GAAI8V,GAClEiH,EAAMonC,EAAqBpnC,IAC3BkZ,EAAakuB,EAAqBluB,WAElC5X,EAAY4X,EAAWA,EAAWj2B,OAAS,GAC3CiiD,EAAMnsC,EAAQmsC,KAAO1vC,KAAKgxC,SAC1Ba,EAA0BtuC,EAAQsuC,yBAA2B7xC,KAAKuD,QAAQsuC,wBAE9E,GAAInC,GAA6B,WAAtBA,EAAIhgD,cAA4B,CACzC,GAAImiD,EAAyB,CAC3B,IAAIR,EAAc9tC,EAAQ8tC,aAAerxC,KAAKuD,QAAQ8tC,YACtD,OAAOvlC,EAAYulC,EAAc7mC,CACnC,CAEA,OAAOA,CACT,CAEA,IAAI2mC,EAAWnxC,KAAKsX,QAAQhN,EAAM/G,GAC9BoqC,EAAMwD,GAAYA,EAASxD,IAC3BmE,EAAaX,GAAYA,EAASY,SAAWvnC,EAC7CwnC,EAAkBb,GAAYA,EAASc,cAAgBznC,EACvD0nC,EAAUtkD,OAAOkB,UAAU+P,SAASvQ,MAAMq/C,GAE1CwE,OAAoC19C,IAAvB8O,EAAQ4uC,WAA2B5uC,EAAQ4uC,WAAanyC,KAAKuD,QAAQ4uC,WAClFC,GAA8BpyC,KAAKqyC,YAAcryC,KAAKqyC,WAAWC,eAGrE,GAAIF,GAA8BzE,IAFE,iBAARA,GAAmC,kBAARA,GAAoC,iBAARA,IAHpE,CAAC,kBAAmB,oBAAqB,mBAKY39C,QAAQkiD,GAAW,IAA6B,iBAAfC,GAAuC,mBAAZD,GAA+B,CAC7J,IAAK3uC,EAAQgvC,gBAAkBvyC,KAAKuD,QAAQgvC,cAE1C,OADAvyC,KAAK0sC,OAAOn4C,KAAK,mEACVyL,KAAKuD,QAAQivC,sBAAwBxyC,KAAKuD,QAAQivC,sBAAsBV,EAAYnE,EAAKpqC,GAAW,QAAQvU,OAAOwb,EAAK,MAAMxb,OAAOgR,KAAKgxC,SAAU,4CAG7J,GAAI1B,EAAc,CAChB,IAAImD,EAA6B,mBAAZP,EACjB1uC,EAAOivC,EAAiB,GAAK,CAAC,EAC9BC,EAAcD,EAAiBT,EAAkBF,EAErD,IAAK,IAAIxoC,KAAKqkC,EACZ,GAAI//C,OAAOkB,UAAUnB,eAAeuO,KAAKyxC,EAAKrkC,GAAI,CAChD,IAAIqpC,EAAU,GAAG3jD,OAAO0jD,GAAa1jD,OAAOsgD,GAActgD,OAAOsa,GACjE9F,EAAK8F,GAAKtJ,KAAKwxC,UAAUmB,EAAS3H,cAAc,CAAC,EAAGznC,EAAS,CAC3D4uC,YAAY,EACZ/C,GAAI1rB,KAEFlgB,EAAK8F,KAAOqpC,IAASnvC,EAAK8F,GAAKqkC,EAAIrkC,GACzC,CAGFqkC,EAAMnqC,CACR,CACF,MAAO,GAAI4uC,GAAoD,iBAAfD,GAAuC,mBAAZD,GACzEvE,EAAMA,EAAIxjC,KAAKgoC,MACNxE,EAAM3tC,KAAK4yC,kBAAkBjF,EAAKrjC,EAAM/G,EAASkuC,QACrD,CACL,IAAIoB,GAAc,EACdd,GAAU,EACVe,OAAwCr+C,IAAlB8O,EAAQ2a,OAAgD,iBAAlB3a,EAAQ2a,MACpE60B,EAAkBlC,WAAWkC,gBAAgBxvC,GAC7CyvC,EAAqBF,EAAsB9yC,KAAKizC,eAAeC,UAAUxD,EAAKnsC,EAAQ2a,OAAS,GAC/FzJ,EAAelR,EAAQ,eAAevU,OAAOgkD,KAAwBzvC,EAAQkR,cAE5EzU,KAAKmzC,cAAcxF,IAAQoF,IAC9BF,GAAc,EACdlF,EAAMl5B,GAGHzU,KAAKmzC,cAAcxF,KACtBoE,GAAU,EACVpE,EAAMnjC,GAGR,IAAI4oC,EAAgBL,GAAmBt+B,IAAiBk5B,GAAO3tC,KAAKuD,QAAQ6vC,cAE5E,GAAIrB,GAAWc,GAAeO,EAAe,CAG3C,GAFApzC,KAAK0sC,OAAOL,IAAI+G,EAAgB,YAAc,aAAc1D,EAAK5jC,EAAWtB,EAAK4oC,EAAgB3+B,EAAek5B,GAE5G2B,EAAc,CAChB,IAAI+D,EAAKrzC,KAAKsX,QAAQ9M,EAAKwgC,cAAc,CAAC,EAAGznC,EAAS,CACpD+rC,cAAc,KAEZ+D,GAAMA,EAAG1F,KAAK3tC,KAAK0sC,OAAOn4C,KAAK,kLACrC,CAEA,IAAI++C,EAAO,GACPC,EAAevzC,KAAKwzC,cAAcC,iBAAiBzzC,KAAKuD,QAAQmwC,YAAanwC,EAAQmsC,KAAO1vC,KAAKgxC,UAErG,GAAmC,aAA/BhxC,KAAKuD,QAAQowC,eAAgCJ,GAAgBA,EAAa,GAC5E,IAAK,IAAIhmD,EAAI,EAAGA,EAAIgmD,EAAa9lD,OAAQF,IACvC+lD,EAAK/jD,KAAKgkD,EAAahmD,QAEe,QAA/ByS,KAAKuD,QAAQowC,cACtBL,EAAOtzC,KAAKwzC,cAAcI,mBAAmBrwC,EAAQmsC,KAAO1vC,KAAKgxC,UAEjEsC,EAAK/jD,KAAKgU,EAAQmsC,KAAO1vC,KAAKgxC,UAGhC,IAAI3S,EAAO,SAASA,KAAKltC,EAAGg9C,EAAG0F,GACzBnC,EAAOnuC,QAAQuwC,kBACjBpC,EAAOnuC,QAAQuwC,kBAAkB3iD,EAAG2a,EAAWqiC,EAAGiF,EAAgBS,EAAgBlG,EAAKyF,EAAe7vC,GAC7FmuC,EAAOqC,kBAAoBrC,EAAOqC,iBAAiBC,aAC5DtC,EAAOqC,iBAAiBC,YAAY7iD,EAAG2a,EAAWqiC,EAAGiF,EAAgBS,EAAgBlG,EAAKyF,EAAe7vC,GAG3GmuC,EAAOjE,KAAK,aAAct8C,EAAG2a,EAAWqiC,EAAGR,EAC7C,EAEI3tC,KAAKuD,QAAQywC,cACXh0C,KAAKuD,QAAQ0wC,oBAAsBnB,EACrCQ,EAAKnkD,SAAQ,SAAU6hD,GACrBU,EAAOuB,eAAeiB,YAAYlD,GAAU7hD,SAAQ,SAAU0E,GAC5DwqC,EAAK,CAAC2S,GAAWxmC,EAAM3W,EAAQ0P,EAAQ,eAAevU,OAAO6E,KAAY4gB,EAC3E,GACF,IAEA4pB,EAAKiV,EAAM9oC,EAAKiK,GAGtB,CAEAk5B,EAAM3tC,KAAK4yC,kBAAkBjF,EAAKrjC,EAAM/G,EAAS4tC,EAAUM,GACvDM,GAAWpE,IAAQnjC,GAAOxK,KAAKuD,QAAQ4wC,8BAA6BxG,EAAM,GAAG3+C,OAAO8c,EAAW,KAAK9c,OAAOwb,IAC3GunC,GAAW/xC,KAAKuD,QAAQ6wC,yBAAwBzG,EAAM3tC,KAAKuD,QAAQ6wC,uBAAuBzG,GAChG,CAEA,OAAOA,CACT,GACC,CACDnjC,IAAK,oBACL1Y,MAAO,SAAS8gD,kBAAkBjF,EAAKnjC,EAAKjH,EAAS4tC,EAAUM,GAC7D,IAAI4C,EAASr0C,KAEb,GAAIA,KAAKqyC,YAAcryC,KAAKqyC,WAAW70B,MACrCmwB,EAAM3tC,KAAKqyC,WAAW70B,MAAMmwB,EAAKpqC,EAAS4tC,EAASmD,QAASnD,EAASoD,OAAQpD,EAASY,QAAS,CAC7FZ,SAAUA,SAEP,IAAK5tC,EAAQixC,kBAAmB,CACjCjxC,EAAQ2tC,eAAelxC,KAAKsxC,aAAa1vC,KAAKopC,cAAc,CAAC,EAAGznC,EAAS,CAC3E2tC,cAAelG,cAAc,CAAC,EAAGhrC,KAAKuD,QAAQ2tC,cAAe3tC,EAAQ2tC,kBAEvE,IACIuD,EADAC,EAAkBnxC,EAAQ2tC,eAAiB3tC,EAAQ2tC,cAAcwD,iBAAmB10C,KAAKuD,QAAQ2tC,cAAcwD,gBAGnH,GAAIA,EAAiB,CACnB,IAAIC,EAAKhH,EAAI/9C,MAAMoQ,KAAKsxC,aAAaC,eACrCkD,EAAUE,GAAMA,EAAGlnD,MACrB,CAEA,IAAIyP,EAAOqG,EAAQzT,SAAsC,iBAApByT,EAAQzT,QAAuByT,EAAQzT,QAAUyT,EAItF,GAHIvD,KAAKuD,QAAQ2tC,cAAc0D,mBAAkB13C,EAAO8tC,cAAc,CAAC,EAAGhrC,KAAKuD,QAAQ2tC,cAAc0D,iBAAkB13C,IACvHywC,EAAM3tC,KAAKsxC,aAAauD,YAAYlH,EAAKzwC,EAAMqG,EAAQmsC,KAAO1vC,KAAKgxC,SAAUztC,GAEzEmxC,EAAiB,CACnB,IAAII,EAAKnH,EAAI/9C,MAAMoQ,KAAKsxC,aAAaC,eAEjCkD,GADUK,GAAMA,EAAGrnD,UACA8V,EAAQwxC,MAAO,EACxC,EAEqB,IAAjBxxC,EAAQwxC,OAAgBpH,EAAM3tC,KAAKsxC,aAAayD,KAAKpH,GAAK,WAC5D,IAAK,IAAIh9C,EAAOC,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMsD,GAAOE,EAAO,EAAGA,EAAOF,EAAME,IAC/EnC,EAAKmC,GAAQD,UAAUC,GAGzB,OAAI4gD,GAAWA,EAAQ,KAAO/iD,EAAK,KAAO6U,EAAQ7B,SAChD2yC,EAAO3H,OAAOn4C,KAAK,6CAA6CvF,OAAON,EAAK,GAAI,aAAaM,OAAOwb,EAAI,KAEjG,MAGF6pC,EAAO7C,UAAUljD,MAAM+lD,EAAQ3lD,EAAKM,OAAO,CAACwb,IACrD,GAAGjH,IACCA,EAAQ2tC,eAAelxC,KAAKsxC,aAAahgC,OAC/C,CAEA,IAAI0jC,EAAczxC,EAAQyxC,aAAeh1C,KAAKuD,QAAQyxC,YAClDC,EAA4C,iBAAhBD,EAA2B,CAACA,GAAeA,EAQ3E,OANIrH,SAAqCsH,GAAsBA,EAAmBxnD,SAAyC,IAA/B8V,EAAQ2xC,qBAClGvH,EAAM4C,EAAc1sB,OAAOoxB,EAAoBtH,EAAKnjC,EAAKxK,KAAKuD,SAAWvD,KAAKuD,QAAQ4xC,wBAA0BnK,cAAc,CAC5HoK,aAAcjE,GACb5tC,GAAWA,EAASvD,OAGlB2tC,CACT,GACC,CACDnjC,IAAK,UACL1Y,MAAO,SAASwlB,QAAQhN,GACtB,IAGI+qC,EACAtD,EACAE,EACAqC,EACAC,EAPAe,EAASt1C,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAwDnF,MAlDoB,iBAAT0Z,IAAmBA,EAAO,CAACA,IACtCA,EAAKnb,SAAQ,SAAUg/C,GACrB,IAAImH,EAAOnC,cAAckC,GAAzB,CAEA,IAAIE,EAAYD,EAAOlE,eAAejD,EAAG5qC,GAErCiH,EAAM+qC,EAAU/qC,IACpBunC,EAAUvnC,EACV,IAAIkZ,EAAa6xB,EAAU7xB,WACvB4xB,EAAO/xC,QAAQiyC,aAAY9xB,EAAaA,EAAW10B,OAAOsmD,EAAO/xC,QAAQiyC,aAC7E,IAAI1C,OAAwCr+C,IAAlB8O,EAAQ2a,OAAgD,iBAAlB3a,EAAQ2a,MACpEu3B,OAA2ChhD,IAApB8O,EAAQ7B,SAAoD,iBAApB6B,EAAQ7B,SAA4C,KAApB6B,EAAQ7B,QACvGg0C,EAAQnyC,EAAQ+vC,KAAO/vC,EAAQ+vC,KAAOgC,EAAO9B,cAAcI,mBAAmBrwC,EAAQmsC,KAAO4F,EAAOtE,SAAUztC,EAAQmwC,aAC1HhwB,EAAWv0B,SAAQ,SAAUigD,GACvBkG,EAAOnC,cAAckC,KACzBd,EAASnF,GAEJwB,EAAiB,GAAG5hD,OAAO0mD,EAAM,GAAI,KAAK1mD,OAAOogD,KAAQkG,EAAOK,OAASL,EAAOK,MAAMC,qBAAuBN,EAAOK,MAAMC,mBAAmBrB,KAChJ3D,EAAiB,GAAG5hD,OAAO0mD,EAAM,GAAI,KAAK1mD,OAAOogD,KAAO,EAExDkG,EAAO5I,OAAOn4C,KAAK,QAASvF,OAAO+iD,EAAS,qBAAuB/iD,OAAO0mD,EAAMvrC,KAAK,MAAO,wCAAyCnb,OAAOulD,EAAQ,wBAA0B,6NAGhLmB,EAAMvmD,SAAQ,SAAUgS,GACtB,IAAIm0C,EAAOnC,cAAckC,GAAzB,CACAf,EAAUnzC,EACV,IAMM00C,EAOFC,EAbAC,EAAWvrC,EACXwrC,EAAY,CAACD,GAEjB,GAAIT,EAAOjD,YAAciD,EAAOjD,WAAW4D,cACzCX,EAAOjD,WAAW4D,cAAcD,EAAWxrC,EAAKrJ,EAAMiuC,EAAI7rC,QAGtDuvC,IAAqB+C,EAAeP,EAAOrC,eAAeC,UAAU/xC,EAAMoC,EAAQ2a,QAClF40B,GAAuB2C,GAAsBO,EAAUzmD,KAAKwmD,EAAWF,GACvEJ,GAAsBO,EAAUzmD,KAAKwmD,GAAY,GAAG/mD,OAAOsmD,EAAO/xC,QAAQ2yC,kBAAkBlnD,OAAOuU,EAAQ7B,UAC3GoxC,GAAqBkD,EAAUzmD,KAAKwmD,GAAYF,GAKtD,KAAOC,EAAcE,EAAU3mD,OACxBimD,EAAOnC,cAAckC,KACxBpD,EAAe6D,EACfT,EAAQC,EAAO7F,YAAYtuC,EAAMiuC,EAAI0G,EAAavyC,GApBf,CAuBzC,IACF,GA9CuC,CA+CzC,IACO,CACLoqC,IAAK0H,EACLtD,QAASA,EACTE,aAAcA,EACdqC,QAASA,EACTC,OAAQA,EAEZ,GACC,CACD/pC,IAAK,gBACL1Y,MAAO,SAASqhD,cAAcxF,GAC5B,aAAel5C,IAARk5C,IAAwB3tC,KAAKuD,QAAQ4yC,YAAsB,OAARxI,IAAoB3tC,KAAKuD,QAAQ6yC,mBAA6B,KAARzI,EAClH,GACC,CACDnjC,IAAK,cACL1Y,MAAO,SAAS29C,YAAYtuC,EAAMiuC,EAAI5kC,GACpC,IAAIjH,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EACnF,OAAIoP,KAAKqyC,YAAcryC,KAAKqyC,WAAW5C,YAAoBzvC,KAAKqyC,WAAW5C,YAAYtuC,EAAMiuC,EAAI5kC,EAAKjH,GAC/FvD,KAAKq2C,cAAc5G,YAAYtuC,EAAMiuC,EAAI5kC,EAAKjH,EACvD,IACE,CAAC,CACHiH,IAAK,kBACL1Y,MAAO,SAASihD,gBAAgBxvC,GAC9B,IAAImtB,EAAS,eAEb,IAAK,IAAInQ,KAAUhd,EACjB,GAAI3V,OAAOkB,UAAUnB,eAAeuO,KAAKqH,EAASgd,IAAWmQ,IAAWnQ,EAAO+1B,UAAU,EAAG5lB,EAAOjjC,cAAWgH,IAAc8O,EAAQgd,GAClI,OAAO,EAIX,OAAO,CACT,KAGKswB,UACT,CA9WiB,CA8WfxD,GAEF,SAASkJ,WAAW95B,GAClB,OAAOA,EAAO+5B,OAAO,GAAGj6B,cAAgBE,EAAOtc,MAAM,EACvD,CAEA,IAAIs2C,EAAe,WACjB,SAASA,aAAalzC,GACpB4nC,gBAAgBnrC,KAAMy2C,cAEtBz2C,KAAKuD,QAAUA,EACfvD,KAAK02C,UAAY12C,KAAKuD,QAAQozC,gBAAiB,EAC/C32C,KAAK22C,cAAgB32C,KAAKuD,QAAQozC,gBAAiB,EACnD32C,KAAK0sC,OAASH,EAAWp+C,OAAO,gBAClC,CA6IA,OA3IAq9C,aAAaiL,aAAc,CAAC,CAC1BjsC,IAAK,wBACL1Y,MAAO,SAAS8kD,sBAAsBz1C,GACpC,IAAKA,GAAQA,EAAKnR,QAAQ,KAAO,EAAG,OAAO,KAC3C,IAAIyhC,EAAItwB,EAAK6D,MAAM,KACnB,OAAiB,IAAbysB,EAAEhkC,OAAqB,MAC3BgkC,EAAEpiC,MACoC,MAAlCoiC,EAAEA,EAAEhkC,OAAS,GAAGiC,cAA8B,KAC3CsQ,KAAK62C,mBAAmBplB,EAAEtnB,KAAK,MACxC,GACC,CACDK,IAAK,0BACL1Y,MAAO,SAASglD,wBAAwB31C,GACtC,IAAKA,GAAQA,EAAKnR,QAAQ,KAAO,EAAG,OAAOmR,EAC3C,IAAIswB,EAAItwB,EAAK6D,MAAM,KACnB,OAAOhF,KAAK62C,mBAAmBplB,EAAE,GACnC,GACC,CACDjnB,IAAK,qBACL1Y,MAAO,SAAS+kD,mBAAmB11C,GACjC,GAAoB,iBAATA,GAAqBA,EAAKnR,QAAQ,MAAQ,EAAG,CACtD,IAAI+mD,EAAe,CAAC,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,OAAQ,QAChEtlB,EAAItwB,EAAK6D,MAAM,KAkBnB,OAhBIhF,KAAKuD,QAAQyzC,aACfvlB,EAAIA,EAAEjvB,KAAI,SAAUy0C,GAClB,OAAOA,EAAKvnD,aACd,IACsB,IAAb+hC,EAAEhkC,QACXgkC,EAAE,GAAKA,EAAE,GAAG/hC,cACZ+hC,EAAE,GAAKA,EAAE,GAAGlV,cACRw6B,EAAa/mD,QAAQyhC,EAAE,GAAG/hC,gBAAkB,IAAG+hC,EAAE,GAAK8kB,WAAW9kB,EAAE,GAAG/hC,iBACpD,IAAb+hC,EAAEhkC,SACXgkC,EAAE,GAAKA,EAAE,GAAG/hC,cACQ,IAAhB+hC,EAAE,GAAGhkC,SAAcgkC,EAAE,GAAKA,EAAE,GAAGlV,eACtB,QAATkV,EAAE,IAAgC,IAAhBA,EAAE,GAAGhkC,SAAcgkC,EAAE,GAAKA,EAAE,GAAGlV,eACjDw6B,EAAa/mD,QAAQyhC,EAAE,GAAG/hC,gBAAkB,IAAG+hC,EAAE,GAAK8kB,WAAW9kB,EAAE,GAAG/hC,gBACtEqnD,EAAa/mD,QAAQyhC,EAAE,GAAG/hC,gBAAkB,IAAG+hC,EAAE,GAAK8kB,WAAW9kB,EAAE,GAAG/hC,iBAGrE+hC,EAAEtnB,KAAK,IAChB,CAEA,OAAOnK,KAAKuD,QAAQ2zC,WAAal3C,KAAKuD,QAAQyzC,aAAe71C,EAAKzR,cAAgByR,CACpF,GACC,CACDqJ,IAAK,gBACL1Y,MAAO,SAASqlD,cAAch2C,GAE5B,OADAnB,KAAK0sC,OAAOK,UAAU,8BAA+B,kIAC9C/sC,KAAKo3C,gBAAgBj2C,EAC9B,GACC,CACDqJ,IAAK,kBACL1Y,MAAO,SAASslD,gBAAgBj2C,GAK9B,OAJ0B,iBAAtBnB,KAAKuD,QAAQiiB,MAA2BxlB,KAAKuD,QAAQ8zC,4BACvDl2C,EAAOnB,KAAK82C,wBAAwB31C,KAG9BnB,KAAK22C,gBAAkB32C,KAAK22C,cAAclpD,QAAUuS,KAAK22C,cAAc3mD,QAAQmR,IAAS,CAClG,GACC,CACDqJ,IAAK,wBACL1Y,MAAO,SAASwlD,sBAAsB5B,GACpC,IAGIL,EAHA7H,EAAQxtC,KAEZ,OAAK01C,GAELA,EAAMvmD,SAAQ,SAAUgS,GACtB,IAAIk0C,EAAJ,CAEA,IAAIkC,EAAa/J,EAAMqJ,mBAAmB11C,GAErCqsC,EAAMjqC,QAAQozC,gBAAiBnJ,EAAM4J,gBAAgBG,KAAalC,EAAQkC,EAJ9D,CAKnB,KAEKlC,GAASr1C,KAAKuD,QAAQozC,eACzBjB,EAAMvmD,SAAQ,SAAUgS,GACtB,IAAIk0C,EAAJ,CAEA,IAAImC,EAAUhK,EAAMsJ,wBAAwB31C,GAE5C,GAAIqsC,EAAM4J,gBAAgBI,GAAU,OAAOnC,EAAQmC,EACnDnC,EAAQ7H,EAAMjqC,QAAQozC,cAAchqC,MAAK,SAAU8qC,GACjD,GAAsC,IAAlCA,EAAaznD,QAAQwnD,GAAgB,OAAOC,CAClD,GAPiB,CAQnB,IAGGpC,IAAOA,EAAQr1C,KAAKyzC,iBAAiBzzC,KAAKuD,QAAQmwC,aAAa,IAC7D2B,GAxBY,IAyBrB,GACC,CACD7qC,IAAK,mBACL1Y,MAAO,SAAS2hD,iBAAiBiE,EAAWv2C,GAC1C,IAAKu2C,EAAW,MAAO,GAGvB,GAFyB,mBAAdA,IAA0BA,EAAYA,EAAUv2C,IAClC,iBAAdu2C,IAAwBA,EAAY,CAACA,IACG,mBAA/C9pD,OAAOkB,UAAU+P,SAASvQ,MAAMopD,GAAiC,OAAOA,EAC5E,IAAKv2C,EAAM,OAAOu2C,EAAmB,SAAK,GAC1C,IAAIrC,EAAQqC,EAAUv2C,GAKtB,OAJKk0C,IAAOA,EAAQqC,EAAU13C,KAAK42C,sBAAsBz1C,KACpDk0C,IAAOA,EAAQqC,EAAU13C,KAAK62C,mBAAmB11C,KACjDk0C,IAAOA,EAAQqC,EAAU13C,KAAK82C,wBAAwB31C,KACtDk0C,IAAOA,EAAQqC,EAAmB,SAChCrC,GAAS,EAClB,GACC,CACD7qC,IAAK,qBACL1Y,MAAO,SAAS8hD,mBAAmBzyC,EAAMw2C,GACvC,IAAIjG,EAAS1xC,KAET43C,EAAgB53C,KAAKyzC,iBAAiBkE,GAAgB33C,KAAKuD,QAAQmwC,aAAe,GAAIvyC,GACtFu0C,EAAQ,GAERmC,EAAU,SAASA,QAAQC,GACxBA,IAEDpG,EAAO0F,gBAAgBU,GACzBpC,EAAMnmD,KAAKuoD,GAEXpG,EAAOhF,OAAOn4C,KAAK,uDAAuDvF,OAAO8oD,IAErF,EAaA,MAXoB,iBAAT32C,GAAqBA,EAAKnR,QAAQ,MAAQ,GACzB,iBAAtBgQ,KAAKuD,QAAQiiB,MAAyBqyB,EAAQ73C,KAAK62C,mBAAmB11C,IAChD,iBAAtBnB,KAAKuD,QAAQiiB,MAAiD,gBAAtBxlB,KAAKuD,QAAQiiB,MAAwBqyB,EAAQ73C,KAAK42C,sBAAsBz1C,IAC1F,gBAAtBnB,KAAKuD,QAAQiiB,MAAwBqyB,EAAQ73C,KAAK82C,wBAAwB31C,KACrD,iBAATA,GAChB02C,EAAQ73C,KAAK62C,mBAAmB11C,IAGlCy2C,EAAczoD,SAAQ,SAAU4oD,GAC1BrC,EAAM1lD,QAAQ+nD,GAAM,GAAGF,EAAQnG,EAAOmF,mBAAmBkB,GAC/D,IACOrC,CACT,KAGKe,YACT,CAtJmB,GAwJfuB,EAAO,CAAC,CACV1E,KAAM,CAAC,MAAO,KAAM,KAAM,MAAO,KAAM,MAAO,MAAO,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,QAAS,KAAM,KAAM,KAAM,KAAM,KAAM,MACjI2E,GAAI,CAAC,EAAG,GACRF,GAAI,GACH,CACDzE,KAAM,CAAC,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,MAAO,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,MAAO,MAAO,KAAM,QAAS,KAAM,MAAO,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MACnY2E,GAAI,CAAC,EAAG,GACRF,GAAI,GACH,CACDzE,KAAM,CAAC,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,MAC9I2E,GAAI,CAAC,GACLF,GAAI,GACH,CACDzE,KAAM,CAAC,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,KAAM,MAClD2E,GAAI,CAAC,EAAG,EAAG,GACXF,GAAI,GACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,EAAG,GAAI,KACrBF,GAAI,GACH,CACDzE,KAAM,CAAC,KAAM,MACb2E,GAAI,CAAC,EAAG,EAAG,GACXF,GAAI,GACH,CACDzE,KAAM,CAAC,MAAO,MACd2E,GAAI,CAAC,EAAG,EAAG,GACXF,GAAI,GACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,GACdF,GAAI,GACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,GACRF,GAAI,GACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,EAAG,IACjBF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,IACdF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,GACRF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,GACRF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,GACdF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,IACXF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,GACXF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,GACRF,GAAI,IACH,CACDzE,KAAM,CAAC,OACP2E,GAAI,CAAC,EAAG,EAAG,GACXF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,GAAI,IACfF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,GACRF,GAAI,GACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,IACXF,GAAI,IACH,CACDzE,KAAM,CAAC,MACP2E,GAAI,CAAC,EAAG,EAAG,EAAG,GACdF,GAAI,IACH,CACDzE,KAAM,CAAC,KAAM,MACb2E,GAAI,CAAC,EAAG,EAAG,GAAI,IACfF,GAAI,KAEFG,EAAqB,CACvB,EAAG,SAAS7jD,EAAE4gB,GACZ,OAAOkjC,OAAOljC,EAAI,EACpB,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAY,GAALljC,EAChB,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAO,CACT,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAOljC,EAAI,IAAM,GAAKA,EAAI,KAAO,GAAK,EAAIA,EAAI,IAAM,GAAKA,EAAI,IAAM,IAAMA,EAAI,IAAM,IAAMA,EAAI,KAAO,IAAM,EAAI,EACvH,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,EAAS,GAALA,EAAS,EAAIA,EAAI,KAAO,GAAKA,EAAI,KAAO,GAAK,EAAIA,EAAI,KAAO,GAAK,EAAI,EAC/G,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAY,GAALljC,EAAS,EAAIA,GAAK,GAAKA,GAAK,EAAI,EAAI,EACpD,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAY,GAALljC,EAAS,EAAIA,EAAI,IAAM,GAAKA,EAAI,IAAM,IAAMA,EAAI,IAAM,IAAMA,EAAI,KAAO,IAAM,EAAI,EACjG,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,EAAS,GAALA,GAAe,IAALA,EAAU,EAAI,EAClE,EACA,EAAG,SAAS5gB,EAAE4gB,GACZ,OAAOkjC,OAAOljC,GAAK,EACrB,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,EAAIA,EAAI,EAAI,EAAIA,EAAI,GAAK,EAAI,EACnE,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,GAAe,IAALA,EAAU,EAAS,GAALA,GAAe,IAALA,EAAU,EAAIA,EAAI,GAAKA,EAAI,GAAK,EAAI,EACtF,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAOljC,EAAI,IAAM,GAAKA,EAAI,KAAO,GAC1C,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAa,IAANljC,EAChB,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,EAAS,GAALA,EAAS,EAAI,EACvD,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAOljC,EAAI,IAAM,GAAKA,EAAI,KAAO,GAAK,EAAIA,EAAI,IAAM,IAAMA,EAAI,IAAM,IAAMA,EAAI,KAAO,IAAM,EAAI,EACxG,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAOljC,EAAI,IAAM,GAAKA,EAAI,KAAO,GAAK,EAAU,IAANA,EAAU,EAAI,EACjE,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,GAAUA,EAAI,IAAM,GAAKA,EAAI,KAAO,GAAK,EAAI,EAC7D,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,EAAI,EAC1C,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,GAAUA,EAAI,IAAM,GAAKA,EAAI,IAAM,GAAK,EAAIA,EAAI,IAAM,IAAMA,EAAI,IAAM,GAAK,EAAI,EAC5G,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,GAAUA,EAAI,IAAM,GAAKA,EAAI,IAAM,GAAK,EAAI,EACzE,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAOljC,EAAI,KAAO,EAAI,EAAIA,EAAI,KAAO,EAAI,EAAIA,EAAI,KAAO,GAAKA,EAAI,KAAO,EAAI,EAAI,EACzF,EACA,GAAI,SAAS5gB,EAAE4gB,GACb,OAAOkjC,OAAY,GAALljC,EAAS,EAAS,GAALA,EAAS,GAAKA,EAAI,GAAKA,EAAI,KAAOA,EAAI,IAAM,EAAI,EAAI,EACjF,GAgBF,IAAImjC,EAAiB,WACnB,SAASA,eAAe5E,GACtB,IAAIjwC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAEnFu6C,gBAAgBnrC,KAAMo4C,gBAEtBp4C,KAAKwzC,cAAgBA,EACrBxzC,KAAKuD,QAAUA,EACfvD,KAAK0sC,OAASH,EAAWp+C,OAAO,kBAChC6R,KAAKq4C,MAtBT,SAASC,cACP,IAAID,EAAQ,CAAC,EASb,OARAL,EAAK7oD,SAAQ,SAAU8B,GACrBA,EAAIqiD,KAAKnkD,SAAQ,SAAUgC,GACzBknD,EAAMlnD,GAAK,CACTonD,QAAStnD,EAAIgnD,GACbO,QAASN,EAAmBjnD,EAAI8mD,IAEpC,GACF,IACOM,CACT,CAWiBC,EACf,CAiFA,OA/EA9M,aAAa4M,eAAgB,CAAC,CAC5B5tC,IAAK,UACL1Y,MAAO,SAAS2mD,QAAQ/I,EAAKt8C,GAC3B4M,KAAKq4C,MAAM3I,GAAOt8C,CACpB,GACC,CACDoX,IAAK,UACL1Y,MAAO,SAAS4mD,QAAQv3C,GACtB,OAAOnB,KAAKq4C,MAAMl3C,IAASnB,KAAKq4C,MAAMr4C,KAAKwzC,cAAcsD,wBAAwB31C,GACnF,GACC,CACDqJ,IAAK,cACL1Y,MAAO,SAAS6mD,YAAYx3C,GAC1B,IAAIy3C,EAAO54C,KAAK04C,QAAQv3C,GACxB,OAAOy3C,GAAQA,EAAKL,QAAQ9qD,OAAS,CACvC,GACC,CACD+c,IAAK,sBACL1Y,MAAO,SAAS+mD,oBAAoB13C,EAAMqJ,GACxC,OAAOxK,KAAKk0C,YAAY/yC,GAAMqB,KAAI,SAAU3O,GAC1C,OAAO2W,EAAM3W,CACf,GACF,GACC,CACD2W,IAAK,cACL1Y,MAAO,SAASoiD,YAAY/yC,GAC1B,IAAIqsC,EAAQxtC,KAER44C,EAAO54C,KAAK04C,QAAQv3C,GAExB,OAAKy3C,EAIEA,EAAKL,QAAQ/1C,KAAI,SAAUs2C,GAChC,OAAOtL,EAAM0F,UAAU/xC,EAAM23C,EAC/B,IALS,EAMX,GACC,CACDtuC,IAAK,YACL1Y,MAAO,SAASohD,UAAU/xC,EAAM+c,GAC9B,IAAIwzB,EAAS1xC,KAET44C,EAAO54C,KAAK04C,QAAQv3C,GAExB,GAAIy3C,EAAM,CACR,IAAI5oC,EAAM4oC,EAAKG,MAAQH,EAAKJ,QAAQt6B,GAAS06B,EAAKJ,QAAQ10C,KAAKk1C,IAAI96B,IAC/DrqB,EAAS+kD,EAAKL,QAAQvoC,GAEtBhQ,KAAKuD,QAAQ01C,sBAAgD,IAAxBL,EAAKL,QAAQ9qD,QAAoC,IAApBmrD,EAAKL,QAAQ,KAClE,IAAX1kD,EACFA,EAAS,SACW,IAAXA,IACTA,EAAS,KAIb,IAAIqlD,EAAe,SAASA,eAC1B,OAAOxH,EAAOnuC,QAAQ0mB,SAAWp2B,EAAOgL,WAAa6yC,EAAOnuC,QAAQ0mB,QAAUp2B,EAAOgL,WAAahL,EAAOgL,UAC3G,EAEA,MAAuC,OAAnCmB,KAAKuD,QAAQ41C,kBACA,IAAXtlD,EAAqB,GACH,iBAAXA,EAA4B,WAAW7E,OAAO6E,EAAOgL,YACzDq6C,IACqC,OAAnCl5C,KAAKuD,QAAQ41C,mBAEbn5C,KAAKuD,QAAQ01C,sBAAgD,IAAxBL,EAAKL,QAAQ9qD,QAAoC,IAApBmrD,EAAKL,QAAQ,GADjFW,IAKFl5C,KAAKuD,QAAQ0mB,SAAWja,EAAInR,WAAamB,KAAKuD,QAAQ0mB,QAAUja,EAAInR,WAAamR,EAAInR,UAC9F,CAGA,OADAmB,KAAK0sC,OAAOn4C,KAAK,6BAA6BvF,OAAOmS,IAC9C,EACT,KAGKi3C,cACT,CA5FqB,GA8FjBgB,EAAe,WACjB,SAASA,eACP,IAAI71C,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAEnFu6C,gBAAgBnrC,KAAMo5C,cAEtBp5C,KAAK0sC,OAASH,EAAWp+C,OAAO,gBAChC6R,KAAKuD,QAAUA,EAEfvD,KAAKq5C,OAAS91C,EAAQ2tC,eAAiB3tC,EAAQ2tC,cAAcmI,QAAU,SAAUvnD,GAC/E,OAAOA,CACT,EAEAkO,KAAK4B,KAAK2B,EACZ,CAwLA,OAtLAioC,aAAa4N,aAAc,CAAC,CAC1B5uC,IAAK,OACL1Y,MAAO,SAAS8P,OACd,IAAI2B,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC9E2S,EAAQ2tC,gBAAe3tC,EAAQ2tC,cAAgB,CAClDoI,aAAa,IAEf,IAAIC,EAAQh2C,EAAQ2tC,cACpBlxC,KAAKoI,YAA0B3T,IAAjB8kD,EAAMnxC,OAAuBmxC,EAAMnxC,OAAS,eAC1DpI,KAAKs5C,iBAAoC7kD,IAAtB8kD,EAAMD,aAA4BC,EAAMD,YAC3Dt5C,KAAKw5C,yBAAoD/kD,IAA9B8kD,EAAMC,qBAAoCD,EAAMC,oBAC3Ex5C,KAAK0wB,OAAS6oB,EAAM7oB,OAASke,YAAY2K,EAAM7oB,QAAU6oB,EAAME,eAAiB,KAChFz5C,KAAKnM,OAAS0lD,EAAM1lD,OAAS+6C,YAAY2K,EAAM1lD,QAAU0lD,EAAMG,eAAiB,KAChF15C,KAAK25C,gBAAkBJ,EAAMI,gBAAkBJ,EAAMI,gBAAkBJ,EAAMI,iBAAmB,IAChG35C,KAAK45C,eAAiBL,EAAMM,eAAiB,GAAKN,EAAMK,gBAAkB,IAC1E55C,KAAK65C,eAAiB75C,KAAK45C,eAAiB,GAAKL,EAAMM,gBAAkB,GACzE75C,KAAK85C,cAAgBP,EAAMO,cAAgBlL,YAAY2K,EAAMO,eAAiBP,EAAMQ,sBAAwBnL,YAAY,OACxH5uC,KAAKg6C,cAAgBT,EAAMS,cAAgBpL,YAAY2K,EAAMS,eAAiBT,EAAMU,sBAAwBrL,YAAY,KACxH5uC,KAAKk6C,wBAA0BX,EAAMW,wBAA0BX,EAAMW,wBAA0BX,EAAMW,yBAA2B,IAChIl6C,KAAKm6C,YAAcZ,EAAMY,YAAcZ,EAAMY,YAAc,IAC3Dn6C,KAAKo6C,kBAAsC3lD,IAAvB8kD,EAAMa,cAA6Bb,EAAMa,aAC7Dp6C,KAAKq6C,aACP,GACC,CACD7vC,IAAK,QACL1Y,MAAO,SAASwf,QACVtR,KAAKuD,SAASvD,KAAK4B,KAAK5B,KAAKuD,QACnC,GACC,CACDiH,IAAK,cACL1Y,MAAO,SAASuoD,cACd,IAAIC,EAAY,GAAGtrD,OAAOgR,KAAK0wB,OAAQ,SAAS1hC,OAAOgR,KAAKnM,QAC5DmM,KAAKu6C,OAAS,IAAInqD,OAAOkqD,EAAW,KACpC,IAAIE,EAAoB,GAAGxrD,OAAOgR,KAAK0wB,QAAQ1hC,OAAOgR,KAAK45C,eAAgB,SAAS5qD,OAAOgR,KAAK65C,gBAAgB7qD,OAAOgR,KAAKnM,QAC5HmM,KAAKy6C,eAAiB,IAAIrqD,OAAOoqD,EAAmB,KACpD,IAAIE,EAAmB,GAAG1rD,OAAOgR,KAAK85C,cAAe,SAAS9qD,OAAOgR,KAAKg6C,eAC1Eh6C,KAAKuxC,cAAgB,IAAInhD,OAAOsqD,EAAkB,IACpD,GACC,CACDlwC,IAAK,cACL1Y,MAAO,SAAS+iD,YAAYhG,EAAK3xC,EAAMwyC,EAAKnsC,GAC1C,IAEI3T,EACAkC,EACA6oD,EAJAnN,EAAQxtC,KAKRyuC,EAAczuC,KAAKuD,SAAWvD,KAAKuD,QAAQ2tC,eAAiBlxC,KAAKuD,QAAQ2tC,cAAc0D,kBAAoB,CAAC,EAEhH,SAASgG,UAAUx5C,GACjB,OAAOA,EAAItR,QAAQ,MAAO,OAC5B,CAEA,IAAI+qD,EAAe,SAASA,aAAarwC,GACvC,GAAIA,EAAIxa,QAAQw9C,EAAMmM,iBAAmB,EAAG,CAC1C,IAAI3T,EAAOwI,oBAAoBtxC,EAAMuxC,EAAajkC,GAClD,OAAOgjC,EAAM4M,aAAe5M,EAAM6L,OAAOrT,OAAMvxC,EAAWi7C,GAAO1J,CACnE,CAEA,IAAIvU,EAAIjnB,EAAIxF,MAAMwoC,EAAMmM,iBACpBxL,EAAI1c,EAAE/mB,QAAQxa,OACd4qD,EAAIrpB,EAAEtnB,KAAKqjC,EAAMmM,iBAAiBzpD,OACtC,OAAOs9C,EAAM6L,OAAO7K,oBAAoBtxC,EAAMuxC,EAAaN,GAAI2M,EAAGpL,EAAKnsC,EACzE,EAEAvD,KAAKq6C,cACL,IAAIU,EAA8Bx3C,GAAWA,EAAQw3C,6BAA+B/6C,KAAKuD,QAAQw3C,4BAC7FrG,EAAkBnxC,GAAWA,EAAQ2tC,eAAiB3tC,EAAQ2tC,cAAcwD,iBAAmB10C,KAAKuD,QAAQ2tC,cAAcwD,gBA2C9H,MA1CY,CAAC,CACXsG,MAAOh7C,KAAKy6C,eACZQ,UAAW,SAASA,UAAU75C,GAC5B,OAAOw5C,UAAUx5C,EACnB,GACC,CACD45C,MAAOh7C,KAAKu6C,OACZU,UAAW,SAASA,UAAU75C,GAC5B,OAAOosC,EAAM8L,YAAcsB,UAAUpN,EAAMplC,OAAOhH,IAAQw5C,UAAUx5C,EACtE,IAEIjS,SAAQ,SAAU+rD,GAGtB,IAFAP,EAAW,EAEJ/qD,EAAQsrD,EAAKF,MAAMrxC,KAAKklC,IAAM,CAGnC,QAAcp6C,KAFd3C,EAAQ+oD,EAAajrD,EAAM,GAAGM,SAG5B,GAA2C,mBAAhC6qD,EAA4C,CACrD,IAAIvoC,EAAOuoC,EAA4BlM,EAAKj/C,EAAO2T,GACnDzR,EAAwB,iBAAT0gB,EAAoBA,EAAO,EAC5C,KAAO,IAAIkiC,EAAiB,CAC1B5iD,EAAQlC,EAAM,GACd,QACF,CACE49C,EAAMd,OAAOn4C,KAAK,8BAA8BvF,OAAOY,EAAM,GAAI,uBAAuBZ,OAAO6/C,IAE/F/8C,EAAQ,EACV,KAC0B,iBAAVA,GAAuB07C,EAAMgM,sBAC7C1nD,EAAQg8C,WAAWh8C,IAOrB,GAJA+8C,EAAMA,EAAI/+C,QAAQF,EAAM,GAAIsrD,EAAKD,UAAUnpD,IAC3CopD,EAAKF,MAAMG,UAAY,IACvBR,GAEgBnN,EAAM2M,YACpB,KAEJ,CACF,IACOtL,CACT,GACC,CACDrkC,IAAK,OACL1Y,MAAO,SAASijD,KAAKlG,EAAKkJ,GACxB,IAGInoD,EACAkC,EAJA4/C,EAAS1xC,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAI/EwqD,EAAgBpQ,cAAc,CAAC,EAAGznC,GAKtC,SAAS83C,iBAAiB7wC,EAAK8wC,GAC7B,IAAIC,EAAMv7C,KAAKk6C,wBACf,GAAI1vC,EAAIxa,QAAQurD,GAAO,EAAG,OAAO/wC,EACjC,IAAIstC,EAAIttC,EAAIxF,MAAM,IAAI5U,OAAO,GAAGpB,OAAOusD,EAAK,WACxCC,EAAgB,IAAIxsD,OAAO8oD,EAAE,IACjCttC,EAAMstC,EAAE,GAER0D,GADAA,EAAgBx7C,KAAK60C,YAAY2G,EAAeJ,IAClBtrD,QAAQ,KAAM,KAE5C,IACEsrD,EAAgB79B,KAAKC,MAAMg+B,GACvBF,IAAkBF,EAAgBpQ,cAAc,CAAC,EAAGsQ,EAAkBF,GAC5E,CAAE,MAAOjyC,GAEP,OADAnJ,KAAK0sC,OAAOn4C,KAAK,oDAAoDvF,OAAOwb,GAAMrB,GAC3E,GAAGna,OAAOwb,GAAKxb,OAAOusD,GAAKvsD,OAAOwsD,EAC3C,CAGA,cADOJ,EAAc3mC,aACdjK,CACT,CAEA,IAxBA4wC,EAAclG,oBAAqB,SAC5BkG,EAAc3mC,aAuBd7kB,EAAQoQ,KAAKuxC,cAAc5nC,KAAKklC,IAAM,CAC3C,IAAI4M,EAAa,GACbC,GAAW,EAEf,GAAI9rD,EAAM,GAAGk4C,SAAS9nC,KAAK25C,mBAAqB,OAAOtpD,KAAKT,EAAM,IAAK,CACrE,IAAI+rD,EAAI/rD,EAAM,GAAGoV,MAAMhF,KAAK25C,iBAAiBn3C,KAAI,SAAUC,GACzD,OAAOA,EAAKvS,MACd,IACAN,EAAM,GAAK+rD,EAAEjxC,QACb+wC,EAAaE,EACbD,GAAW,CACb,CAGA,IADA5pD,EAAQimD,EAAGsD,iBAAiBn/C,KAAK8D,KAAMpQ,EAAM,GAAGM,OAAQkrD,GAAgBA,KAC3DxrD,EAAM,KAAOi/C,GAAwB,iBAAV/8C,EAAoB,OAAOA,EAC9C,iBAAVA,IAAoBA,EAAQg8C,WAAWh8C,IAE7CA,IACHkO,KAAK0sC,OAAOn4C,KAAK,qBAAqBvF,OAAOY,EAAM,GAAI,iBAAiBZ,OAAO6/C,IAC/E/8C,EAAQ,IAGN4pD,IACF5pD,EAAQ2pD,EAAWxV,QAAO,SAAU/uB,EAAG4jC,GACrC,OAAOpJ,EAAO2H,OAAOniC,EAAG4jC,EAAGv3C,EAAQmsC,IAAKnsC,EAC1C,GAAGzR,EAAM5B,SAGX2+C,EAAMA,EAAI/+C,QAAQF,EAAM,GAAIkC,GAC5BkO,KAAKu6C,OAAOY,UAAY,CAC1B,CAEA,OAAOtM,CACT,KAGKuK,YACT,CAvMmB,GAkNnB,IAAIwC,EAAY,SAAUzM,GAGxB,SAASyM,UAAUC,EAASC,EAAOhL,GACjC,IAAItD,EAEAjqC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAuBnF,OArBAu6C,gBAAgBnrC,KAAM47C,WAEtBpO,EAAQ3B,2BAA2B7rC,KAAM8rC,gBAAgB8P,WAAW1/C,KAAK8D,OAErE+uC,GACF1B,EAAanxC,KAAKyvC,uBAAuB6B,IAG3CA,EAAMqO,QAAUA,EAChBrO,EAAMsO,MAAQA,EACdtO,EAAMsD,SAAWA,EACjBtD,EAAMgG,cAAgB1C,EAAS0C,cAC/BhG,EAAMjqC,QAAUA,EAChBiqC,EAAMd,OAASH,EAAWp+C,OAAO,oBACjCq/C,EAAMz0B,MAAQ,CAAC,EACfy0B,EAAMp1B,MAAQ,GAEVo1B,EAAMqO,SAAWrO,EAAMqO,QAAQj6C,MACjC4rC,EAAMqO,QAAQj6C,KAAKkvC,EAAUvtC,EAAQs4C,QAASt4C,GAGzCiqC,CACT,CA2LA,OAxNAvB,UAAU2P,UAAWzM,GA+BrB3D,aAAaoQ,UAAW,CAAC,CACvBpxC,IAAK,YACL1Y,MAAO,SAASiqD,UAAUC,EAAWt4B,EAAYngB,EAAShB,GACxD,IAAImvC,EAAS1xC,KAETi8C,EAAS,GACTC,EAAU,GACVC,EAAkB,GAClBC,EAAmB,GA8BvB,OA7BAJ,EAAU7sD,SAAQ,SAAUugD,GAC1B,IAAI2M,GAAmB,EACvB34B,EAAWv0B,SAAQ,SAAUigD,GAC3B,IAAIn0C,EAAO,GAAGjM,OAAO0gD,EAAK,KAAK1gD,OAAOogD,IAEjC7rC,EAAQ+4C,QAAU5K,EAAOoK,MAAM5L,kBAAkBR,EAAKN,GACzDsC,EAAO34B,MAAM9d,GAAQ,EACZy2C,EAAO34B,MAAM9d,GAAQ,IAAqC,IAAvBy2C,EAAO34B,MAAM9d,GACrDihD,EAAQlsD,QAAQiL,GAAQ,GAAGihD,EAAQ3sD,KAAK0L,IAE5Cy2C,EAAO34B,MAAM9d,GAAQ,EACrBohD,GAAmB,EACfH,EAAQlsD,QAAQiL,GAAQ,GAAGihD,EAAQ3sD,KAAK0L,GACxCghD,EAAOjsD,QAAQiL,GAAQ,GAAGghD,EAAO1sD,KAAK0L,GACtCmhD,EAAiBpsD,QAAQo/C,GAAM,GAAGgN,EAAiB7sD,KAAK6/C,IAEhE,IACKiN,GAAkBF,EAAgB5sD,KAAKmgD,EAC9C,KAEIuM,EAAOxuD,QAAUyuD,EAAQzuD,SAC3BuS,KAAKoY,MAAM7oB,KAAK,CACd2sD,QAASA,EACTK,OAAQ,CAAC,EACTC,OAAQ,GACRj6C,SAAUA,IAIP,CACL05C,OAAQA,EACRC,QAASA,EACTC,gBAAiBA,EACjBC,iBAAkBA,EAEtB,GACC,CACD5xC,IAAK,SACL1Y,MAAO,SAASyqD,OAAOthD,EAAMknB,EAAKjlB,GAChC,IAAIq8B,EAAIt+B,EAAK+J,MAAM,KACf0qC,EAAMnW,EAAE,GACR6V,EAAK7V,EAAE,GACPpX,GAAKniB,KAAKytC,KAAK,gBAAiBiC,EAAKN,EAAIjtB,GAEzCjlB,GACF8C,KAAK87C,MAAM/L,kBAAkBL,EAAKN,EAAIlyC,GAGxC8C,KAAK+Y,MAAM9d,GAAQknB,GAAO,EAAI,EAC9B,IAAIo6B,OAAS,CAAC,EACdv8C,KAAKoY,MAAMjpB,SAAQ,SAAUstD,IAxzCnC,SAASC,SAASnrD,EAAQy0C,EAAMkC,EAAUl5C,GACxC,IAAI2tD,EAAkB5O,cAAcx8C,EAAQy0C,EAAMp4C,QAC9CwF,EAAMupD,EAAgBvpD,IACtB+6C,EAAIwO,EAAgBxO,EAExB/6C,EAAI+6C,GAAK/6C,EAAI+6C,IAAM,GACfn/C,IAAQoE,EAAI+6C,GAAK/6C,EAAI+6C,GAAGn/C,OAAOk5C,IAC9Bl5C,GAAQoE,EAAI+6C,GAAG5+C,KAAK24C,EAC3B,CAizCQwU,CAASD,EAAEF,OAAQ,CAAC7M,GAAMN,GArGlC,SAASr0C,OAAO3N,EAAK6hB,GAGnB,IAFA,IAAIomC,EAAQjoD,EAAI4C,QAAQif,IAEN,IAAXomC,GACLjoD,EAAIiW,OAAOgyC,EAAO,GAClBA,EAAQjoD,EAAI4C,QAAQif,EAExB,CA+FQlU,CAAO0hD,EAAEP,QAASjhD,GACdknB,GAAKs6B,EAAED,OAAOjtD,KAAK4yB,GAEE,IAArBs6B,EAAEP,QAAQzuD,QAAiBgvD,EAAEp2C,OAC/BzY,OAAO0c,KAAKmyC,EAAEF,QAAQptD,SAAQ,SAAUgC,GACjCorD,OAAOprD,KAAIorD,OAAOprD,GAAK,IAExBsrD,EAAEF,OAAOprD,GAAG1D,QACdgvD,EAAEF,OAAOprD,GAAGhC,SAAQ,SAAUigD,GACxBmN,OAAOprD,GAAGnB,QAAQo/C,GAAM,GAAGmN,OAAOprD,GAAG5B,KAAK6/C,EAChD,GAEJ,IACAqN,EAAEp2C,MAAO,EAELo2C,EAAED,OAAO/uD,OACXgvD,EAAEl6C,SAASk6C,EAAED,QAEbC,EAAEl6C,WAGR,IACAvC,KAAKytC,KAAK,SAAU8O,QACpBv8C,KAAKoY,MAAQpY,KAAKoY,MAAM3L,QAAO,SAAUgwC,GACvC,OAAQA,EAAEp2C,IACZ,GACF,GACC,CACDmE,IAAK,OACL1Y,MAAO,SAAS8qD,KAAKlN,EAAKN,EAAIyN,GAC5B,IAAIxI,EAASr0C,KAET88C,EAAQlsD,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,EAC5E8qB,EAAO9qB,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,IAC3E2R,EAAW3R,UAAUnD,OAAS,EAAImD,UAAU,QAAK6D,EACrD,OAAKi7C,EAAIjiD,OACFuS,KAAK67C,QAAQgB,GAAQnN,EAAKN,GAAI,SAAUjtB,EAAKjlB,GAC9CilB,GAAOjlB,GAAQ4/C,EAAQ,EACzBtiC,YAAW,WACT65B,EAAOuI,KAAK1gD,KAAKm4C,EAAQ3E,EAAKN,EAAIyN,EAAQC,EAAQ,EAAU,EAAPphC,EAAUnZ,EACjE,GAAGmZ,GAILnZ,EAAS4f,EAAKjlB,EAChB,IAVwBqF,EAAS,KAAM,CAAC,EAW1C,GACC,CACDiI,IAAK,iBACL1Y,MAAO,SAASirD,eAAef,EAAWt4B,GACxC,IAAI4xB,EAASt1C,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC/E2R,EAAW3R,UAAUnD,OAAS,EAAImD,UAAU,QAAK6D,EAErD,IAAKuL,KAAK67C,QAER,OADA77C,KAAK0sC,OAAOn4C,KAAK,kEACVgO,GAAYA,IAGI,iBAAdy5C,IAAwBA,EAAYh8C,KAAKwzC,cAAcI,mBAAmBoI,IAC3D,iBAAft4B,IAAyBA,EAAa,CAACA,IAClD,IAAIu4B,EAASj8C,KAAK+7C,UAAUC,EAAWt4B,EAAYngB,EAAShB,GAE5D,IAAK05C,EAAOA,OAAOxuD,OAEjB,OADKwuD,EAAOC,QAAQzuD,QAAQ8U,IACrB,KAGT05C,EAAOA,OAAO9sD,SAAQ,SAAU8L,GAC9Bq6C,EAAO0H,QAAQ/hD,EACjB,GACF,GACC,CACDuP,IAAK,OACL1Y,MAAO,SAAS0zB,KAAKw2B,EAAWt4B,EAAYnhB,GAC1CvC,KAAK+8C,eAAef,EAAWt4B,EAAY,CAAC,EAAGnhB,EACjD,GACC,CACDiI,IAAK,SACL1Y,MAAO,SAASwqD,OAAON,EAAWt4B,EAAYnhB,GAC5CvC,KAAK+8C,eAAef,EAAWt4B,EAAY,CACzC44B,QAAQ,GACP/5C,EACL,GACC,CACDiI,IAAK,UACL1Y,MAAO,SAASkrD,QAAQ/hD,GACtB,IAAIgiD,EAASj9C,KAET0wB,EAAS9/B,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,GAC7E2oC,EAAIt+B,EAAK+J,MAAM,KACf0qC,EAAMnW,EAAE,GACR6V,EAAK7V,EAAE,GACXv5B,KAAK48C,KAAKlN,EAAKN,EAAI,YAAQ36C,OAAWA,GAAW,SAAU0tB,EAAKjlB,GAC1DilB,GAAK86B,EAAOvQ,OAAOn4C,KAAK,GAAGvF,OAAO0hC,EAAQ,sBAAsB1hC,OAAOogD,EAAI,kBAAkBpgD,OAAO0gD,EAAK,WAAYvtB,IACpHA,GAAOjlB,GAAM+/C,EAAOvQ,OAAOL,IAAI,GAAGr9C,OAAO0hC,EAAQ,qBAAqB1hC,OAAOogD,EAAI,kBAAkBpgD,OAAO0gD,GAAMxyC,GAErH+/C,EAAOV,OAAOthD,EAAMknB,EAAKjlB,EAC3B,GACF,GACC,CACDsN,IAAK,cACL1Y,MAAO,SAASkiD,YAAYgI,EAAWlwC,EAAWtB,EAAKqpC,EAAeqJ,GACpE,IAAI35C,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAE/EoP,KAAK8wC,SAAS6E,OAAS31C,KAAK8wC,SAAS6E,MAAMC,qBAAuB51C,KAAK8wC,SAAS6E,MAAMC,mBAAmB9pC,GAC3G9L,KAAK0sC,OAAOn4C,KAAK,qBAAsBvF,OAAOwb,EAAK,wBAA0Bxb,OAAO8c,EAAW,wBAA0B,4NAIvHtB,SAA6C,KAARA,IAErCxK,KAAK67C,SAAW77C,KAAK67C,QAAQ1tD,QAC/B6R,KAAK67C,QAAQ1tD,OAAO6tD,EAAWlwC,EAAWtB,EAAKqpC,EAAe,KAAM7I,cAAc,CAAC,EAAGznC,EAAS,CAC7F25C,SAAUA,KAITlB,GAAcA,EAAU,IAC7Bh8C,KAAK87C,MAAMnM,YAAYqM,EAAU,GAAIlwC,EAAWtB,EAAKqpC,GACvD,KAGK+H,SACT,CA1NgB,CA0NdvO,GAsEF,SAAS8P,iBAAiB55C,GAqBxB,MApB0B,iBAAfA,EAAQ6rC,KAAiB7rC,EAAQ6rC,GAAK,CAAC7rC,EAAQ6rC,KACvB,iBAAxB7rC,EAAQmwC,cAA0BnwC,EAAQmwC,YAAc,CAACnwC,EAAQmwC,cAC1C,iBAAvBnwC,EAAQiyC,aAAyBjyC,EAAQiyC,WAAa,CAACjyC,EAAQiyC,aAEtEjyC,EAAQmzC,YACNnzC,EAAQmzC,WAAanzC,EAAQmzC,UAAU1mD,QAAQ,UAAY,IAC7DuT,EAAQmzC,UAAYnzC,EAAQmzC,UAAU1nD,OAAO,CAAC,YAGhDuU,EAAQozC,cAAgBpzC,EAAQmzC,WAG9BnzC,EAAQ65C,uBACV75C,EAAQ8zC,yBAA2B9zC,EAAQ65C,sBAGzC75C,EAAQozC,eAAiBpzC,EAAQozC,cAAc3mD,QAAQ,UAAY,IACrEuT,EAAQozC,cAAgBpzC,EAAQozC,cAAc3nD,OAAO,CAAC,YAGjDuU,CACT,CAEA,SAASY,OAAQ,CA0gBjB,QAFc,IAtgBH,SAAUgrC,GAGnB,SAASkO,OACP,IAAI7P,EAEAjqC,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC/E2R,EAAW3R,UAAUnD,OAAS,EAAImD,UAAU,QAAK6D,EAiBrD,GAfA02C,gBAAgBnrC,KAAMq9C,MAEtB7P,EAAQ3B,2BAA2B7rC,KAAM8rC,gBAAgBuR,MAAMnhD,KAAK8D,OAEhE+uC,GACF1B,EAAanxC,KAAKyvC,uBAAuB6B,IAG3CA,EAAMjqC,QAAU45C,iBAAiB55C,GACjCiqC,EAAMsD,SAAW,CAAC,EAClBtD,EAAMd,OAASH,EACfiB,EAAM8P,QAAU,CACdC,SAAU,IAGRh7C,IAAairC,EAAMgQ,gBAAkBj6C,EAAQk6C,QAAS,CACxD,IAAKjQ,EAAMjqC,QAAQm6C,cAGjB,OAFAlQ,EAAM5rC,KAAK2B,EAAShB,GAEbspC,2BAA2B2B,EAAO7B,uBAAuB6B,IAGlEhzB,YAAW,WACTgzB,EAAM5rC,KAAK2B,EAAShB,EACtB,GAAG,EACL,CAEA,OAAOirC,CACT,CA8dA,OAlgBAvB,UAAUoR,KAAMlO,GAsChB3D,aAAa6R,KAAM,CAAC,CAClB7yC,IAAK,OACL1Y,MAAO,SAAS8P,OACd,IAAI8vC,EAAS1xC,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC/E2R,EAAW3R,UAAUnD,OAAS,EAAImD,UAAU,QAAK6D,EAmBrD,SAASkpD,oBAAoBC,GAC3B,OAAKA,EACwB,mBAAlBA,EAAqC,IAAIA,EAC7CA,EAFoB,IAG7B,CAEA,GAvBuB,mBAAZr6C,IACThB,EAAWgB,EACXA,EAAU,CAAC,GAGTA,EAAQmzC,YAAcnzC,EAAQozC,eAChC32C,KAAK0sC,OAAOK,UAAU,YAAa,0HAGjCxpC,EAAQ65C,uBAAyB75C,EAAQ8zC,0BAC3Cr3C,KAAK0sC,OAAOK,UAAU,YAAa,iJAGrC/sC,KAAKuD,QAAUynC,cAAc,CAAC,EA1JpC,SAAS,cACP,MAAO,CACL2B,OAAO,EACP+Q,eAAe,EACftO,GAAI,CAAC,eACLC,UAAW,CAAC,eACZqE,YAAa,CAAC,OACd8B,YAAY,EACZkB,WAAW,EACX0G,sBAAsB,EACtBzG,eAAe,EACfU,0BAA0B,EAC1B7xB,KAAM,MACNq4B,SAAS,EACT5E,sBAAsB,EACtB3J,aAAc,IACd+B,YAAa,IACbyM,gBAAiB,IACjB5H,iBAAkB,IAClB6H,yBAAyB,EACzB/J,aAAa,EACbZ,eAAe,EACfO,cAAe,WACfM,oBAAoB,EACpBH,mBAAmB,EACnBiH,6BAA6B,EAC7B/F,aAAa,EACbG,yBAAyB,EACzBgB,YAAY,EACZC,mBAAmB,EACnB7D,eAAe,EACfJ,YAAY,EACZK,uBAAuB,EACvB4B,wBAAwB,EACxBD,6BAA6B,EAC7BtC,yBAAyB,EACzBF,iCAAkC,SAAS9tB,OAAOn1B,GAChD,IAAIyT,EAAM,CAAC,EAKX,GAJyB,WAArBlP,QAAQvE,EAAK,MAAkByT,EAAMzT,EAAK,IACvB,iBAAZA,EAAK,KAAiByT,EAAIsS,aAAe/lB,EAAK,IAClC,iBAAZA,EAAK,KAAiByT,EAAI67C,aAAetvD,EAAK,IAEhC,WAArBuE,QAAQvE,EAAK,KAAyC,WAArBuE,QAAQvE,EAAK,IAAkB,CAClE,IAAI6U,EAAU7U,EAAK,IAAMA,EAAK,GAC9Bd,OAAO0c,KAAK/G,GAASpU,SAAQ,SAAUqb,GACrCrI,EAAIqI,GAAOjH,EAAQiH,EACrB,GACF,CAEA,OAAOrI,CACT,EACA+uC,cAAe,CACboI,aAAa,EACbD,OAAQ,SAASA,OAAOvnD,EAAOmsD,EAASvO,EAAKnsC,GAC3C,OAAOzR,CACT,EACA4+B,OAAQ,KACR78B,OAAQ,KACR8lD,gBAAiB,IACjBC,eAAgB,IAChBE,cAAe,MACfE,cAAe,IACfE,wBAAyB,IACzBC,YAAa,IACbzF,iBAAiB,GAGvB,CAuFuC,GAAO10C,KAAKuD,QAAS45C,iBAAiB55C,IACvEvD,KAAKq5C,OAASr5C,KAAKuD,QAAQ2tC,cAAcmI,OACpC92C,IAAUA,EAAW4B,OAQrBnE,KAAKuD,QAAQk6C,QAAS,CACrBz9C,KAAKs9C,QAAQ5Q,OACfH,EAAW3qC,KAAK+7C,oBAAoB39C,KAAKs9C,QAAQ5Q,QAAS1sC,KAAKuD,SAE/DgpC,EAAW3qC,KAAK,KAAM5B,KAAKuD,SAG7B,IAAI26C,EAAK,IAAIzH,EAAaz2C,KAAKuD,SAC/BvD,KAAK87C,MAAQ,IAAI5M,EAAclvC,KAAKuD,QAAQusC,UAAW9vC,KAAKuD,SAC5D,IAAIg2B,EAAIv5B,KAAK8wC,SACbvX,EAAEmT,OAASH,EACXhT,EAAE8c,cAAgBr2C,KAAK87C,MACvBviB,EAAEia,cAAgB0K,EAClB3kB,EAAE0Z,eAAiB,IAAImF,EAAe8F,EAAI,CACxCj0B,QAASjqB,KAAKuD,QAAQu6C,gBACtB3E,kBAAmBn5C,KAAKuD,QAAQ41C,kBAChCF,qBAAsBj5C,KAAKuD,QAAQ01C,uBAErC1f,EAAE+X,aAAe,IAAI8H,EAAap5C,KAAKuD,SACvCg2B,EAAEoc,MAAQ,CACRC,mBAAoB51C,KAAK41C,mBAAmB7mD,KAAKiR,OAEnDu5B,EAAEwa,iBAAmB,IAAI6H,EAAU+B,oBAAoB39C,KAAKs9C,QAAQzB,SAAUtiB,EAAE8c,cAAe9c,EAAGv5B,KAAKuD,SACvGg2B,EAAEwa,iBAAiB3xB,GAAG,KAAK,SAAUI,GACnC,IAAK,IAAI7xB,EAAOC,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMsD,EAAO,EAAIA,EAAO,EAAI,GAAIE,EAAO,EAAGA,EAAOF,EAAME,IAClGnC,EAAKmC,EAAO,GAAKD,UAAUC,GAG7B6gD,EAAOjE,KAAKn/C,MAAMojD,EAAQ,CAAClvB,GAAOxzB,OAAON,GAC3C,IAEIsR,KAAKs9C,QAAQa,mBACf5kB,EAAE4kB,iBAAmBR,oBAAoB39C,KAAKs9C,QAAQa,kBACtD5kB,EAAE4kB,iBAAiBv8C,KAAK23B,EAAGv5B,KAAKuD,QAAQ66C,UAAWp+C,KAAKuD,UAGtDvD,KAAKs9C,QAAQjL,aACf9Y,EAAE8Y,WAAasL,oBAAoB39C,KAAKs9C,QAAQjL,YAC5C9Y,EAAE8Y,WAAWzwC,MAAM23B,EAAE8Y,WAAWzwC,KAAK5B,OAG3CA,KAAK0wC,WAAa,IAAIG,EAAW7wC,KAAK8wC,SAAU9wC,KAAKuD,SACrDvD,KAAK0wC,WAAWtuB,GAAG,KAAK,SAAUI,GAChC,IAAK,IAAI1xB,EAAQF,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAMyD,EAAQ,EAAIA,EAAQ,EAAI,GAAIC,EAAQ,EAAGA,EAAQD,EAAOC,IACxGrC,EAAKqC,EAAQ,GAAKH,UAAUG,GAG9B2gD,EAAOjE,KAAKn/C,MAAMojD,EAAQ,CAAClvB,GAAOxzB,OAAON,GAC3C,IACAsR,KAAKs9C,QAAQC,SAASpuD,SAAQ,SAAUma,GAClCA,EAAE1H,MAAM0H,EAAE1H,KAAK8vC,EACrB,GACF,CAEA,GAAI1xC,KAAKuD,QAAQmwC,cAAgB1zC,KAAK8wC,SAASqN,mBAAqBn+C,KAAKuD,QAAQmsC,IAAK,CACpF,IAAIgG,EAAQ11C,KAAK8wC,SAAS0C,cAAcC,iBAAiBzzC,KAAKuD,QAAQmwC,aAClEgC,EAAMjoD,OAAS,GAAkB,QAAbioD,EAAM,KAAc11C,KAAKuD,QAAQmsC,IAAMgG,EAAM,GACvE,CAEK11C,KAAK8wC,SAASqN,kBAAqBn+C,KAAKuD,QAAQmsC,KACnD1vC,KAAK0sC,OAAOn4C,KAAK,2DAGJ,CAAC,cAAe,oBAAqB,oBAAqB,qBAChEpF,SAAQ,SAAU0tD,GACzBnL,EAAOmL,GAAU,WACf,IAAIwB,EAEJ,OAAQA,EAAe3M,EAAOoK,OAAOe,GAAQvuD,MAAM+vD,EAAcztD,UACnE,CACF,IACsB,CAAC,cAAe,eAAgB,oBAAqB,wBAC3DzB,SAAQ,SAAU0tD,GAChCnL,EAAOmL,GAAU,WACf,IAAIyB,EAIJ,OAFCA,EAAgB5M,EAAOoK,OAAOe,GAAQvuD,MAAMgwD,EAAe1tD,WAErD8gD,CACT,CACF,IACA,IAAIz4B,EAAWkF,QAEXqH,EAAO,SAASA,OAClB,IAAIwP,EAAS,SAASA,OAAO7S,EAAKoB,GAC5BmuB,EAAO8L,eAAe9L,EAAOhF,OAAOn4C,KAAK,yEAC7Cm9C,EAAO8L,eAAgB,EAClB9L,EAAOnuC,QAAQk6C,SAAS/L,EAAOhF,OAAOL,IAAI,cAAeqF,EAAOnuC,SAErEmuC,EAAOjE,KAAK,cAAeiE,EAAOnuC,SAElC0V,EAAS3B,QAAQiM,GACjBhhB,EAAS4f,EAAKoB,EAChB,EAEA,GAAImuB,EAAOsK,WAAiD,OAApCtK,EAAOnuC,QAAQ6sC,mBAA8BsB,EAAO8L,cAAe,OAAOxoB,EAAO,KAAM0c,EAAOnuB,EAAEx0B,KAAK2iD,IAE7HA,EAAOX,eAAeW,EAAOnuC,QAAQmsC,IAAK1a,EAC5C,EAQA,OANIh1B,KAAKuD,QAAQusC,YAAc9vC,KAAKuD,QAAQm6C,cAC1Cl4B,IAEAhL,WAAWgL,EAAM,GAGZvM,CACT,GACC,CACDzO,IAAK,gBACL1Y,MAAO,SAASysD,cAAcvN,GAC5B,IAAIqD,EAASr0C,KAGTw+C,EADW5tD,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAKuT,KAE/EmwC,EAA8B,iBAAbtD,EAAwBA,EAAWhxC,KAAKgxC,SAG7D,GAFwB,mBAAbA,IAAyBwN,EAAexN,IAE9ChxC,KAAKuD,QAAQusC,WAAa9vC,KAAKuD,QAAQw6C,wBAAyB,CACnE,GAAIzJ,GAAqC,WAA1BA,EAAQ5kD,cAA4B,OAAO8uD,IAC1D,IAAIvC,EAAS,GAETjyB,EAAS,SAASA,OAAO0lB,GACtBA,GAEM2E,EAAOvD,SAAS0C,cAAcI,mBAAmBlE,GAEvDvgD,SAAQ,SAAUgC,GACjB8qD,EAAOjsD,QAAQmB,GAAK,GAAG8qD,EAAO1sD,KAAK4B,EACzC,GACF,EAEA,GAAKmjD,EAMHtqB,EAAOsqB,QALSt0C,KAAK8wC,SAAS0C,cAAcC,iBAAiBzzC,KAAKuD,QAAQmwC,aAChEvkD,SAAQ,SAAUgC,GAC1B,OAAO64B,EAAO74B,EAChB,IAKE6O,KAAKuD,QAAQs6C,SACf79C,KAAKuD,QAAQs6C,QAAQ1uD,SAAQ,SAAUgC,GACrC,OAAO64B,EAAO74B,EAChB,IAGF6O,KAAK8wC,SAASiD,iBAAiBvuB,KAAKy2B,EAAQj8C,KAAKuD,QAAQ6rC,GAAIoP,EAC/D,MACEA,EAAa,KAEjB,GACC,CACDh0C,IAAK,kBACL1Y,MAAO,SAAS2sD,gBAAgBnL,EAAMlE,EAAI7sC,GACxC,IAAI0W,EAAWkF,QAQf,OAPKm1B,IAAMA,EAAOtzC,KAAKg8C,WAClB5M,IAAIA,EAAKpvC,KAAKuD,QAAQ6rC,IACtB7sC,IAAUA,EAAW4B,MAC1BnE,KAAK8wC,SAASiD,iBAAiBuI,OAAOhJ,EAAMlE,GAAI,SAAUjtB,GACxDlJ,EAAS3B,UACT/U,EAAS4f,EACX,IACOlJ,CACT,GACC,CACDzO,IAAK,MACL1Y,MAAO,SAAS4sD,IAAIzxD,GAClB,IAAKA,EAAQ,MAAM,IAAI8S,MAAM,iGAC7B,IAAK9S,EAAO6T,KAAM,MAAM,IAAIf,MAAM,4FA0BlC,MAxBoB,YAAhB9S,EAAO6T,OACTd,KAAKs9C,QAAQzB,QAAU5uD,IAGL,WAAhBA,EAAO6T,MAAqB7T,EAAOo/C,KAAOp/C,EAAOsH,MAAQtH,EAAOgX,SAClEjE,KAAKs9C,QAAQ5Q,OAASz/C,GAGJ,qBAAhBA,EAAO6T,OACTd,KAAKs9C,QAAQa,iBAAmBlxD,GAGd,eAAhBA,EAAO6T,OACTd,KAAKs9C,QAAQjL,WAAaplD,GAGR,kBAAhBA,EAAO6T,MACTyvC,EAAcE,iBAAiBxjD,GAGb,aAAhBA,EAAO6T,MACTd,KAAKs9C,QAAQC,SAAShuD,KAAKtC,GAGtB+S,IACT,GACC,CACDwK,IAAK,iBACL1Y,MAAO,SAASi/C,eAAerB,EAAKntC,GAClC,IAAI+yC,EAASt1C,KAEbA,KAAK2+C,qBAAuBjP,EAC5B,IAAIz2B,EAAWkF,QACfne,KAAKytC,KAAK,mBAAoBiC,GAE9B,IAwBIkP,EAAS,SAASA,OAAOtL,GAC3B,IAAIniD,EAAoB,iBAATmiD,EAAoBA,EAAOgC,EAAOxE,SAAS0C,cAAc8D,sBAAsBhE,GAE1FniD,IACGmkD,EAAOtE,WACVsE,EAAOtE,SAAW7/C,EAClBmkD,EAAO0G,UAAY1G,EAAOxE,SAAS0C,cAAcI,mBAAmBziD,IAGjEmkD,EAAO5E,WAAWM,UAAUsE,EAAO5E,WAAWK,eAAe5/C,GAC9DmkD,EAAOxE,SAASqN,kBAAkB7I,EAAOxE,SAASqN,iBAAiBU,kBAAkB1tD,IAG3FmkD,EAAOiJ,cAAcptD,GAAG,SAAUgxB,IArCzB,SAAS9b,KAAK8b,EAAKhxB,GACxBA,GACFmkD,EAAOtE,SAAW7/C,EAClBmkD,EAAO0G,UAAY1G,EAAOxE,SAAS0C,cAAcI,mBAAmBziD,GAEpEmkD,EAAO5E,WAAWK,eAAe5/C,GAEjCmkD,EAAOqJ,0BAAuBlqD,EAE9B6gD,EAAO7H,KAAK,kBAAmBt8C,GAE/BmkD,EAAO5I,OAAOL,IAAI,kBAAmBl7C,IAErCmkD,EAAOqJ,0BAAuBlqD,EAGhCwkB,EAAS3B,SAAQ,WACf,OAAOg+B,EAAO/xB,EAAEj1B,MAAMgnD,EAAQ1kD,UAChC,IACI2R,GAAUA,EAAS4f,GAAK,WAC1B,OAAOmzB,EAAO/xB,EAAEj1B,MAAMgnD,EAAQ1kD,UAChC,GACF,CAgBIyV,CAAK8b,EAAKhxB,EACZ,GACF,EAUA,OARKu+C,IAAO1vC,KAAK8wC,SAASqN,kBAAqBn+C,KAAK8wC,SAASqN,iBAAiBxiB,OAElE+T,GAAO1vC,KAAK8wC,SAASqN,kBAAoBn+C,KAAK8wC,SAASqN,iBAAiBxiB,MAClF37B,KAAK8wC,SAASqN,iBAAiBW,OAAOF,GAEtCA,EAAOlP,GAJPkP,EAAO5+C,KAAK8wC,SAASqN,iBAAiBW,UAOjC7lC,CACT,GACC,CACDzO,IAAK,YACL1Y,MAAO,SAASitD,UAAUrP,EAAKN,GAC7B,IAAI6N,EAASj9C,KAETg/C,EAAS,SAASA,OAAOx0C,EAAK2oB,GAChC,IAAI5vB,EAEJ,GAAsB,WAAlBtQ,QAAQkgC,GAAoB,CAC9B,IAAK,IAAI0Z,EAAQj8C,UAAUnD,OAAQwxD,EAAO,IAAI5xD,MAAMw/C,EAAQ,EAAIA,EAAQ,EAAI,GAAIC,EAAQ,EAAGA,EAAQD,EAAOC,IACxGmS,EAAKnS,EAAQ,GAAKl8C,UAAUk8C,GAG9BvpC,EAAU05C,EAAO15C,QAAQouC,iCAAiC,CAACnnC,EAAK2oB,GAAMnkC,OAAOiwD,GAC/E,MACE17C,EAAUynC,cAAc,CAAC,EAAG7X,GAM9B,OAHA5vB,EAAQmsC,IAAMnsC,EAAQmsC,KAAOsP,OAAOtP,IACpCnsC,EAAQ+vC,KAAO/vC,EAAQ+vC,MAAQ0L,OAAO1L,KACtC/vC,EAAQ6rC,GAAK7rC,EAAQ6rC,IAAM4P,OAAO5P,GAC3B6N,EAAO15B,EAAE/Y,EAAKjH,EACvB,EASA,MAPmB,iBAARmsC,EACTsP,EAAOtP,IAAMA,EAEbsP,EAAO1L,KAAO5D,EAGhBsP,EAAO5P,GAAKA,EACL4P,CACT,GACC,CACDx0C,IAAK,IACL1Y,MAAO,SAASyxB,IACd,IAAI27B,EAEJ,OAAOl/C,KAAK0wC,aAAewO,EAAmBl/C,KAAK0wC,YAAYc,UAAUljD,MAAM4wD,EAAkBtuD,UACnG,GACC,CACD4Z,IAAK,SACL1Y,MAAO,SAASm/C,SACd,IAAIkO,EAEJ,OAAOn/C,KAAK0wC,aAAeyO,EAAoBn/C,KAAK0wC,YAAYO,OAAO3iD,MAAM6wD,EAAmBvuD,UAClG,GACC,CACD4Z,IAAK,sBACL1Y,MAAO,SAASstD,oBAAoBhQ,GAClCpvC,KAAKuD,QAAQ8rC,UAAYD,CAC3B,GACC,CACD5kC,IAAK,qBACL1Y,MAAO,SAAS8jD,mBAAmBxG,GACjC,IAAIiQ,EAASr/C,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAEnF,IAAKoP,KAAKw9C,cAER,OADAx9C,KAAK0sC,OAAOn4C,KAAK,kDAAmDyL,KAAKg8C,YAClE,EAGT,IAAKh8C,KAAKg8C,YAAch8C,KAAKg8C,UAAUvuD,OAErC,OADAuS,KAAK0sC,OAAOn4C,KAAK,6DAA8DyL,KAAKg8C,YAC7E,EAGT,IAAItM,EAAM1vC,KAAKg8C,UAAU,GACrBtI,IAAc1zC,KAAKuD,SAAUvD,KAAKuD,QAAQmwC,YAC1C4L,EAAUt/C,KAAKg8C,UAAUh8C,KAAKg8C,UAAUvuD,OAAS,GACrD,GAA0B,WAAtBiiD,EAAIhgD,cAA4B,OAAO,EAE3C,IAAI6vD,EAAiB,SAASA,eAAepuD,EAAG8jB,GAC9C,IAAIuqC,EAAYH,EAAOvO,SAASiD,iBAAiBh7B,MAAM,GAAG/pB,OAAOmC,EAAG,KAAKnC,OAAOimB,IAEhF,OAAsB,IAAfuqC,GAAkC,IAAdA,CAC7B,EAEA,GAAIj8C,EAAQk8C,SAAU,CACpB,IAAIC,EAAYn8C,EAAQk8C,SAASz/C,KAAMu/C,GACvC,QAAkB9qD,IAAdirD,EAAyB,OAAOA,CACtC,CAEA,QAAI1/C,KAAKkwC,kBAAkBR,EAAKN,MAC3BpvC,KAAK8wC,SAASiD,iBAAiB8H,YAChC0D,EAAe7P,EAAKN,IAASsE,IAAe6L,EAAeD,EAASlQ,IAE1E,GACC,CACD5kC,IAAK,iBACL1Y,MAAO,SAAS6tD,eAAevQ,EAAI7sC,GACjC,IAAIq9C,EAAS5/C,KAETiZ,EAAWkF,QAEf,OAAKne,KAAKuD,QAAQ6rC,IAKA,iBAAPA,IAAiBA,EAAK,CAACA,IAClCA,EAAGjgD,SAAQ,SAAU8lB,GACf2qC,EAAOr8C,QAAQ6rC,GAAGp/C,QAAQilB,GAAK,GAAG2qC,EAAOr8C,QAAQ6rC,GAAG7/C,KAAK0lB,EAC/D,IACAjV,KAAKu+C,eAAc,SAAUp8B,GAC3BlJ,EAAS3B,UACL/U,GAAUA,EAAS4f,EACzB,IACOlJ,IAZL1W,GAAYA,IACLsrC,QAAQv2B,UAYnB,GACC,CACD9M,IAAK,gBACL1Y,MAAO,SAAS+tD,cAAcvM,EAAM/wC,GAClC,IAAI0W,EAAWkF,QACK,iBAATm1B,IAAmBA,EAAO,CAACA,IACtC,IAAIwM,EAAY9/C,KAAKuD,QAAQs6C,SAAW,GACpCkC,EAAUzM,EAAK7mC,QAAO,SAAUijC,GAClC,OAAOoQ,EAAU9vD,QAAQ0/C,GAAO,CAClC,IAEA,OAAKqQ,EAAQtyD,QAKbuS,KAAKuD,QAAQs6C,QAAUiC,EAAU9wD,OAAO+wD,GACxC//C,KAAKu+C,eAAc,SAAUp8B,GAC3BlJ,EAAS3B,UACL/U,GAAUA,EAAS4f,EACzB,IACOlJ,IATD1W,GAAUA,IACPsrC,QAAQv2B,UASnB,GACC,CACD9M,IAAK,MACL1Y,MAAO,SAASmX,IAAIymC,GAElB,GADKA,IAAKA,EAAM1vC,KAAKg8C,WAAah8C,KAAKg8C,UAAUvuD,OAAS,EAAIuS,KAAKg8C,UAAU,GAAKh8C,KAAKgxC,WAClFtB,EAAK,MAAO,MAEjB,MADc,CAAC,KAAM,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,KAAM,KAAM,KAAM,MAAO,MAAO,MAAO,MAAO,MAAO,KAAM,KAAM,MAAO,MAAO,MAAO,KAAM,KAAM,MAAO,MAAO,MAAO,KAAM,MAAO,MAAO,MAAO,MAAO,KAAM,OAC1Z1/C,QAAQgQ,KAAK8wC,SAAS0C,cAAcsD,wBAAwBpH,KAAS,EAAI,MAAQ,KAClG,GACC,CACDllC,IAAK,iBACL1Y,MAAO,SAASkuD,iBAGd,OAAO,IAAI3C,KAFGzsD,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EACpEA,UAAUnD,OAAS,EAAImD,UAAU,QAAK6D,EAEvD,GACC,CACD+V,IAAK,gBACL1Y,MAAO,SAASmuD,gBACd,IAAIC,EAASlgD,KAETuD,EAAU3S,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAK,CAAC,EAC/E2R,EAAW3R,UAAUnD,OAAS,QAAsBgH,IAAjB7D,UAAU,GAAmBA,UAAU,GAAKuT,KAE/Eg8C,EAAgBnV,cAAc,CAAC,EAAGhrC,KAAKuD,QAASA,EAAS,CAC3Dk6C,SAAS,IAGPnsD,EAAQ,IAAI+rD,KAAK8C,GAsBrB,MArBoB,CAAC,QAAS,WAAY,YAC5BhxD,SAAQ,SAAUma,GAC9BhY,EAAMgY,GAAK42C,EAAO52C,EACpB,IACAhY,EAAMw/C,SAAW9F,cAAc,CAAC,EAAGhrC,KAAK8wC,UACxCx/C,EAAMw/C,SAAS6E,MAAQ,CACrBC,mBAAoBtkD,EAAMskD,mBAAmB7mD,KAAKuC,IAEpDA,EAAMo/C,WAAa,IAAIG,EAAWv/C,EAAMw/C,SAAUx/C,EAAMiS,SACxDjS,EAAMo/C,WAAWtuB,GAAG,KAAK,SAAUI,GACjC,IAAK,IAAIwqB,EAAQp8C,UAAUnD,OAAQiB,EAAO,IAAIrB,MAAM2/C,EAAQ,EAAIA,EAAQ,EAAI,GAAIC,EAAQ,EAAGA,EAAQD,EAAOC,IACxGv+C,EAAKu+C,EAAQ,GAAKr8C,UAAUq8C,GAG9B37C,EAAMm8C,KAAKn/C,MAAMgD,EAAO,CAACkxB,GAAOxzB,OAAON,GACzC,IACA4C,EAAMsQ,KAAKu+C,EAAe59C,GAC1BjR,EAAMo/C,WAAWntC,QAAUjS,EAAMiS,QACjCjS,EAAMo/C,WAAWqD,iBAAiBjD,SAAS6E,MAAQ,CACjDC,mBAAoBtkD,EAAMskD,mBAAmB7mD,KAAKuC,IAE7CA,CACT,KAGK+rD,IACT,CApgBW,CAogBThQ,ICjvEI+S,EAAkB,YAClBC,EAAiB,OACjBC,EAAsB,GAUtBC,wBAA0B,CAACC,EAAaC,KAClBC,eAAQF,GAC9BJ,EACAI,EAAY1wD,QAAQ,MAAO,MAIJ,KAHF4wD,eAAQD,GAC7BJ,EACAI,EAAW3wD,QAAQ,MAAO,MA8G1B6wD,2BAA6B,KACjC,MAAMC,EACJN,EAAoBO,WACjB/0C,IAAwC,IAA1BA,EAAUg1C,eACtB,EAYP,OAVKF,IAtEL5Z,8BACExzC,OACA,2BACAgH,SAoEe,IAEfhH,OAAOutD,cACL,IAAIC,YAAY,2BAA4B,CAC1C36B,SAAS,OAKPu6B,CAAR,EAaIK,4BAA+BC,IACnC,MAAMlQ,EAAWmQ,EAAAA,UAAAA,GACjB,GAAIxa,aAAMua,GACR,OAAO,EAGT,MAAME,EAAexzD,OAAO0c,KAAK42C,GAEjCC,EAAAA,MAAAA,GAAiB,SAAS,CAACzR,EAAKN,KAE9BkR,EAAoB3zC,MAAM00C,GAAUA,EAAMpmD,OAASm0C,IAAnD,aAEI,EACJuR,4BAA4B,IAG9BS,EAAajyD,SAASqxD,IACJ5yD,OAAO0c,KAAK42C,EAAUV,IAC9BrxD,SAASsxD,IACf,MAAM30C,EAAYy0C,wBAAwBC,EAAaC,GACjDa,EAAeJ,EAAUV,GAAaC,GACvC9Z,aAAM2a,IACTH,EAAAA,kBACEnQ,EACAllC,EAnGkBw1C,KACF1zD,OAAO0c,KAAKg3C,GACpBnyD,SAASqb,IACnBnd,MAAMC,QAAQg0D,EAAa92C,KAC7B82C,EAAa92C,GAAKrb,SAAQ,CAACoyD,EAAYlrC,KACrC,IAAImrC,EAASh3C,EACT2tC,OAAOsJ,UAAUprC,IAAoB,IAAVA,IAC7BmrC,EAAU,GAAEh3C,YAEd82C,EAAaE,GAAUD,CAAvB,GAEH,IAGID,GAsFCI,CAAmBJ,IACnB,GACA,EAEH,GAXH,GAFF,EAiCI9P,UAAY,CAChB3nC,EACA83C,EACAC,EACAvjC,EACAwjC,EACAngD,EACAogD,KAEAj4C,EAAKA,EAAG/Z,QAAQ,MAAO,KA1LJ,IAAC0wD,EAAaC,EA4LjC,MAAMv5C,GA5L2Bu5C,EA2LUpiC,GA1LjBqiC,eADNF,EA2LWoB,GAzL3BxB,EACAI,EAAYtwD,QAIW,KAHFwwD,eAAQD,GAC7BJ,EACAI,EAAWvwD,SAsLgB,IAAM2Z,EAAG3Z,OAExC,IAAIqT,EAAU,CAAC,EAaf,OAZKojC,aAAMmb,KACTv+C,EAAO,MAAYu+C,GAGhBnb,aAAMkb,KACTt+C,EAAO,QAAcs+C,GAGlBnB,eAAQiB,KACXp+C,EAAO,aAAmBo+C,GAGrBR,EAAAA,EAAUj6C,EAAY3D,EAA7B,EAGI3B,kBAAO,KACP+kC,aAAMnzC,OAAO40C,WACf50C,OAAO40C,QAAU,CAAC,GAGhBzB,aAAMnzC,OAAO40C,QAAQiV,QACvB7pD,OAAO40C,QAAQiV,KAAO,CACpBz7C,KAAMA,kBACN4vC,UACAsP,aAAa,GAEhB,EA+BH,GAAiBl/C,KAAF,kBAAQmgD,iBA5BGb,IAExB,MAAM39C,EAAU,CACd2tC,cAAe,CACbxgB,OAAQ,IACR78B,OAAQ,KAEVi8C,UAAW,CAAC,GAIRkS,EAxNmB,MACzB,MAAMC,EAAWpb,gCACfrzC,OAAO40C,QACP,0BAEF,OAAIzB,aAAMsb,GACD,GAES,IAAIC,IAAID,GAAUE,aACnBtwD,IAAI,SAArB,EA+MwBuwD,GACxB,IAAK1B,eAAQsB,GAAkB,CAK7Bz+C,EAHuBy+C,EAAgBpyD,MAAM,uBACzC,MACA,eACsBoyD,CAC3B,CAlKmCd,KACpC,GAAIva,aAAMua,GACR,OAAO,EAEYtzD,OAAO0c,KAAK42C,GACpB/xD,SAASqxD,IACJ5yD,OAAO0c,KAAK42C,EAAUV,IAC9BrxD,SAASsxD,IACf,MAAM30C,EAAYy0C,wBAAwBC,EAAaC,GACjDa,EAAeJ,EAAUV,GAAaC,GACvC9Z,aAAM2a,IACThB,EAAoB/wD,KAAK,CAAE0L,KAAM6Q,EAAWg1C,aAAa,GAC1D,GALH,GAFF,EA+JAuB,CAA6BnB,GAG7BC,EAAAA,KAAa59C,GAAS,CAAC4e,EAAKoB,KAC1B09B,4BAA4BC,EAA5B,GADF,EAKuC1P,WCrPzC,uBAnCiBhnC,IACf,IACE,OAAO+S,KAAKC,MAAMhqB,OAAO8uD,eAAe7b,QAAQj8B,GACjD,CAAC,MAAOrB,GACP,MACD,GA8BH,uBApBgB,CAACqB,EAAK1Y,KACpB,IACE0B,OAAO8uD,eAAerb,QAAQz8B,EAAK+S,KAAK2pB,UAAUp1C,GACnD,CAAC,MAAOqX,GAEP3V,OAAO8uD,eAAe3X,QACtBn3C,OAAO8uD,eAAerb,QAAQz8B,EAAK+S,KAAK2pB,UAAUp1C,GACnD,GC1BY,MAAMywD,WACjBlvD,YAAYmvD,EAAWC,GACnB,GAAI9b,aAAM6b,GAAY,CAClB,IAAIE,EAAY,mDAChBA,GAAa,sDACbA,GAAa,4BACbpuD,QAAQ2P,MAAMy+C,EACjB,CAGD,GAFA1iD,KAAKwiD,UAAYA,EAEb7b,aAAM8b,GAAa,CACnB,IAAIE,EAAY,8CAChBA,GAAa,wDACbruD,QAAQ2P,MAAM0+C,EACjB,CACD3iD,KAAKyiD,WAAaA,CACrB,CAEmB,qBAACv7C,GACjB,MAAMhK,EAAO,CACT0lD,KAAM17C,EACNmyC,OAAQ,QAEN5a,QAAiBokB,MAAM7iD,KAAKwiD,UAAY,cAAe,CACzD/qC,OAAQ,OACRqrC,YAAa,UACb5kB,QAASl+B,KAAK+iD,aACdlnD,KAAM0hB,KAAK2pB,UAAUhqC,KAGzB,aAAauhC,EAAS3C,MACzB,CAEe,mBACZ,MAAM2C,QAAiBokB,MAAM7iD,KAAKwiD,UAAY,SAAU,CACpD/qC,OAAQ,MACRqrC,YAAa,UACb5kB,QAASl+B,KAAK+iD,eAGlB,aAAatkB,EAAS3C,MACzB,CAEgB,oBACb,MAAM2C,QAAiBokB,MAAM7iD,KAAKwiD,UAAY,UAAW,CACrD/qC,OAAQ,OACRqrC,YAAa,UACb5kB,QAASl+B,KAAK+iD,eAGlB,aAAatkB,EAAS3C,MACzB,CAEDinB,aACI,MAAO,CACHC,OAAQ,mBACR,eAAgB,mBAChB,mBAAoBhjD,KAAKyiD,WAEhC,EC5DL,MAOA,yBAP0B,CAACt5B,EAAY3e,EAAK1Y,IACpC,aAAMq3B,GACC,KAGJA,EAAWxc,MAAMpb,GAAWA,EAAOiZ,KAAS1Y,ICkBvD,cAhBa,KACP60C,aAAMnzC,OAAO40C,WACf50C,OAAO40C,QAAU,CAAC,GAGhBzB,aAAMnzC,OAAO40C,QAAQ6a,UACvBzvD,OAAO40C,QAAQ6a,OAAS,CACtBtc,MADsB,aAEtB+Z,QAFsB,eAGtBwC,kBAHsB,yBAItBrc,yBAJsB,gCAKtBG,uBAAsBA,+BAEzB,EChBY,MAAMmc,SACjB9vD,YAAYwxC,GACR,MAAMue,EAAiBzvD,SAAS0xC,cAAc,qBAC9CrlC,KAAKyiD,WAAc9b,aAAMyc,GAEnB,GADAA,EAAenvD,aAAa,mBAElC+L,KAAK6kC,MAAQA,EACb7kC,KAAKqjD,YAAc,IAAId,WARb,qBAQmCviD,KAAKyiD,YAE7C9b,aAAM9B,IACP7kC,KAAKsjD,yBAEZ,CAEDC,qBAAqBX,GACjB,MAAMY,EAAmBxjD,KAAK6kC,MAAMQ,cAAc,uBAClD,GAAIsB,aAAM6c,IAAqB7c,aAAMic,GACjC,OAAO,EAIX,MAAMa,EAAkB9vD,SAASuC,cAAc,MAC/CutD,EAAgBnmD,UCvBDslD,KACnB,MAAMc,EAAmB,CACrBC,MAAO,4BAGX,IAAI/mD,EAAa,GACjBhP,OAAO0c,KAAKo5C,GAAkBv0D,SAASqb,IACnC5N,GAAe,GAAE4N,MAAQk5C,EAAiBl5C,MAA1C,IAGJ,MAAMo5C,EAAejd,aAAMnzC,OAAO40C,SAC5B50C,OAAO40C,QAAQiV,KAAK7L,UAClB,sCACA,qBACA,YACA,OACAoR,EAAKiB,mBAEN,iBAAgBjB,EAAKiB,qBAC5B,MAAQ,WAAUjnD,8CAAiCgnD,YAAnD,EDIgCE,CAAclB,GAC1CY,EAAiBzkD,YAAY0kD,GAG7B,MAAMM,EAAuBP,EAAiBne,cAC1C,iBAECsB,aAAMod,IACPA,EAAqB53C,iBACjB,QACAnM,KAAKgkD,aAAaj1D,KAAKiR,MAGlC,CAEDsjD,0BACqBtjD,KAAKqjD,YAAYY,aAE7BrsC,MAAM1a,IACH,MAAM,OAAEgnD,EAAF,OAAUxmB,GAAWxgC,EACvBwgC,IAAWiJ,aAAMud,IACjBlkD,KAAKujD,qBAAqBW,EAC7B,IAEJ1oC,OAAM,SAAUvX,GAEhB,GACR,CAED+/C,aAAaxhC,GACTA,EAAMS,iBACN,MAAMkC,EAAS3C,EAAMqC,cACrB,GAAI8hB,aAAMxhB,GACN,OAAO,EAGMnlB,KAAKqjD,YAAYc,cAE7BvsC,MAAM1a,IACH,MAAM,OAAEgnD,EAAF,YAAUE,EAAV,OAAuB1mB,GAAWxgC,EAClCie,EAAU3nB,OAAO40C,QAAQiV,KAAK7L,UAChC,kCACA,kDACA,YACA,OACA,CACI,EAAG4S,EAAYP,kBACf,EAAGK,EAAOL,oBAGlBrwD,OAAO40C,QAAQyC,aAAajC,GAAGztB,GAI/B3nB,OAAO+c,SAAS8zC,SAAW,OAA3B,IAEH7oC,OAAM,SAAUvX,GACb,GAAIzQ,OAAO40C,QAAS,CAChB,MAAMjtB,EAAU3nB,OAAO40C,QAAQiV,KAAK7L,UAChC,gCACA,8CACA,aAEJh+C,OAAO40C,QAAQyC,aAAa5mC,MAAMkX,EACrC,CACJ,GACR,EE3FL,MACMmpC,EAAoB3d,aAAMnzC,OAAO+wD,WAEnC,qBADA/wD,OAAO40C,QAAQiV,KAAK7L,UAAU,4CAA6C,qBAAsB,aCCtF,MAAMgT,eACjBnxD,YAAYwxC,GACR,MAAMue,EAAiBzvD,SAAS0xC,cAAc,qBAC9CrlC,KAAK6kC,MAAQA,EACb7kC,KAAKyiD,WAAc9b,aAAMyc,GAAmE,GAAjDA,EAAenvD,aAAa,mBACvE+L,KAAKqjD,YAAc,IAAId,WANb,qBAMmCviD,KAAKyiD,YAE7C9b,aAAM9B,IACP7kC,KAAKykD,aAEZ,CAEDA,cACIzkD,KAAK0kD,4BACL1kD,KAAK2kD,sBACR,CAEDA,uBAC+B3kD,KAAK6kC,MAAMz6B,iBAAiB,2BACpCjb,SAAQy1D,IACvBA,EAAmBz4C,iBAAiB,QAASnM,KAAK6kD,iBAAiB91D,KAAKiR,MAAxE,GAEP,CAED0kD,4BACmCr3D,MAAMK,KAAKsS,KAAK6kC,MAAMz6B,iBAAiB,6BAC/Cjb,SAAQ21D,IAC3B,MAAMC,EAAeD,EAAiBzf,cAAc,6BAC9C2f,EAAaF,EAAiBzf,cAAc,mBAClD,GAAIsB,aAAMqe,GACN,OAAO,EAGX,MAAMC,EAAgB,IAAI/C,IAAIgD,mBAAmBF,EAAW/wD,aAAa,UAOnEkxD,EDtCQ,EAACj+C,EAAY8B,KACnC,MAAM06C,EAAmB,CACrB,mBAAoB,UACpB,MAASY,EACT,uBAAwBp9C,EACxBy8C,MAAO,oDAGNhd,aAAM39B,KAA0B,IAAbA,IACpB06C,EAAiB16C,UAAW,EAC5B06C,EAAiBC,OAAS,kBAG9B,IAAI/mD,EAAa,GAKjB,OAJAhP,OAAO0c,KAAKo5C,GAAkBv0D,SAAQqb,IAClC5N,GAAe,GAAE4N,MAAQk5C,EAAiBl5C,MAA1C,IAGI,WAAU5N,qDAAlB,ECoBwCwoD,CAND,IAAIC,gBAAgBJ,EAAcK,QAGnBzzD,IAAI,sCAC3B80C,aAAMoe,IAAiBA,EAAa5f,UAAUl/B,SAAS,kBAGxEs/C,EAAqB5xD,SAASuC,cAAc,OAClDqvD,EAAmBjoD,UAAY6nD,EAC/BH,EAAWQ,cAAczmD,YAAYwmD,EAAmBvmD,WAAxD,GAEP,CAED6lD,iBAAiBriC,GACbA,EAAMS,iBACN,MAAMkC,EAAS3C,EAAMqC,cACrB,GAAI8hB,aAAMxhB,GACN,OAAO,EAGX,MAAMje,EAAaie,EAAOlxB,aAAa,wBACtB+L,KAAKqjD,YAAYoC,eAAev+C,GAE5C0Q,MAAM1a,IACH,MAAM,KAAC0lD,EAAD,OAAOllB,GAAUxgC,EACjBijC,EAAWwG,aAAMic,GAAQ,GAAKA,EAAKiB,kBACnC1oC,EAAU3nB,OAAO40C,QAAQiV,KAAK7L,UAAU,sCAAuC,gCAAiC,YAAa,OAAQ,CAAC,EAAGrR,IAC/I3sC,OAAO40C,QAAQyC,aAAajC,GAAGztB,GAI/B3nB,OAAO+c,SAAS8zC,SAAW,OAA3B,IAEH7oC,OAAM,SAAUvX,GACb,GAAIzQ,OAAO40C,QAAS,CAChB,MAAMjtB,EAAU3nB,OAAO40C,QAAQiV,KAAK7L,UAAU,oCAAqC,0CAA2C,aAC9Hh+C,OAAO40C,QAAQyC,aAAa5mC,MAAMkX,EACrC,CACJ,GACR,EC7EU,MAAMuqC,SACjBryD,YAAYwxC,EAAO8gB,EAAiBC,GAChC,MAAMC,EAAY,aAAMF,GAElB9gB,EAAMQ,cAAc,0BADpBsgB,EAEAG,EAAkB9lD,KAAK+lD,mBAAmBF,GAChD7lD,KAAKrL,KAAOkwC,EACZ7kC,KAAKkjB,QAAU2iC,EACf7lD,KAAK7J,QAAW,eAAQ2vD,GAElBjhB,EAAMQ,cAAc,0BADpB1xC,SAASiW,eAAek8C,GAE9B9lD,KAAKgmD,SAAU,aAAMJ,IAAoBprD,QAAQorD,GACjD5lD,KAAKgJ,UAAW,EAChBhJ,KAAK4lC,aACL5lC,KAAK+kC,qBACT,CAOAa,aACI,GAAI,aAAM5lC,KAAK7J,SACX,OAEJ,MAAM8vD,EAAejmD,KAAK7J,QAAQmH,UAAUpN,OACxC,eAAQ+1D,KACRjmD,KAAKkjB,QAAQrmB,aAAa,WAAY,QACtCmD,KAAKgJ,UAAW,EAExB,CAQA+8C,mBAAmBG,GACf,OAAQ,aAAMA,GAAqD,GAAzCA,EAASjyD,aAAa,gBACpD,CACA8wC,sBACS,aAAM/kC,KAAKkjB,UAAa,aAAMljB,KAAK7J,UAAa6J,KAAKgJ,UACtDhJ,KAAKkjB,QAAQ/W,iBAAiB,QAASnM,KAAKggB,OAAOjxB,KAAKiR,MAEhE,CAQAggB,OAAOilB,GACHA,EAAOhiB,iBACHjjB,KAAKgmD,QAELhmD,KAAKmmD,eAGLnmD,KAAKrL,KAAKwwC,UAAUnlB,OAAO,QAG/B,MAAMomC,EAAgBpmD,KAAKkjB,QAAQjvB,aAAa,kBAIjC,MAHC,eAAQmyD,IACc,SAAhCA,EAAc12D,eAGhBsQ,KAAKkgC,OAGLlgC,KAAKwpC,MAAMxpC,KAAKkjB,QAExB,CAMAgd,OACIlgC,KAAKkjB,QAAQrmB,aAAa,gBAAiB,QAC3CmD,KAAK7J,QAAQiF,gBAAgB,SACjC,CAQAouC,MAAMqc,GACF,MAAMQ,EAAmBrmD,KAAK+lD,mBAAmBF,GACjD,IAAIS,EAAW3yD,SAASiW,eAAey8C,GACnC,aAAMC,KACNA,EAAWtmD,KAAK7J,SAGpB0vD,EAAShpD,aAAa,gBAAiB,SACvCypD,EAASzpD,aAAa,SAAU,OACpC,CAOAspD,eAC6B94D,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,2BAC9Cjb,SAAS+2D,IAClBA,IAAalmD,KAAKkjB,SAClBljB,KAAKwpC,MAAM0c,EACf,GAER,ECjHW,MAAMK,cACjBlzD,YAAYwxC,GACR7kC,KAAKrL,KAAOkwC,EACZ7kC,KAAK4lC,YACT,CACAA,aACI,GAAI,aAAM5lC,KAAKrL,MACX,OAEqBtH,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,2BAC9Cjb,SAAS+2D,IACtB,IAAIR,SAAS1lD,KAAKrL,KAAMuxD,GAAU,EAAK,GAE/C,ECZW,MAAMM,KACjBnzD,YAAYwxC,GACR7kC,KAAKrL,KAAOkwC,EACZ7kC,KAAKc,KAAOd,KAAKrL,KAAKV,aAAa,aACnC+L,KAAKymD,iBAAmBzmD,KAAK0mD,sBAAqB,GAClD1mD,KAAK4hB,MAAQv0B,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,oBACnDpK,KAAK2mD,iBACL3mD,KAAK+kC,qBACT,CACA4hB,iBACI3mD,KAAK4hB,MAAMzyB,SAASy3D,IACgC,OAA5CA,EAAM5nD,WAAWtC,SAAShN,eAE1BsQ,KAAK6mD,yBAAyBD,EAAM5nD,YAExC,MAAM8nD,EAAcF,EAAMx8C,iBAAiB,mBAC3C,GAAIpK,KAAK+mD,SAASH,KACb,aAAME,IACPA,EAAYr5D,OAAS,EAAG,CACxB,MAAMu5D,EAAahnD,KAAKinD,mBACxBL,EAAM7qD,aAAairD,EAAYJ,EAAM5nD,WACzC,IAER,CACAkoD,oBAAoBC,GACX95D,MAAMC,QAAQ65D,IAGnBA,EAAMh4D,SAASi4D,IACX,MAAMzsD,EAAOqF,KAAKrL,KAAK0wC,cAAc,WAAW+hB,MAC3C,aAAMzsD,IACPA,EAAKwqC,UAAU5uB,IAAI,iBACvB,GAER,CACAwuB,sBACI/kC,KAAK4hB,MAAMzyB,SAASy3D,IAChBA,EAAMz6C,iBAAiB,QAASnM,KAAKqnD,YAAYt4D,KAAKiR,MAAM,GAEpE,CACAqnD,YAAY7kC,GACRA,EAAMS,iBACNT,EAAMO,kBACN,MACMpoB,EADS6nB,EAAM9e,OACD0S,QAAQ,mBACvB,aAAMzb,KACPqF,KAAKsnD,4BACL3sD,EAAKwqC,UAAUnlB,OAAO,qBAEtBhgB,KAAK+mD,SAASpsD,IACdqF,KAAKggB,OAAOrlB,EAEpB,CACA2sD,4BACItnD,KAAKrL,KAAKyV,iBAAiB,qBAAqBjb,SAASy3D,IACrDA,EAAMzhB,UAAUpqC,OAAO,mBAAmB,GAElD,CACAksD,mBACI,MAAMD,EAAarzD,SAASuC,cAAc,QAE1C,OADA8wD,EAAW7hB,UAAU5uB,IAAI,sBAClBywC,CACX,CACAH,yBAAyBz1D,GACrB,MAAMm2D,EAAY5zD,SAASuC,cAAc,QACzCqxD,EAAUpiB,UAAU5uB,IAAI,mBACxBnlB,EAAQwJ,WAAWmB,aAAawrD,EAAWn2D,GAC3Cm2D,EAAUxoD,YAAY3N,EAC1B,CACA21D,SAASpsD,GACL,OAAQ,aAAMA,IAASA,EAAKwqC,UAAUl/B,SAAS,mBACnD,CACA+Z,OAAOrlB,GACHA,EAAKwqC,UAAUnlB,OAAO,kBACtBhgB,KAAKwnD,sBAAsB7sD,EAAK1G,aAAa,SACjD,CACAwzD,iBAEI,OA/EW,wBA8EiB,eAAQznD,KAAKc,MAA0B,GAAlB,IAAMd,KAAKc,OAChDpR,aAChB,CACAg3D,qBAAqB9kD,GACjB,MAAM8lD,EAAe1nD,KAAKynD,iBACpBzf,EAAcpB,gBAAgB8gB,GAKpC,OAJK,aAAM9lD,KAAkB,IAATA,GAChB5B,KAAKknD,oBAAoBlf,GAE7BhoC,KAAKymD,iBAAmBp5D,MAAMC,QAAQ06C,GAAeA,EAAc,GAC5DhoC,KAAKymD,gBAChB,CACAkB,uBACI,MAAMD,EAAe1nD,KAAKynD,iBACtBp6D,MAAMC,QAAQ0S,KAAKymD,mBACnB3f,gBAAgB4gB,EAAc1nD,KAAKymD,iBAE3C,CACAe,sBAAsBxhB,IACd,eAAQA,IAAU34C,MAAMC,QAAQ0S,KAAKymD,oBAGrCzmD,KAAKymD,iBAAiB3e,SAAS9B,GAC/BhmC,KAAKymD,iBAAmBzmD,KAAKymD,iBAAiBh6C,QAAQ9L,GAASA,IAASqlC,IAGxEhmC,KAAKymD,iBAAiBl3D,KAAKy2C,GAE/BhmC,KAAK2nD,uBACT,EC5GW,MAAMC,MACjBv0D,YAAYwxC,GACR7kC,KAAKrL,KAAOkwC,EACZ7kC,KAAK6nD,SAAWx6D,MAAMK,KAAKiG,SAASyW,iBAAiB,WAAWy6B,EAAMh7B,8BACtE7J,KAAK8nD,aAAez6D,MAAMK,KAAKsS,KAAKrL,KAAKyV,iBAAiB,2BAC1DpK,KAAK8lC,OAASjB,EAAMQ,cAAc,gBAClCrlC,KAAK+kC,qBACT,CACAA,sBACI/kC,KAAK6nD,SAAS14D,SAAS02D,IACnBA,EAAS15C,iBAAiB,QAASnM,KAAKkgC,KAAKnxC,KAAKiR,MAAM,IAE5DA,KAAK8nD,aAAa34D,SAAS44D,IACvBA,EAAa57C,iBAAiB,QAASnM,KAAKwpC,MAAMz6C,KAAKiR,MAAM,IAEjErM,SAASwY,iBAAiB,QAASnM,KAAKgoD,WAAWj5D,KAAKiR,MAC5D,CACAkgC,KAAK+E,GACDA,EAAOhiB,iBACP,MAAMglC,EAAgBhjB,EAAOvhC,OACvBwf,EAAUljB,KAAKkoD,kBAAkBD,GACvCjoD,KAAKmoD,oBAAoBjlC,GACzBljB,KAAKrL,KAAKwwC,UAAU5uB,IAAI,QACxBvW,KAAKrL,KAAKwwC,UAAUpqC,OAAO,aAC3BmoB,EAAQ69B,cAAc,IAAIC,YAAY,uBAAwB,CAC1D36B,SAAS,EACTI,OAAQ,CAAEvf,WAAYlH,KAAKrL,KAAKkV,MAExC,CASAq+C,kBAAkBhC,GACd,OAAI,aAAMA,GACC,MAENA,EAASlyD,aAAa,iBACvBkyD,EAAWA,EAAS9vC,QAAQ,0BAEzB8vC,EACX,CACA1c,QACIxpC,KAAKrL,KAAKwwC,UAAUpqC,OAAO,QAC3BiF,KAAKrL,KAAKwwC,UAAU5uB,IAAI,aACxB/iB,OAAOutD,cAAc,IAAIC,YAAY,uBAAwB,CACzDv6B,OAAQ,CAAEvf,WAAYlH,KAAKrL,KAAKkV,MAExC,CACAm+C,WAAW/iB,GACY,WAAfA,EAAOz6B,KACPxK,KAAKwpC,OAEb,CACA2e,oBAAoBtC,GAChB,GAAI,aAAMA,IAAa,aAAM7lD,KAAK8lC,QAC9B,OAEJ,MAAMsiB,EAAgBvC,EAAS5xD,aAAa,qBACvC,eAAQm0D,KACTpoD,KAAK8lC,OAAOuiB,UAAYD,EAEhC,ECtDJ50D,OAAOgO,OAASA,IAChBhO,OAAOywC,EAAIziC,IAGXyhD,gBACA5a,qBACAwC,EAAajpC,OACb0mD,EAAa1mD,OCHO+5B,WAClB,MAAM4sB,EAAaC,uBAAuBC,GACpCC,EAAgB/hB,aAAM4hB,GAC5B,GAAI5hB,aAAM8hB,IAAgBC,EACxB,OAAO,EAGT,GAAIA,EAAe,CACjB,MAAMC,OAtBQhtB,WAChB,MAAM8C,QAAiBokB,MAAM+F,GAC7B,GAAKnqB,EAASmK,GAIZ,aAAanK,EAAS3C,OAFtB,MAAM,IAAI/7B,MAAO,uBAAsB0+B,EAASf,SAGjD,EAe4BmrB,CAAUJ,GAErC,OADAD,uBAAuBC,EAAaE,GAC7BA,CACR,CACC,OAAOJ,CACR,EDRHO,CAAYzgB,kBAAkB,aAAazwB,MAAMspC,IAC3CA,GACFoH,EAAavG,iBAAiBb,EAC/B,IAGHvtD,SAASwY,iBAAiB,oBAAqBqW,IAEhB7uB,SAASyW,iBAAiB,mBAClCjb,SAAS45D,IAC5B,IAAInkB,aAAamkB,EAAjB,IAGwBp1D,SAASyW,iBAAiB,cAClCjb,SAAS65D,IACzB,IAAI5hB,UAAU4hB,EAAd,IAGmBr1D,SAASyW,iBAAiB,wBAClCjb,SAAS85D,IACpB,IAAIzC,KAAKyC,EAAT,IAGmB57D,MAAMK,KACzBiG,SAASyW,iBAAiB,0BAEfjb,SAAS+5D,IACpB,MAAMC,EAAex1D,SAAS0xC,cAC5B6jB,EAAcj1D,aAAa,SAExB0yC,aAAMwiB,IACT,IAAIvB,MAAMuB,EACX,IAGwBx1D,SAASyW,iBAClC,mCAEiBjb,SAASi6D,IAC1B,IAAI1D,SAAS0D,EAAb,IAG8Bz1D,SAASyW,iBACvC,yCAEsBjb,SAASi6D,IAC/B,IAAI7C,cAAc6C,EAAlB,IAGF,MAAMC,EAAsB11D,SAAS0xC,cAAc,qCAC9CsB,aAAM0iB,IACTh8D,MAAMK,KAAK27D,EAAoBj/C,iBAAiB,gBAAgBjb,SAC3Dm6D,IACM3iB,aAAM2iB,IACT,IAAI9E,eAAe8E,EACpB,IAKT,MAAMC,EAAoB51D,SAAS0xC,cAAc,iCAC5CsB,aAAM4iB,IACT,IAAIpG,SAASoG,EACd","sources":["webpack://@neos-project/neos/./node_modules/dompurify/dist/purify.js","webpack://@neos-project/neos/./node_modules/jquery/dist/jquery.js","webpack://@neos-project/neos/webpack/bootstrap","webpack://@neos-project/neos/webpack/runtime/compat get default export","webpack://@neos-project/neos/webpack/runtime/define property getters","webpack://@neos-project/neos/webpack/runtime/hasOwnProperty shorthand","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/TopBar/DropdownMenu.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/TopBar/Expandable.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Helper/isNil.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Helper/getCollectionValueByPath.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Helper/createCollectionByPath.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/LocalStorage.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/TopBar/MenuPanel.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/Configuration.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Helper/isEmpty.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/Notification/MessageTemplate.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/Notification/Message.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/Notification/Toast.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/Notification.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/typeof.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/defineProperty.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/objectSpread.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/classCallCheck.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/createClass.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js","webpack://@neos-project/neos/./node_modules/@babel/runtime/helpers/esm/inherits.js","webpack://@neos-project/neos/./node_modules/i18next/dist/esm/i18next.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/Localization.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/SessionStorage.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/ApiService.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Helper/getItemByKeyValue.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/Helper.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/TopBar/UserMenu.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Templates/RestoreButton.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Templates/ImpersonateButton.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Module/Administration/UserManagement.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/DropDown.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/DropDownGroup.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/Tree.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/Components/Modal.ts","webpack://@neos-project/neos/./Resources/Public/JavaScript/index.js","webpack://@neos-project/neos/./Resources/Public/JavaScript/Services/ResourceCache.js"],"sourcesContent":["/*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.2.2/LICENSE */\n\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = global || self, global.DOMPurify = factory());\n}(this, function () { 'use strict';\n\n function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\n var hasOwnProperty = Object.hasOwnProperty,\n setPrototypeOf = Object.setPrototypeOf,\n isFrozen = Object.isFrozen,\n getPrototypeOf = Object.getPrototypeOf,\n getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;\n var freeze = Object.freeze,\n seal = Object.seal,\n create = Object.create; // eslint-disable-line import/no-mutable-exports\n\n var _ref = typeof Reflect !== 'undefined' && Reflect,\n apply = _ref.apply,\n construct = _ref.construct;\n\n if (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n }\n\n if (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n }\n\n if (!seal) {\n seal = function seal(x) {\n return x;\n };\n }\n\n if (!construct) {\n construct = function construct(Func, args) {\n return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray(args))))();\n };\n }\n\n var arrayForEach = unapply(Array.prototype.forEach);\n var arrayPop = unapply(Array.prototype.pop);\n var arrayPush = unapply(Array.prototype.push);\n\n var stringToLowerCase = unapply(String.prototype.toLowerCase);\n var stringMatch = unapply(String.prototype.match);\n var stringReplace = unapply(String.prototype.replace);\n var stringIndexOf = unapply(String.prototype.indexOf);\n var stringTrim = unapply(String.prototype.trim);\n\n var regExpTest = unapply(RegExp.prototype.test);\n\n var typeErrorCreate = unconstruct(TypeError);\n\n function unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n return apply(func, thisArg, args);\n };\n }\n\n function unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n\n return construct(func, args);\n };\n }\n\n /* Add properties to a lookup table */\n function addToSet(set, array) {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n var l = array.length;\n while (l--) {\n var element = array[l];\n if (typeof element === 'string') {\n var lcElement = stringToLowerCase(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n }\n\n /* Shallow clone an object */\n function clone(object) {\n var newObject = create(null);\n\n var property = void 0;\n for (property in object) {\n if (apply(hasOwnProperty, object, [property])) {\n newObject[property] = object[property];\n }\n }\n\n return newObject;\n }\n\n /* IE10 doesn't support __lookupGetter__ so lets'\n * simulate it. It also automatically checks\n * if the prop is function or getter and behaves\n * accordingly. */\n function lookupGetter(object, prop) {\n while (object !== null) {\n var desc = getOwnPropertyDescriptor(object, prop);\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n return null;\n }\n\n var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);\n\n // SVG\n var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);\n\n var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);\n\n // List of SVG elements that are disallowed by default.\n // We still need to know them so that we can do namespace\n // checks properly in case one wants to add them to\n // allow-list.\n var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'feimage', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);\n\n var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);\n\n // Similarly to SVG, we want to know all MathML elements,\n // even those that we disallow by default.\n var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\n\n var text = freeze(['#text']);\n\n var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);\n\n var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);\n\n var mathMl$1 = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);\n\n var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n // eslint-disable-next-line unicorn/better-regex\n var MUSTACHE_EXPR = seal(/\\{\\{[\\s\\S]*|[\\s\\S]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n var ERB_EXPR = seal(/<%[\\s\\S]*|[\\s\\S]*%>/gm);\n var DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n var ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n );\n var IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\n var ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n );\n\n var _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\n function _toConsumableArray$1(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\n var getGlobal = function getGlobal() {\n return typeof window === 'undefined' ? null : window;\n };\n\n /**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {Document} document The document object (to determine policy name suffix)\n * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported).\n */\n var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {\n if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n var suffix = null;\n var ATTR_NAME = 'data-tt-policy-suffix';\n if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {\n suffix = document.currentScript.getAttribute(ATTR_NAME);\n }\n\n var policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML: function createHTML(html$$1) {\n return html$$1;\n }\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n };\n\n function createDOMPurify() {\n var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n\n var DOMPurify = function DOMPurify(root) {\n return createDOMPurify(root);\n };\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = '2.2.6';\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n\n if (!window || !window.document || window.document.nodeType !== 9) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n var originalDocument = window.document;\n\n var document = window.document;\n var DocumentFragment = window.DocumentFragment,\n HTMLTemplateElement = window.HTMLTemplateElement,\n Node = window.Node,\n Element = window.Element,\n NodeFilter = window.NodeFilter,\n _window$NamedNodeMap = window.NamedNodeMap,\n NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,\n Text = window.Text,\n Comment = window.Comment,\n DOMParser = window.DOMParser,\n trustedTypes = window.trustedTypes;\n\n\n var ElementPrototype = Element.prototype;\n\n var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n var getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n var template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);\n var emptyHTML = trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML('') : '';\n\n var _document = document,\n implementation = _document.implementation,\n createNodeIterator = _document.createNodeIterator,\n getElementsByTagName = _document.getElementsByTagName,\n createDocumentFragment = _document.createDocumentFragment;\n var importNode = originalDocument.importNode;\n\n\n var documentMode = {};\n try {\n documentMode = clone(document).documentMode ? document.documentMode : {};\n } catch (_) {}\n\n var hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;\n\n var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,\n ERB_EXPR$$1 = ERB_EXPR,\n DATA_ATTR$$1 = DATA_ATTR,\n ARIA_ATTR$$1 = ARIA_ATTR,\n IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE$$1 = ATTR_WHITESPACE;\n var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n\n var ALLOWED_TAGS = null;\n var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(html), _toConsumableArray$1(svg), _toConsumableArray$1(svgFilters), _toConsumableArray$1(mathMl), _toConsumableArray$1(text)));\n\n /* Allowed attribute names */\n var ALLOWED_ATTR = null;\n var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n var FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n var FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n var ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n var ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n var ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n var SAFE_FOR_TEMPLATES = false;\n\n /* Decide if document with ... should be returned */\n var WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n var SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n var FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n var RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n var RETURN_DOM_FRAGMENT = false;\n\n /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM\n * `Node` is imported into the current `Document`. If this flag is not enabled the\n * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by\n * DOMPurify.\n *\n * This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false`\n * might cause XSS from attacks hidden in closed shadowroots in case the browser\n * supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/\n */\n var RETURN_DOM_IMPORT = true;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n var RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks? */\n var SANITIZE_DOM = true;\n\n /* Keep element content when removing element? */\n var KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n var IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n var USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);\n\n /* Tags that are safe for data: URIs */\n var DATA_URI_TAGS = null;\n var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\n /* Attributes safe for values like \"javascript:\" */\n var URI_SAFE_ATTRIBUTES = null;\n var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);\n\n /* Keep a reference to config to pass to hooks */\n var CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n var formElement = document.createElement('form');\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n var _parseConfig = function _parseConfig(cfg) {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n\n /* Set configuration parameters */\n ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;\n URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;\n FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};\n FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};\n USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT !== false; // Default true\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(text)));\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html);\n addToSet(ALLOWED_ATTR, html$1);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg);\n addToSet(ALLOWED_ATTR, svg$1);\n addToSet(ALLOWED_ATTR, xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg$1);\n addToSet(ALLOWED_ATTR, xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl);\n addToSet(ALLOWED_ATTR, mathMl$1);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n\n var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n var ALL_SVG_TAGS = addToSet({}, svg);\n addToSet(ALL_SVG_TAGS, svgFilters);\n addToSet(ALL_SVG_TAGS, svgDisallowed);\n\n var ALL_MATHML_TAGS = addToSet({}, mathMl);\n addToSet(ALL_MATHML_TAGS, mathMlDisallowed);\n\n var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n\n /**\n *\n *\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n var _checkValidNamespace = function _checkValidNamespace(element) {\n var parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: HTML_NAMESPACE,\n tagName: 'template'\n };\n }\n\n var tagName = stringToLowerCase(element.tagName);\n var parentTagName = stringToLowerCase(parent.tagName);\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via\n // svg if parent is either or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erronously deleted from\n // HTML namespace.\n var commonSvgAndHTMLElements = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return !ALL_MATHML_TAGS[tagName] && (commonSvgAndHTMLElements[tagName] || !ALL_SVG_TAGS[tagName]);\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG or MathML). Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n var _forceRemove = function _forceRemove(node) {\n arrayPush(DOMPurify.removed, { element: node });\n try {\n node.parentNode.removeChild(node);\n } catch (_) {\n try {\n node.outerHTML = emptyHTML;\n } catch (_) {\n node.remove();\n }\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n var _removeAttribute = function _removeAttribute(name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node\n });\n }\n\n node.removeAttribute(name);\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n var _initDocument = function _initDocument(dirty) {\n /* Create a HTML document */\n var doc = void 0;\n var leadingWhitespace = void 0;\n\n if (FORCE_BODY) {\n dirty = '' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n var matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n\n var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n /* Use the DOMParser API by default, fallback later if needs be */\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');\n } catch (_) {}\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createHTMLDocument('');\n var _doc = doc,\n body = _doc.body;\n\n body.parentNode.removeChild(body.parentNode.firstElementChild);\n body.outerHTML = dirtyPayload;\n }\n\n if (dirty && leadingWhitespace) {\n doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);\n }\n\n /* Work on whole document or just its body */\n return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n };\n\n /**\n * _createIterator\n *\n * @param {Document} root document/fragment to create iterator for\n * @return {Iterator} iterator instance\n */\n var _createIterator = function _createIterator(root) {\n return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {\n return NodeFilter.FILTER_ACCEPT;\n }, false);\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n var _isClobbered = function _isClobbered(elm) {\n if (elm instanceof Text || elm instanceof Comment) {\n return false;\n }\n\n if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function') {\n return true;\n }\n\n return false;\n };\n\n /**\n * _isNode\n *\n * @param {Node} obj object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n var _isNode = function _isNode(object) {\n return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === 'object' ? object instanceof Node : object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n var _executeHook = function _executeHook(entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n\n arrayForEach(hooks[entryPoint], function (hook) {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n var _sanitizeElements = function _sanitizeElements(currentNode) {\n var content = void 0;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check if tagname contains Unicode */\n if (stringMatch(currentNode.nodeName, /[\\u0080-\\uFFFF]/)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n var tagName = stringToLowerCase(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName: tagName,\n allowedTags: ALLOWED_TAGS\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (!_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n var parentNode = getParentNode(currentNode);\n var childNodes = getChildNodes(currentNode);\n var childCount = childNodes.length;\n for (var i = childCount - 1; i >= 0; --i) {\n parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));\n }\n }\n\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\\/no(script|embed)/i, currentNode.innerHTML)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {\n /* Get the element's text content */\n content = currentNode.textContent;\n content = stringReplace(content, MUSTACHE_EXPR$$1, ' ');\n content = stringReplace(content, ERB_EXPR$$1, ' ');\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n return false;\n\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if (!value) ; else {\n return false;\n }\n\n return true;\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n var attr = void 0;\n var value = void 0;\n var lcName = void 0;\n var l = void 0;\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n\n var attributes = currentNode.attributes;\n\n /* Check if we have attributes; if not we might have a text node */\n\n if (!attributes) {\n return;\n }\n\n var hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR\n };\n l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n attr = attributes[l];\n var _attr = attr,\n name = _attr.name,\n namespaceURI = _attr.namespaceURI;\n\n value = stringTrim(attr.value);\n lcName = stringToLowerCase(name);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n value = stringReplace(value, MUSTACHE_EXPR$$1, ' ');\n value = stringReplace(value, ERB_EXPR$$1, ' ');\n }\n\n /* Is `value` valid for this attribute? */\n var lcTag = currentNode.nodeName.toLowerCase();\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n\n arrayPop(DOMPurify.removed);\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n var shadowNode = void 0;\n var shadowIterator = _createIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n\n while (shadowNode = shadowIterator.nextNode()) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} configuration object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty, cfg) {\n var body = void 0;\n var importedNode = void 0;\n var currentNode = void 0;\n var oldNode = void 0;\n var returnNode = void 0;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n if (!dirty) {\n dirty = '';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n // eslint-disable-next-line no-negated-condition\n if (typeof dirty.toString !== 'function') {\n throw typeErrorCreate('toString is not a function');\n } else {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n }\n }\n\n /* Check we can run. Otherwise fall back or ignore */\n if (!DOMPurify.isSupported) {\n if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {\n if (typeof dirty === 'string') {\n return window.toStaticHTML(dirty);\n }\n\n if (_isNode(dirty)) {\n return window.toStaticHTML(dirty.outerHTML);\n }\n }\n\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n\n if (IN_PLACE) ; else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : emptyHTML;\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n var nodeIterator = _createIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while (currentNode = nodeIterator.nextNode()) {\n /* Fix IE's strange behavior with manipulated textNodes #89 */\n if (currentNode.nodeType === 3 && currentNode === oldNode) {\n continue;\n }\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n\n oldNode = currentNode;\n }\n\n oldNode = null;\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n\n if (RETURN_DOM_IMPORT) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n\n return returnNode;\n }\n\n var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$$1, ' ');\n serializedHTML = stringReplace(serializedHTML, ERB_EXPR$$1, ' ');\n }\n\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function (cfg) {\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {string} tag Tag name of containing element.\n * @param {string} attr Attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n\n var lcTag = stringToLowerCase(tag);\n var lcName = stringToLowerCase(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n *\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n\n return DOMPurify;\n }\n\n var purify = createDOMPurify();\n\n return purify;\n\n}));\n//# sourceMappingURL=purify.js.map\n","/*!\n * jQuery JavaScript Library v3.6.0\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2021-03-02T17:08Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n\t\t// Support: Chrome <=57, Firefox <=52\n\t\t// In some browsers, typeof returns \"function\" for HTML elements\n\t\t// (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n\t\t// We don't want to classify *any* DOM node as a function.\n\t\t// Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5\n\t\t// Plus for old WebKit, typeof returns \"function\" for HTML collections\n\t\t// (e.g., `typeof document.getElementsByTagName(\"div\") === \"function\"`). (gh-4756)\n\t\treturn typeof obj === \"function\" && typeof obj.nodeType !== \"number\" &&\n\t\t\ttypeof obj.item !== \"function\";\n\t};\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\nvar document = window.document;\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnonce: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, node, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar i, val,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\n\t\t\t\t// Support: Firefox 64+, Edge 18+\n\t\t\t\t// Some browsers don't support the \"nonce\" property on scripts.\n\t\t\t\t// On the other hand, just using `getAttribute` is not enough as\n\t\t\t\t// the `nonce` attribute is reset to an empty string whenever it\n\t\t\t\t// becomes browsing-context connected.\n\t\t\t\t// See https://github.com/whatwg/html/issues/2369\n\t\t\t\t// See https://html.spec.whatwg.org/#nonce-attributes\n\t\t\t\t// The `node.getAttribute` check was added for the sake of\n\t\t\t\t// `jQuery.globalEval` so that it can fake a nonce-containing node\n\t\t\t\t// via an object.\n\t\t\t\tval = node[ i ] || node.getAttribute && node.getAttribute( i );\n\t\t\t\tif ( val ) {\n\t\t\t\t\tscript.setAttribute( i, val );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.6.0\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.6\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://js.foundation/\n *\n * Date: 2021-02-16\n */\n( function( window ) {\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ( {} ).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpushNative = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[ i ] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|\" +\n\t\t\"ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\n\tidentifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t\t// \"Attribute values must be CSS identifiers [capture 5]\n\t\t// or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\t\twhitespace + \"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" +\n\t\twhitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace +\n\t\t\"*\" ),\n\trdescend = new RegExp( whitespace + \"|>\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trhtml = /HTML$/i,\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace + \"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\treturn nonHex ?\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\tnonHex :\n\n\t\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t\t// Support: IE <=11+\n\t\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t\t// surrogate pair\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" +\n\t\t\t\tch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && elem.nodeName.toLowerCase() === \"fieldset\";\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t( arr = slice.call( preferredDoc.childNodes ) ),\n\t\tpreferredDoc.childNodes\n\t);\n\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\t// eslint-disable-next-line no-unused-expressions\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpushNative.apply( target, slice.call( els ) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( ( target[ j++ ] = els[ i++ ] ) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&\n\n\t\t\t\t// Support: IE 8 only\n\t\t\t\t// Exclude object elements\n\t\t\t\t( nodeType !== 1 || context.nodeName.toLowerCase() !== \"object\" ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// We can use :scope instead of the ID hack if the browser\n\t\t\t\t\t// supports it & if we're not changing the context.\n\t\t\t\t\tif ( newContext !== context || !support.scope ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement( \"fieldset\" );\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch ( e ) {\n\t\treturn false;\n\t} finally {\n\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split( \"|\" ),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[ i ] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( ( cur = cur.nextSibling ) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn ( name === \"input\" || name === \"button\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\tvar namespace = elem && elem.namespaceURI,\n\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t// Support: IE <=8\n\t// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes\n\t// https://bugs.jquery.com/ticket/4833\n\treturn !rhtml.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( preferredDoc != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t// Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,\n\t// Safari 4 - 5 only, Opera <=11.6 - 12.x only\n\t// IE/Edge & older browsers don't support the :scope pseudo-class.\n\t// Support: Safari 6.0 only\n\t// Safari 6.0 supports :scope but it's an alias of :root there.\n\tsupport.scope = assert( function( el ) {\n\t\tdocElem.appendChild( el ).appendChild( document.createElement( \"div\" ) );\n\t\treturn typeof el.querySelectorAll !== \"undefined\" &&\n\t\t\t!el.querySelectorAll( \":scope fieldset div\" ).length;\n\t} );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert( function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute( \"className\" );\n\t} );\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert( function( el ) {\n\t\tel.appendChild( document.createComment( \"\" ) );\n\t\treturn !el.getElementsByTagName( \"*\" ).length;\n\t} );\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert( function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t} );\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[ \"ID\" ] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode( \"id\" );\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[ \"ID\" ] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( ( elem = elems[ i++ ] ) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode( \"id\" );\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[ \"TAG\" ] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[ \"CLASS\" ] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {\n\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert( function( el ) {\n\n\t\t\tvar input;\n\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"\" +\n\t\t\t\t\"\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll( \"[msallowcapture^='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll( \"[selected]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"~=\" );\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 15 - 18+\n\t\t\t// IE 11/Edge don't find elements on a `[name='']` query in some cases.\n\t\t\t// Adding a temporary attribute to the document before the selection works\n\t\t\t// around the issue.\n\t\t\t// Interestingly, IE 10 & older don't seem to have the issue.\n\t\t\tinput = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"name\", \"\" );\n\t\t\tel.appendChild( input );\n\t\t\tif ( !el.querySelectorAll( \"[name='']\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\t\t\t\t\twhitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll( \":checked\" ).length ) {\n\t\t\t\trbuggyQSA.push( \":checked\" );\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push( \".#.+[+~]\" );\n\t\t\t}\n\n\t\t\t// Support: Firefox <=3.6 - 5 only\n\t\t\t// Old Firefox doesn't throw on a badly-escaped identifier.\n\t\t\tel.querySelectorAll( \"\\\\\\f\" );\n\t\t\trbuggyQSA.push( \"[\\\\r\\\\n\\\\f]\" );\n\t\t} );\n\n\t\tassert( function( el ) {\n\t\t\tel.innerHTML = \"\" +\n\t\t\t\t\"\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement( \"input\" );\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll( \"[name=d]\" ).length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll( \":enabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll( \":disabled\" ).length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: Opera 10 - 11 only\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll( \"*,:x\" );\n\t\t\trbuggyQSA.push( \",.*:\" );\n\t\t} );\n\t}\n\n\tif ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector ) ) ) ) {\n\n\t\tassert( function( el ) {\n\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t} );\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( \"|\" ) );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( \"|\" ) );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t) );\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( ( b = b.parentNode ) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( a == document || a.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, a ) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tif ( b == document || b.ownerDocument == preferredDoc &&\n\t\t\t\tcontains( preferredDoc, b ) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\treturn a == document ? -1 :\n\t\t\t\tb == document ? 1 :\n\t\t\t\t/* eslint-enable eqeqeq */\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( ( cur = cur.parentNode ) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[ i ] === bp[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[ i ], bp[ i ] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t/* eslint-disable eqeqeq */\n\t\t\tap[ i ] == preferredDoc ? -1 :\n\t\t\tbp[ i ] == preferredDoc ? 1 :\n\t\t\t/* eslint-enable eqeqeq */\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\n\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t// fragment in IE 9\n\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( context.ownerDocument || context ) != document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\n\t// Set document vars if needed\n\t// Support: IE 11+, Edge 17 - 18+\n\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( ( elem.ownerDocument || elem ) != document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[ 1 ] = match[ 1 ].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[ 3 ] = ( match[ 3 ] || match[ 4 ] ||\n\t\t\t\tmatch[ 5 ] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" ) );\n\t\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[ 3 ] ) {\n\t\t\t\tSizzle.error( match[ 0 ] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\t\tif ( matchExpr[ \"CHILD\" ].test( match[ 0 ] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[ 3 ] ) {\n\t\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length ) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace +\n\t\t\t\t\t\")\" + className + \"(\" + whitespace + \"|$)\" ) ) && classCache(\n\t\t\t\t\t\tclassName, function( elem ) {\n\t\t\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\t/* eslint-disable max-len */\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t\t/* eslint-enable max-len */\n\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || ( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ expando ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( outerCache[ node.uniqueID ] = {} );\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction( function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[ i ] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} ) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\t\"has\": markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\t\"contains\": markFunction( function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\t( !document.hasFocus || document.hasFocus() ) &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn ( nodeName === \"input\" && !!elem.checked ) ||\n\t\t\t\t( nodeName === \"option\" && !!elem.selected );\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t// but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[ \"empty\" ]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( ( attr = elem.getAttribute( \"type\" ) ) == null ||\n\t\t\t\t\tattr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\t\"last\": createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\t\"eq\": createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\t\"even\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"odd\": createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"lt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ?\n\t\t\t\targument + length :\n\t\t\t\targument > length ?\n\t\t\t\t\tlength :\n\t\t\t\t\targument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\t\"gt\": createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\nExpr.pseudos[ \"nth\" ] = Expr.pseudos[ \"eq\" ];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rcombinators.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || ( elem[ expando ] = {} );\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] ||\n\t\t\t\t\t\t\t( outerCache[ elem.uniqueID ] = {} );\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = uniqueCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts(\n\t\t\t\tselector || \"*\",\n\t\t\t\tcontext.nodeType ? [ context ] : context,\n\t\t\t\t[]\n\t\t\t),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\ttokens\n\t\t\t\t\t\t.slice( 0, i - 1 )\n\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[ \"TAG\" ]( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: ) matching elements by id\n\t\t\tfor ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+, Edge 17 - 18+\n\t\t\t\t\t// IE/Edge sometimes throw a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache(\n\t\t\tselector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers )\n\t\t);\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n * selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n * selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( Expr.find[ \"ID\" ]( token.matches[ 0 ]\n\t\t\t\t.replace( runescape, funescape ), context ) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[ \"needsContext\" ].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = Expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\ttoken.matches[ 0 ].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split( \"\" ).sort( sortOrder ).join( \"\" ) === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert( function( el ) {\n\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement( \"fieldset\" ) ) & 1;\n} );\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert( function( el ) {\n\tel.innerHTML = \"\";\n\treturn el.firstChild.getAttribute( \"href\" ) === \"#\";\n} ) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert( function( el ) {\n\tel.innerHTML = \"\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n} ) ) {\n\taddHandle( \"value\", function( elem, _name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t} );\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert( function( el ) {\n\treturn el.getAttribute( \"disabled\" ) == null;\n} ) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t( val = elem.getAttributeNode( name ) ) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\t\tnull;\n\t\t}\n\t} );\n}\n\nreturn Sizzle;\n\n} )( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n}\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the primary Deferred\n\t\t\tprimary = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tprimary.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( primary.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn primary.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );\n\t\t}\n\n\t\treturn primary.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t// - Node\n\t// - Node.ELEMENT_NODE\n\t// - Node.DOCUMENT_NODE\n\t// - Object\n\t// - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t// 1. No key was specified\n\t\t// 2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t// 1. The entire cache object\n\t\t// 2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t// 1. An object of properties\n\t\t// 2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar documentElement = document.documentElement;\n\n\n\n\tvar isAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t\t},\n\t\tcomposed = { composed: true };\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only\n\t// Check attachment across shadow DOM boundaries when possible (gh-3504)\n\t// Support: iOS 10.0-10.2 only\n\t// Early iOS 10 versions support `attachShadow` but not `getRootNode`,\n\t// leading to errors. We need to check for `getRootNode`.\n\tif ( documentElement.getRootNode ) {\n\t\tisAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t\t};\n\t}\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tisAttached( elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// Support: IE <=9 only\n\t// IE <=9 replaces \", \"
\" ],\n\tcol: [ 2, \"\", \"
\" ],\n\ttr: [ 2, \"\", \"
\" ],\n\ttd: [ 3, \"\", \"
\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: IE <=9 only\nif ( !support.option ) {\n\twrapMap.optgroup = wrapMap.option = [ 1, \"\" ];\n}\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\nvar rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Support: Chrome 86+\n\t\t\t\t\t\t// In Chrome, if an element having a focusout handler is blurred by\n\t\t\t\t\t\t// clicking outside of it, it invokes the handler synchronously. If\n\t\t\t\t\t\t// that handler calls `.remove()` on the element, the data is cleared,\n\t\t\t\t\t\t// leaving `result` undefined. We need to guard against this.\n\t\t\t\t\t\treturn result && result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\twhich: true\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\t// Suppress native focus or blur as it's already being fired\n\t\t// in leverageNative.\n\t\t_default: function() {\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event ) dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.get( src );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdataPriv.remove( dest, \"handle events\" );\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase() !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html;\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableTrDimensionsVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t},\n\n\t\t// Support: IE 9 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Behavior in IE 9 is more subtle than in newer versions & it passes\n\t\t// some versions of this test; make sure not to make it pass there!\n\t\t//\n\t\t// Support: Firefox 70+\n\t\t// Only Firefox includes border widths\n\t\t// in computed dimensions. (gh-4529)\n\t\treliableTrDimensions: function() {\n\t\t\tvar table, tr, trChild, trStyle;\n\t\t\tif ( reliableTrDimensionsVal == null ) {\n\t\t\t\ttable = document.createElement( \"table\" );\n\t\t\t\ttr = document.createElement( \"tr\" );\n\t\t\t\ttrChild = document.createElement( \"div\" );\n\n\t\t\t\ttable.style.cssText = \"position:absolute;left:-11111px;border-collapse:separate\";\n\t\t\t\ttr.style.cssText = \"border:1px solid\";\n\n\t\t\t\t// Support: Chrome 86+\n\t\t\t\t// Height set through cssText does not get applied.\n\t\t\t\t// Computed height then comes back as 0.\n\t\t\t\ttr.style.height = \"1px\";\n\t\t\t\ttrChild.style.height = \"9px\";\n\n\t\t\t\t// Support: Android 8 Chrome 86+\n\t\t\t\t// In our bodyBackground.html iframe,\n\t\t\t\t// display for all div elements is set to \"inline\",\n\t\t\t\t// which causes a problem only in Android 8 Chrome 86.\n\t\t\t\t// Ensuring the div is display: block\n\t\t\t\t// gets around this issue.\n\t\t\t\ttrChild.style.display = \"block\";\n\n\t\t\t\tdocumentElement\n\t\t\t\t\t.appendChild( table )\n\t\t\t\t\t.appendChild( tr )\n\t\t\t\t\t.appendChild( trChild );\n\n\t\t\t\ttrStyle = window.getComputedStyle( tr );\n\t\t\t\treliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderTopWidth, 10 ) +\n\t\t\t\t\tparseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;\n\n\t\t\t\tdocumentElement.removeChild( table );\n\t\t\t}\n\t\t\treturn reliableTrDimensionsVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t// .css('filter') (IE 9 only, #12537)\n\t// .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Support: IE 9 - 11 only\n\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t// In those cases, the computed value can be trusted to be border-box.\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\n\t\t// Support: IE 10 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Interestingly, in some cases IE 9 doesn't suffer from this issue.\n\t\t!support.reliableTrDimensions() && nodeName( elem, \"tr\" ) ||\n\n\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\tval === \"auto\" ||\n\n\t\t// Support: Android <=4.1 - 4.3 only\n\t\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t} ) :\n\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\n\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( _i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || Object.create( null ) )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\n\t\t\t\t// Handle: regular nodes (via `this.ownerDocument`), window\n\t\t\t\t// (via `this.document`) & document (via `this`).\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, parserErrorElem;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {}\n\n\tparserErrorElem = xml && xml.getElementsByTagName( \"parsererror\" )[ 0 ];\n\tif ( !xml || parserErrorElem ) {\n\t\tjQuery.error( \"Invalid XML: \" + (\n\t\t\tparserErrorElem ?\n\t\t\t\tjQuery.map( parserErrorElem.childNodes, function( el ) {\n\t\t\t\t\treturn el.textContent;\n\t\t\t\t} ).join( \"\\n\" ) :\n\t\t\t\tdata\n\t\t) );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} ).filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} ).map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t * - BEFORE asking for a transport\n\t * - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\noriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce.guid++ ) +\n\t\t\t\t\tuncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script but not if jsonp\n\t\t\tif ( !isSuccess &&\n\t\t\t\tjQuery.inArray( \"script\", s.dataTypes ) > -1 &&\n\t\t\t\tjQuery.inArray( \"json\", s.dataTypes ) < 0 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\" ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain or forced-by-attrs requests\n\tif ( s.crossDomain || s.scriptAttrs ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"