Compare commits

...

22 Commits

Author SHA1 Message Date
Grégoire Paris
e750360bd5 Merge pull request #10101 from greg0ire/followup-9488
Assert that serialization leaves PersistentCollection usable
2022-10-07 08:37:17 +02:00
Grégoire Paris
e8ac1169ad Bump CI workflows (#10106) 2022-10-06 16:57:00 +02:00
Grégoire Paris
dd8c7003b8 Assert that serialization leaves PersistentCollection usable
That feature is no longer covered since support for merging entities in
the entity manager was removed.
2022-10-06 10:40:06 +02:00
Grégoire Paris
9bec416bb0 Merge pull request #10100 from greg0ire/forward-compat-attributes
Forward compat attributes
2022-10-05 22:44:49 +02:00
Grégoire Paris
021722acc7 Remove ignored annotation
Making it a separate, valid annotation breaks the tests
2022-10-05 22:15:04 +02:00
Grégoire Paris
5a528bef5d Use short class name
It is more friendly with conversion to attributes
2022-10-05 22:00:44 +02:00
Grégoire Paris
5fbcb18334 Spell cities properly 2022-10-05 21:55:24 +02:00
Grégoire Paris
8280f41fa5 Merge pull request #10099 from greg0ire/fix-attribute-docs
Fix attribute reference
2022-10-05 21:48:46 +02:00
Grégoire Paris
d95d8d0a19 Fix broken links 2022-10-05 21:40:09 +02:00
Grégoire Paris
d36004f825 Remove trailing whitespace 2022-10-05 21:39:31 +02:00
Grégoire Paris
18366db578 Remove reference to JoinColumns
While that class can be an annotation, it cannot be an attribute because
it is not necessary when using attributes.

See https://github.com/doctrine/orm/issues/9986
2022-10-05 21:38:38 +02:00
Grégoire Paris
1b5bef3d4d Merge pull request #10094 from doctrine/fix_doc_toc 2022-10-04 15:55:16 +02:00
Christophe Coevoet
880b622fe6 Fix heading levels for the embeddable tutorial 2022-10-04 14:13:44 +02:00
Grégoire Paris
cbf141f7ed Add missing variable name in param phpdoc and switch to psalm-assert (#10092)
* Add missing variable name in param phpdoc

* Use psalm-assert instead of psalm-param

The parameter can in fact be any string, but if an exception is not
thrown, then it was a valid value.
2022-10-03 21:17:21 +02:00
Grégoire Paris
536bb4f678 Merge pull request #10090 from greg0ire/update-psalm-baseline
Update Psalm baseline
2022-10-02 16:23:14 +02:00
Grégoire Paris
3f2f42277e Update Psalm baseline 2022-10-02 16:02:57 +02:00
Grégoire Paris
757d950128 Merge pull request #10080 from greg0ire/add-missing-template-annotation
Address changes from doctrine/collections 1.8.0
2022-09-29 22:58:03 +02:00
Grégoire Paris
f07840b10c Address changes from doctrine/collections 1.8.0
Not quite sure why this annotation is not inherited.
2022-09-29 17:07:57 +02:00
Grégoire Paris
6e8afeeb60 Merge pull request #10072 from greg0ire/fix-return-type 2022-09-27 13:50:49 +02:00
Grégoire Paris
9130b27aca Remove return type override
In the parent class, all 3 methods are documented to return mixed.
This was not forward compatible with the addition of return types.
2022-09-27 13:41:09 +02:00
Grégoire Paris
2e7c2bb385 Merge pull request #10058 from HypeMC/enum-with-query-builder-fix
Fix using enums with the QueryBuilder
2022-09-23 22:08:15 +02:00
HypeMC
d69a0fa2cf Fix using enums with the QueryBuilder 2022-09-22 22:39:52 +02:00
23 changed files with 137 additions and 74 deletions

View File

@@ -10,4 +10,4 @@ on:
jobs:
coding-standards:
uses: "doctrine/.github/.github/workflows/coding-standards.yml@2.0.0"
uses: "doctrine/.github/.github/workflows/coding-standards.yml@2.1.0"

View File

@@ -36,7 +36,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -53,7 +53,7 @@ jobs:
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
@@ -68,7 +68,7 @@ jobs:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "phpunit-sqlite-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage*.xml"
@@ -110,7 +110,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -126,7 +126,7 @@ jobs:
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
@@ -134,7 +134,7 @@ jobs:
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage.xml"
@@ -185,7 +185,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -202,7 +202,7 @@ jobs:
extensions: "${{ matrix.extension }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
@@ -210,7 +210,7 @@ jobs:
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage.xml"
@@ -261,7 +261,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -278,7 +278,7 @@ jobs:
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
@@ -293,7 +293,7 @@ jobs:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage files"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage*.xml"
@@ -313,7 +313,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -324,7 +324,7 @@ jobs:
ini-values: "zend.assertions=1"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "${{ matrix.deps }}"
@@ -343,16 +343,16 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
- name: "Download coverage files"
uses: "actions/download-artifact@v2"
uses: "actions/download-artifact@v3"
with:
path: "reports"
- name: "Upload to Codecov"
uses: "codecov/codecov-action@v1"
uses: "codecov/codecov-action@v3"
with:
directory: reports

View File

@@ -24,7 +24,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -36,7 +36,7 @@ jobs:
ini-values: "zend.assertions=1"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v2"
uses: "actions/cache@v3"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"

View File

@@ -7,7 +7,7 @@ on:
jobs:
release:
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@2.0.0"
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@2.1.0"
secrets:
GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}

View File

@@ -33,7 +33,7 @@ jobs:
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -50,7 +50,7 @@ jobs:
if: "${{ matrix.persistence-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"
@@ -78,7 +78,7 @@ jobs:
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -87,7 +87,7 @@ jobs:
php-version: "${{ matrix.php-version }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"

View File

@@ -10,8 +10,8 @@ annotation metadata supported since the first version 2.0.
Index
-----
- :ref:`#[AssociationOverride] <attrref_associationoverride]`
- :ref:`#[AttributeOverride] <attrref_attributeoverride]`
- :ref:`#[AssociationOverride] <attrref_associationoverride>`
- :ref:`#[AttributeOverride] <attrref_attributeoverride>`
- :ref:`#[Column] <attrref_column>`
- :ref:`#[Cache] <attrref_cache>`
- :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
@@ -27,7 +27,6 @@ Index
- :ref:`#[Id] <attrref_id>`
- :ref:`#[InheritanceType] <attrref_inheritancetype>`
- :ref:`#[JoinColumn] <attrref_joincolumn>`
- :ref:`#[JoinColumns] <attrref_joincolumns>`
- :ref:`#[JoinTable] <attrref_jointable>`
- :ref:`#[ManyToOne] <attrref_manytoone>`
- :ref:`#[ManyToMany] <attrref_manytomany>`
@@ -179,7 +178,7 @@ Optional parameters:
If not specified, default value is ``false``.
- **insertable**: Boolean value to determine if the column should be
included when inserting a new row into the underlying entities table.
included when inserting a new row into the underlying entities table.
If not specified, default value is true.
- **updatable**: Boolean value to determine if the column should be

View File

@@ -1,5 +1,5 @@
Separating Concerns using Embeddables
-------------------------------------
=====================================
Embeddables are classes which are not entities themselves, but are embedded
in entities and can also be queried in DQL. You'll mostly want to use them

View File

@@ -464,14 +464,14 @@ abstract class AbstractHydrator
break;
}
if ($value !== null && isset($cacheKeyInfo['enumType'])) {
$value = $this->buildEnum($value, $cacheKeyInfo['enumType']);
}
$rowData['data'][$dqlAlias][$fieldName] = $type
? $type->convertToPHPValue($value, $this->_platform)
: $value;
if ($rowData['data'][$dqlAlias][$fieldName] !== null && isset($cacheKeyInfo['enumType'])) {
$rowData['data'][$dqlAlias][$fieldName] = $this->buildEnum($rowData['data'][$dqlAlias][$fieldName], $cacheKeyInfo['enumType']);
}
if ($cacheKeyInfo['isIdentifier'] && $value !== null) {
$id[$dqlAlias] .= '|' . $value;
$nonemptyComponents[$dqlAlias] = true;

View File

@@ -76,12 +76,11 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
}
/**
* {@inheritDoc}
*
* Do an optimized search of an element
*
* @param object $element
* @psalm-param TValue $element
*
* @return bool
* @template TMaybeContained
*/
public function contains($element)
{

View File

@@ -63,8 +63,8 @@ class ReflectionEnumProperty extends ReflectionProperty
}
/**
* @param object $object
* @param int|string|int[]|string[]|null $value
* @param object $object
* @param int|string|int[]|string[]|BackedEnum|BackedEnum[]|null $value
*/
public function setValue($object, $value = null): void
{
@@ -82,11 +82,15 @@ class ReflectionEnumProperty extends ReflectionProperty
}
/**
* @param object $object
* @param int|string $value
* @param object $object
* @param int|string|BackedEnum $value
*/
private function initializeEnumValue($object, $value): BackedEnum
{
if ($value instanceof BackedEnum) {
return $value;
}
$enumType = $this->enumType;
try {

View File

@@ -393,6 +393,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
/**
* {@inheritdoc}
*
* @template TMaybeContained
*/
public function contains($element): bool
{

View File

@@ -23,7 +23,7 @@ class SqlValueVisitor extends ExpressionVisitor
/**
* Converts a comparison expression into the target query language output.
*
* @return void
* {@inheritDoc}
*/
public function walkComparison(Comparison $comparison)
{
@@ -32,35 +32,39 @@ class SqlValueVisitor extends ExpressionVisitor
$operator = $comparison->getOperator();
if (($operator === Comparison::EQ || $operator === Comparison::IS) && $value === null) {
return;
return null;
} elseif ($operator === Comparison::NEQ && $value === null) {
return;
return null;
}
$this->values[] = $value;
$this->types[] = [$field, $value, $operator];
return null;
}
/**
* Converts a composite expression into the target query language output.
*
* @return void
* {@inheritDoc}
*/
public function walkCompositeExpression(CompositeExpression $expr)
{
foreach ($expr->getExpressionList() as $child) {
$this->dispatch($child);
}
return null;
}
/**
* Converts a value expression into the target query language part.
*
* @return void
* {@inheritDoc}
*/
public function walkValue(Value $value)
{
return;
return null;
}
/**

View File

@@ -527,11 +527,12 @@ public function __construct(<params>)
* Sets the class fields visibility for the entity (can either be private or protected).
*
* @param string $visibility
* @psalm-param self::FIELD_VISIBLE_*
*
* @return void
*
* @throws InvalidArgumentException
*
* @psalm-assert self::FIELD_VISIBLE_* $visibility
*/
public function setFieldVisibility($visibility)
{

View File

@@ -500,7 +500,7 @@
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Mapping/ClassMetadata.php">
<PropertyNotSetInConstructor occurrences="5">
<PropertyNotSetInConstructor occurrences="4">
<code>ClassMetadata</code>
<code>ClassMetadata</code>
<code>ClassMetadata</code>
@@ -525,10 +525,6 @@
<code>addNamedNativeQuery</code>
<code>addNamedQuery</code>
</DeprecatedMethod>
<DocblockTypeContradiction occurrences="2">
<code>! $definition</code>
<code>$definition</code>
</DocblockTypeContradiction>
<InvalidArrayOffset occurrences="1">
<code>$subClass-&gt;table[$indexType][$indexName]</code>
</InvalidArrayOffset>
@@ -661,10 +657,9 @@
<code>$this-&gt;associationMappings[$idProperty]['joinColumns']</code>
<code>$this-&gt;associationMappings[$idProperty]['joinColumns']</code>
</PossiblyUndefinedArrayOffset>
<PropertyNotSetInConstructor occurrences="5">
<PropertyNotSetInConstructor occurrences="4">
<code>$idGenerator</code>
<code>$namespace</code>
<code>$sequenceGeneratorDefinition</code>
<code>$table</code>
<code>$tableGeneratorDefinition</code>
</PropertyNotSetInConstructor>
@@ -2718,9 +2713,6 @@
<DocblockTypeContradiction occurrences="1">
<code>class_exists($metadata-&gt;name)</code>
</DocblockTypeContradiction>
<InvalidDocblock occurrences="1">
<code>public function setFieldVisibility($visibility)</code>
</InvalidDocblock>
<PossiblyFalseArgument occurrences="2">
<code>$last</code>
<code>strrpos($metadata-&gt;name, '\\')</code>
@@ -2735,9 +2727,7 @@
<code>(array) $metadata-&gt;table['options']</code>
<code>(bool) $embeddablesImmutable</code>
</RedundantCastGivenDocblockType>
<RedundantConditionGivenDocblockType occurrences="3">
<code>$metadata-&gt;sequenceGeneratorDefinition</code>
<code>$metadata-&gt;sequenceGeneratorDefinition</code>
<RedundantConditionGivenDocblockType occurrences="1">
<code>isset($metadata-&gt;lifecycleCallbacks)</code>
</RedundantConditionGivenDocblockType>
</file>
@@ -2840,10 +2830,9 @@
<code>$field['associationKey']</code>
<code>isset($field['associationKey']) &amp;&amp; $field['associationKey']</code>
</RedundantCondition>
<RedundantConditionGivenDocblockType occurrences="4">
<RedundantConditionGivenDocblockType occurrences="3">
<code>$metadata-&gt;inheritanceType</code>
<code>$metadata-&gt;inheritanceType</code>
<code>$sequenceDefinition</code>
<code>isset($metadata-&gt;lifecycleCallbacks)</code>
</RedundantConditionGivenDocblockType>
</file>

View File

@@ -92,6 +92,8 @@
<!-- DBAL 3.2 forward compatibility -->
<file name="lib/Doctrine/ORM/Tools/Pagination/CountOutputWalker.php"/>
<file name="lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php"/>
<!-- https://github.com/vimeo/psalm/issues/8520 -->
<file name="lib/Doctrine/ORM/PersistentCollection.php"/>
</errorLevel>
</DocblockTypeContradiction>
<InvalidArgument>

View File

@@ -51,7 +51,7 @@ class City
* @JoinColumn(name="state_id", referencedColumnName="id")
*/
#[ORM\Cache]
#[ORM\ManyToOne(targetEntity: 'State', inversedBy: 'citities')]
#[ORM\ManyToOne(targetEntity: 'State', inversedBy: 'cities')]
#[ORM\JoinColumn(name: 'state_id', referencedColumnName: 'id')]
protected $state;

View File

@@ -66,6 +66,58 @@ class EnumTest extends OrmFunctionalTestCase
$this->assertEquals(Suit::Clubs, $fetchedCard->suit);
}
public function testEnumHydrationObjectHydrator(): void
{
$this->setUpEntitySchema([Card::class]);
$card1 = new Card();
$card1->suit = Suit::Clubs;
$card2 = new Card();
$card2->suit = Suit::Hearts;
$this->_em->persist($card1);
$this->_em->persist($card2);
$this->_em->flush();
unset($card1, $card2);
$this->_em->clear();
/** @var list<Card> $foundCards */
$foundCards = $this->_em->createQueryBuilder()
->select('c')
->from(Card::class, 'c')
->where('c.suit = :suit')
->setParameter('suit', Suit::Clubs)
->getQuery()
->getResult();
self::assertNotEmpty($foundCards);
foreach ($foundCards as $card) {
self::assertSame(Suit::Clubs, $card->suit);
}
}
public function testEnumArrayHydrationObjectHydrator(): void
{
$this->setUpEntitySchema([Scale::class]);
$scale = new Scale();
$scale->supportedUnits = [Unit::Gram, Unit::Meter];
$this->_em->persist($scale);
$this->_em->flush();
$this->_em->clear();
$result = $this->_em->createQueryBuilder()
->from(Scale::class, 's')
->select('s')
->getQuery()
->getResult();
self::assertInstanceOf(Scale::class, $result[0]);
self::assertEqualsCanonicalizing([Unit::Gram, Unit::Meter], $result[0]->supportedUnits);
}
public function testEnumHydration(): void
{
$this->setUpEntitySchema([Card::class, CardWithNullable::class]);

View File

@@ -125,7 +125,7 @@ class DDC5684Object
/**
* @var DDC5684ObjectIdType
* @Id
* @Column(type=Doctrine\Tests\ORM\Functional\Ticket\DDC5684ObjectIdType::class)
* @Column(type=DDC5684ObjectIdType::class)
* @GeneratedValue(strategy="AUTO")
*/
public $id;

View File

@@ -153,8 +153,8 @@ class GH6141People
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="gh6141people")
* @DiscriminatorMap({
* Doctrine\Tests\ORM\Functional\Ticket\GH6141People::BOSS = GH6141Boss::class,
* Doctrine\Tests\ORM\Functional\Ticket\GH6141People::EMPLOYEE = GH6141Employee::class
* GH6141People::BOSS = GH6141Boss::class,
* GH6141People::EMPLOYEE = GH6141Employee::class
* })
*/
abstract class GH6141Person

View File

@@ -58,7 +58,7 @@ class GH7012UserData
/**
* @var QuotedUser
* @Id
* @OneToOne(targetEntity=Doctrine\Tests\Models\Quote\User::class)
* @OneToOne(targetEntity=QuotedUser::class)
* @JoinColumn(name="`user-id`", referencedColumnName="`user-id`", onDelete="CASCADE")
*/
public $user;

View File

@@ -48,8 +48,8 @@ class GH7512Test extends OrmFunctionalTestCase
* @Entity()
* @InheritanceType("JOINED")
* @DiscriminatorMap({
* "entitya"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA::class,
* "entityB"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityB::class
* "entitya"=GH7512EntityA::class,
* "entityB"=GH7512EntityB::class
* })
*/
class GH7512EntityA
@@ -63,7 +63,7 @@ class GH7512EntityA
public $id;
/**
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityC", mappedBy="entityA")
* @OneToMany(targetEntity="GH7512EntityC", mappedBy="entityA")
* @var Collection<int, GH7512EntityC>
*/
public $entityCs;
@@ -86,7 +86,7 @@ class GH7512EntityC
public $id;
/**
* @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA", inversedBy="entityCs")
* @ManyToOne(targetEntity="GH7512EntityA", inversedBy="entityCs")
* @var GH7512EntityA
*/
public $entityA;

View File

@@ -21,6 +21,8 @@ use stdClass;
use function array_keys;
use function assert;
use function method_exists;
use function serialize;
use function unserialize;
/**
* Tests the lazy-loading capabilities of the PersistentCollection and the initialization of collections.
@@ -286,4 +288,13 @@ class PersistentCollectionTest extends OrmTestCase
$this->collection->clear();
}
public function testItCanBeSerializedAndUnserializedBack(): void
{
$this->collection->add(new stdClass());
$collection = unserialize(serialize($this->collection));
$collection->add(new stdClass());
$collection[3] = new stdClass();
self::assertCount(3, $collection);
}
}

View File

@@ -366,7 +366,7 @@ class DDC1649Two
{
/**
* @var DDC1649One
* @Id @ManyToOne(targetEntity="DDC1649One")@JoinColumn(name="id", referencedColumnName="id")
* @Id @ManyToOne(targetEntity="DDC1649One")
*/
public $one;
}