From 523697d0b663221bc91d39c93b4317d164726816 Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 09:29:56 +0200 Subject: [PATCH 1/7] [DDC-1398] Extra-lazy get for indexed associations If an association is EXTRA_LAZY and has an indexBy, then you can call get() without loading the entire collection. --- lib/Doctrine/ORM/PersistentCollection.php | 8 ++++ .../ORM/Persisters/ManyToManyPersister.php | 18 ++++++++ .../ORM/Persisters/OneToManyPersister.php | 18 ++++++++ .../Functional/ExtraLazyCollectionTest.php | 41 ++++++++++++++++++- 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 53ba1c1f2..d5a922aaf 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -517,6 +517,14 @@ final class PersistentCollection implements Collection, Selectable */ public function get($key) { + if ( ! $this->initialized + && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY + && isset($this->association['indexBy']) + ) { + $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); + return $persister->get($this, $key); + } + $this->initialize(); return $this->coll->get($key); diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index d9f7e30ca..4ad32e8d8 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -33,6 +33,24 @@ use Doctrine\ORM\UnitOfWork; */ class ManyToManyPersister extends AbstractCollectionPersister { + /** + * {@inheritdoc} + * + * @override + */ + public function get(PersistentCollection $coll, $index) + { + $mapping = $coll->getMapping(); + $uow = $this->em->getUnitOfWork(); + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + if (!isset($mapping['indexBy'])) { + throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); + } + + return current($persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1)); + } + /** * {@inheritdoc} * diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index 911d699f6..041dfe5e2 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -32,6 +32,24 @@ use Doctrine\ORM\UnitOfWork; */ class OneToManyPersister extends AbstractCollectionPersister { + /** + * {@inheritdoc} + * + * @override + */ + public function get(PersistentCollection $coll, $index) + { + $mapping = $coll->getMapping(); + $uow = $this->em->getUnitOfWork(); + $persister = $uow->getEntityPersister($mapping['targetEntity']); + + if (!isset($mapping['indexBy'])) { + throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); + } + + return current($persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1)); + } + /** * Generates the SQL UPDATE that updates a particular row's foreign * key to null. diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index b6c7a0f1e..aa6adb13a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -24,7 +24,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['groups']['indexBy'] = 'id'; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['articles']['indexBy'] = 'id'; $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; @@ -40,6 +42,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + unset($class->associationMappings['groups']['indexBy']); + unset($class->associationMappings['articles']['indexBy']); + $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY; } @@ -174,8 +179,8 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); $this->assertEquals(2, count($someGroups)); - $this->assertTrue($user->groups->contains($someGroups[0])); - $this->assertTrue($user->groups->contains($someGroups[1])); + $this->assertTrue($user->groups->contains(array_shift($someGroups))); + $this->assertTrue($user->groups->contains(array_shift($someGroups))); } /** @@ -512,6 +517,38 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($qc + 1, $this->getCurrentQueryCount()); } + /** + * @group DDC-1398 + */ + public function testGetIndexByOneToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $queryCount = $this->getCurrentQueryCount(); + + $user->articles->get($this->articleId); + + $this->assertFalse($user->articles->isInitialized()); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + } + + /** + * @group DDC-1398 + */ + public function testGetIndexByManyToMany() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $queryCount = $this->getCurrentQueryCount(); + + $user->groups->get($this->groupId); + + $this->assertFalse($user->groups->isInitialized()); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + } + private function loadFixture() { $user1 = new \Doctrine\Tests\Models\CMS\CmsUser(); From 3555007f08c94435921d3c1ca2ad46e38a82ba2b Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 10:09:52 +0200 Subject: [PATCH 2/7] Return NULL for non-existent keys The load() function already returns just one entity or NULL, so the current() is not needed and the result can be returned directly. --- lib/Doctrine/ORM/Persisters/ManyToManyPersister.php | 2 +- lib/Doctrine/ORM/Persisters/OneToManyPersister.php | 2 +- .../Tests/ORM/Functional/ExtraLazyCollectionTest.php | 12 ++++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php index 4ad32e8d8..df46aa30a 100644 --- a/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php @@ -48,7 +48,7 @@ class ManyToManyPersister extends AbstractCollectionPersister throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - return current($persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1)); + return $persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1); } /** diff --git a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php index 041dfe5e2..120ad548d 100644 --- a/lib/Doctrine/ORM/Persisters/OneToManyPersister.php +++ b/lib/Doctrine/ORM/Persisters/OneToManyPersister.php @@ -47,7 +47,7 @@ class OneToManyPersister extends AbstractCollectionPersister throw new \BadMethodCallException("Selecting a collection by index is only supported on indexed collections."); } - return current($persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1)); + return $persister->load(array($mapping['indexBy'] => $index), null, null, array(), 0, 1); } /** diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index aa6adb13a..fe642ac1b 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -549,6 +549,18 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); } + /** + * @group DDC-1398 + */ + public function testGetNonExistentIndexBy() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $this->assertNull($user->articles->get(-1)); + $this->assertNull($user->groups->get(-1)); + } + private function loadFixture() { $user1 = new \Doctrine\Tests\Models\CMS\CmsUser(); From 647c5e2cad135abb9158a538b4e3f7758f8b71ed Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 10:18:08 +0200 Subject: [PATCH 3/7] Test actual data returned by get() --- .../Tests/ORM/Functional/ExtraLazyCollectionTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index fe642ac1b..b1a2f7fd4 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -527,10 +527,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $queryCount = $this->getCurrentQueryCount(); - $user->articles->get($this->articleId); + $article = $user->articles->get($this->articleId); $this->assertFalse($user->articles->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + $this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId)); } /** @@ -543,10 +544,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $queryCount = $this->getCurrentQueryCount(); - $user->groups->get($this->groupId); + $group = $user->groups->get($this->groupId); $this->assertFalse($user->groups->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + $this->assertSame($group, $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId)); } /** From 53c9ffda302af24e137607b244591b79419e6116 Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 10:20:16 +0200 Subject: [PATCH 4/7] Get rid of variable --- lib/Doctrine/ORM/PersistentCollection.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index d5a922aaf..dd5a90d18 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -521,8 +521,7 @@ final class PersistentCollection implements Collection, Selectable && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY && isset($this->association['indexBy']) ) { - $persister = $this->em->getUnitOfWork()->getCollectionPersister($this->association); - return $persister->get($this, $key); + return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key); } $this->initialize(); From 3b92cfac5a7ae7fdc853b819f3d12505f2fe1c2f Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 13:45:38 +0200 Subject: [PATCH 5/7] Use find() if the indexBy field is the identifier --- lib/Doctrine/ORM/PersistentCollection.php | 6 ++++++ .../Tests/ORM/Functional/ExtraLazyCollectionTest.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index dd5a90d18..4e64acb26 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -521,6 +521,12 @@ final class PersistentCollection implements Collection, Selectable && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY && isset($this->association['indexBy']) ) { + $class = $this->em->getClassMetadata($this->association['targetEntity']); + + if (!$class->isIdentifierComposite && $class->isIdentifier($this->association['indexBy'])) { + return $this->em->find($class->name, $key); + } + return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key); } diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index b1a2f7fd4..cbafd1132 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -532,6 +532,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertFalse($user->articles->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); $this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId)); + + $article = $user->articles->get($this->articleId); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); } /** @@ -549,6 +552,9 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertFalse($user->groups->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); $this->assertSame($group, $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId)); + + $group = $user->groups->get($this->groupId); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); } /** From 28791620157c413e9dce23663a064eeb012061e3 Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 14:00:58 +0200 Subject: [PATCH 6/7] No need to lookup metadata --- lib/Doctrine/ORM/PersistentCollection.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 4e64acb26..a50cd8343 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -521,10 +521,8 @@ final class PersistentCollection implements Collection, Selectable && $this->association['fetch'] === Mapping\ClassMetadataInfo::FETCH_EXTRA_LAZY && isset($this->association['indexBy']) ) { - $class = $this->em->getClassMetadata($this->association['targetEntity']); - - if (!$class->isIdentifierComposite && $class->isIdentifier($this->association['indexBy'])) { - return $this->em->find($class->name, $key); + if (!$this->typeClass->isIdentifierComposite && $this->typeClass->isIdentifier($this->association['indexBy'])) { + return $this->em->find($this->typeClass->name, $key); } return $this->em->getUnitOfWork()->getCollectionPersister($this->association)->get($this, $key); From 70427871ce73090441ea8c0ed635efe6782a48c3 Mon Sep 17 00:00:00 2001 From: Sander Marechal Date: Thu, 20 Jun 2013 14:20:00 +0200 Subject: [PATCH 7/7] Extra test for indexBy identifier versus indexBy other fields --- .../Functional/ExtraLazyCollectionTest.php | 63 ++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php index cbafd1132..5d8fa0f2a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ExtraLazyCollectionTest.php @@ -17,6 +17,10 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase private $groupId; private $articleId; + private $groupname; + private $topic; + private $phonenumber; + public function setUp() { $this->useModelSet('cms'); @@ -24,9 +28,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; - $class->associationMappings['groups']['indexBy'] = 'id'; + $class->associationMappings['groups']['indexBy'] = 'name'; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; - $class->associationMappings['articles']['indexBy'] = 'id'; + $class->associationMappings['articles']['indexBy'] = 'topic'; + $class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; + $class->associationMappings['phonenumbers']['indexBy'] = 'phonenumber'; $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_EXTRA_LAZY; @@ -41,9 +47,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'); $class->associationMappings['groups']['fetch'] = ClassMetadataInfo::FETCH_LAZY; $class->associationMappings['articles']['fetch'] = ClassMetadataInfo::FETCH_LAZY; + $class->associationMappings['phonenumbers']['fetch'] = ClassMetadataInfo::FETCH_LAZY; unset($class->associationMappings['groups']['indexBy']); unset($class->associationMappings['articles']['indexBy']); + unset($class->associationMappings['phonenumbers']['indexBy']); $class = $this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsGroup'); $class->associationMappings['users']['fetch'] = ClassMetadataInfo::FETCH_LAZY; @@ -517,6 +525,26 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals($qc + 1, $this->getCurrentQueryCount()); } + /** + * @group DDC-1398 + */ + public function testGetIndexByIdentifier() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + /* @var $user CmsUser */ + + $queryCount = $this->getCurrentQueryCount(); + + $phonenumber = $user->phonenumbers->get($this->phonenumber); + + $this->assertFalse($user->phonenumbers->isInitialized()); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + $this->assertSame($phonenumber, $this->_em->find('Doctrine\Tests\Models\CMS\CmsPhonenumber', $this->phonenumber)); + + $article = $user->phonenumbers->get($this->phonenumber); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); + } + /** * @group DDC-1398 */ @@ -527,14 +555,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $queryCount = $this->getCurrentQueryCount(); - $article = $user->articles->get($this->articleId); + $article = $user->articles->get($this->topic); $this->assertFalse($user->articles->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); $this->assertSame($article, $this->_em->find('Doctrine\Tests\Models\CMS\CmsArticle', $this->articleId)); - - $article = $user->articles->get($this->articleId); - $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); } /** @@ -547,14 +572,11 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $queryCount = $this->getCurrentQueryCount(); - $group = $user->groups->get($this->groupId); + $group = $user->groups->get($this->groupname); $this->assertFalse($user->groups->isInitialized()); $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); $this->assertSame($group, $this->_em->find('Doctrine\Tests\Models\CMS\CmsGroup', $this->groupId)); - - $group = $user->groups->get($this->groupId); - $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount(), "Getting the same entity should not cause an extra query to be executed"); } /** @@ -618,23 +640,36 @@ class ExtraLazyCollectionTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->persist($group3); $article1 = new \Doctrine\Tests\Models\CMS\CmsArticle(); - $article1->topic = "Test"; - $article1->text = "Test"; + $article1->topic = "Test1"; + $article1->text = "Test1"; $article1->setAuthor($user1); $article2 = new \Doctrine\Tests\Models\CMS\CmsArticle(); - $article2->topic = "Test"; - $article2->text = "Test"; + $article2->topic = "Test2"; + $article2->text = "Test2"; $article2->setAuthor($user1); $this->_em->persist($article1); $this->_em->persist($article2); + $phonenumber1 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $phonenumber1->phonenumber = '12345'; + + $phonenumber2 = new \Doctrine\Tests\Models\CMS\CmsPhonenumber(); + $phonenumber2->phonenumber = '67890'; + + $this->_em->persist($phonenumber1); + $this->_em->persist($phonenumber2); + $this->_em->flush(); $this->_em->clear(); $this->articleId = $article1->id; $this->userId = $user1->getId(); $this->groupId = $group1->id; + + $this->groupname = $group1->name; + $this->topic = $article1->topic; + $this->phonenumber = $phonenumber1->phonenumber; } } \ No newline at end of file