Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 16 | class CacheTest extends \PHPUnit_Framework_TestCase |
||
| 17 | { |
||
| 18 | /** |
||
| 19 | * @var \Joomla\Cache\Cache |
||
| 20 | * @since 1.0 |
||
| 21 | */ |
||
| 22 | public $instance; |
||
| 23 | |||
| 24 | /** |
||
| 25 | * @var string Cache Classname to test |
||
| 26 | * @since 1.0 |
||
| 27 | */ |
||
| 28 | public $cacheClass = 'Joomla\\Cache\\Tests\\ConcreteCache'; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @var array |
||
| 32 | * @since 1.0 |
||
| 33 | */ |
||
| 34 | public $cacheOptions = array('foo' => 900); |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Tests the registry options is correctly initialised. |
||
| 38 | * |
||
| 39 | * @return void |
||
| 40 | * |
||
| 41 | * @covers Joomla\Cache\Cache::__construct |
||
| 42 | * @covers Joomla\Cache\Apc::__construct |
||
| 43 | * @covers Joomla\Cache\Memcached::__construct |
||
| 44 | * |
||
| 45 | * @since 1.0 |
||
| 46 | */ |
||
| 47 | public function test__construct() |
||
| 48 | { |
||
| 49 | $this->assertEquals('900', $this->instance->getOption('foo')); |
||
| 50 | } |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Tests the Joomla\Cache\Cache::__construct method. |
||
| 54 | * |
||
| 55 | * @return void |
||
| 56 | * |
||
| 57 | * @covers Joomla\Cache\Cache::__construct |
||
| 58 | * @covers Joomla\Cache\Apc::__construct |
||
| 59 | * @covers Joomla\Cache\Memcached::__construct |
||
| 60 | * @expectedException \Joomla\Cache\Exception\InvalidArgumentException |
||
| 61 | * @since 1.0 |
||
| 62 | */ |
||
| 63 | public function test__constructWithInvalidParams() |
||
| 64 | { |
||
| 65 | // Throws exception, options is null |
||
| 66 | $className = $this->cacheClass; |
||
| 67 | new $className(null); |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Tests the Joomla\Cache\Cache::clear method. |
||
| 72 | * |
||
| 73 | * @return void |
||
| 74 | * |
||
| 75 | * @covers Joomla\Cache\Cache::clear |
||
| 76 | * @covers Joomla\Cache\Memcached::clear |
||
| 77 | * @since 1.1.3 |
||
| 78 | */ |
||
| 79 | public function testClear() |
||
| 80 | { |
||
| 81 | $cacheInstance = $this->instance; |
||
| 82 | $cacheInstance->clear(); |
||
| 83 | |||
| 84 | $this->assertFalse( |
||
| 85 | $cacheInstance->hasItem('foobar'), |
||
| 86 | __LINE__ |
||
| 87 | ); |
||
| 88 | |||
| 89 | // Create a stub for the CacheItemInterface class. |
||
| 90 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 91 | ->getMock(); |
||
| 92 | |||
| 93 | // Configure the stub. |
||
| 94 | $stub->method('get') |
||
| 95 | ->willReturn('barfoo'); |
||
| 96 | |||
| 97 | // Configure the stub. |
||
| 98 | $stub->method('getKey') |
||
| 99 | ->willReturn('foobar'); |
||
| 100 | |||
| 101 | $this->assertTrue( |
||
| 102 | $cacheInstance->save($stub), |
||
| 103 | __LINE__ |
||
| 104 | ); |
||
| 105 | |||
| 106 | $this->assertTrue( |
||
| 107 | $cacheInstance->hasItem('foobar'), |
||
| 108 | __LINE__ |
||
| 109 | ); |
||
| 110 | |||
| 111 | $this->assertTrue( |
||
| 112 | $cacheInstance->clear(), |
||
| 113 | __LINE__ |
||
| 114 | ); |
||
| 115 | |||
| 116 | $this->assertFalse( |
||
| 117 | $cacheInstance->hasItem('foobar'), |
||
| 118 | __LINE__ |
||
| 119 | ); |
||
| 120 | } |
||
| 121 | |||
| 122 | /** |
||
| 123 | * Tests the the Joomla\Cache\Cache::get method. |
||
| 124 | * |
||
| 125 | * @return void |
||
| 126 | * |
||
| 127 | * @covers Joomla\Cache\Memcached::get |
||
| 128 | * @covers Joomla\Cache\Memcached::connect |
||
| 129 | * @since 1.0 |
||
| 130 | */ |
||
| 131 | public function testGet() |
||
| 132 | { |
||
| 133 | $cacheInstance = $this->instance; |
||
| 134 | $cacheInstance->clear(); |
||
| 135 | |||
| 136 | // Create a stub for the CacheItemInterface class. |
||
| 137 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 138 | ->getMock(); |
||
| 139 | |||
| 140 | $stub->method('get') |
||
| 141 | ->willReturn('bar'); |
||
| 142 | |||
| 143 | $stub->method('getKey') |
||
| 144 | ->willReturn('foo'); |
||
| 145 | |||
| 146 | $cacheInstance->save($stub); |
||
| 147 | $this->hitKey('foo', 'bar'); |
||
| 148 | $this->missKey('foobar', 'foobar'); |
||
| 149 | } |
||
| 150 | |||
| 151 | /** |
||
| 152 | * Checks to ensure a that $key is not set at all in the Cache |
||
| 153 | * |
||
| 154 | * @param string $key Key of cache item to check |
||
| 155 | * @param string $value Value cache item should be |
||
| 156 | * |
||
| 157 | * @return void |
||
| 158 | * |
||
| 159 | * @since 1.1 |
||
| 160 | */ |
||
| 161 | protected function missKey($key = '', $value = '') |
||
| 162 | { |
||
| 163 | $cacheInstance = $this->instance; |
||
| 164 | $cacheItem = $cacheInstance->getItem($key); |
||
| 165 | $cacheValue = $cacheItem->get(); |
||
| 166 | $cacheKey = $cacheItem->getKey(); |
||
| 167 | $cacheHit = $cacheItem->isHit(); |
||
| 168 | $this->assertThat($cacheKey, $this->equalTo($key), __LINE__); |
||
| 169 | $this->assertNull($cacheValue, __LINE__); |
||
| 170 | $this->assertFalse($cacheHit, __LINE__); |
||
| 171 | } |
||
| 172 | |||
| 173 | /** |
||
| 174 | * Checks to ensure a that $key is set to $value in the Cache |
||
| 175 | * |
||
| 176 | * @param string $key Key of cache item to check |
||
| 177 | * @param string $value Value cache item should be |
||
| 178 | * |
||
| 179 | * @return void |
||
| 180 | * |
||
| 181 | * @since 1.1 |
||
| 182 | */ |
||
| 183 | protected function hitKey($key = '', $value = '') |
||
| 184 | { |
||
| 185 | $cacheInstance = $this->instance; |
||
| 186 | $cacheItem = $cacheInstance->getItem($key); |
||
| 187 | $cacheKey = $cacheItem->getKey(); |
||
| 188 | $cacheValue = $cacheItem->get(); |
||
| 189 | $cacheHit = $cacheItem->isHit(); |
||
| 190 | $this->assertThat($cacheKey, $this->equalTo($key), __LINE__); |
||
| 191 | $this->assertThat($cacheValue, $this->equalTo($value), __LINE__); |
||
| 192 | $this->assertTrue($cacheHit, __LINE__); |
||
| 193 | } |
||
| 194 | |||
| 195 | /** |
||
| 196 | * Tests the Joomla\Cache\Cache::set method. |
||
| 197 | * |
||
| 198 | * @return void |
||
| 199 | * |
||
| 200 | * @covers Joomla\Cache\Cache::set |
||
| 201 | * @covers Joomla\Cache\Memcached::set |
||
| 202 | * @covers Joomla\Cache\Memcached::connect |
||
| 203 | * @since 1.0 |
||
| 204 | */ |
||
| 205 | public function testSet() |
||
| 206 | { |
||
| 207 | $cacheInstance = $this->instance; |
||
| 208 | $cacheInstance->clear(); |
||
| 209 | |||
| 210 | // Create a stub for the CacheItemInterface class. |
||
| 211 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 212 | ->getMock(); |
||
| 213 | |||
| 214 | $stub->method('get') |
||
| 215 | ->willReturn('barSet'); |
||
| 216 | |||
| 217 | $stub->method('getKey') |
||
| 218 | ->willReturn('fooSet'); |
||
| 219 | |||
| 220 | $result = $cacheInstance->save($stub); |
||
| 221 | $this->assertTrue($result, __LINE__); |
||
| 222 | |||
| 223 | $fooValue = $cacheInstance->getItem('fooSet')->get(); |
||
| 224 | $this->assertThat($fooValue, $this->equalTo('barSet'), __LINE__); |
||
| 225 | } |
||
| 226 | |||
| 227 | /** |
||
| 228 | * Tests the Joomla\Cache\Cache::getItems method. |
||
| 229 | * |
||
| 230 | * @return void |
||
| 231 | * |
||
| 232 | * @covers Joomla\Cache\Cache::getItems |
||
| 233 | * @covers Joomla\Cache\Apc::getItems |
||
| 234 | * @since 1.0 |
||
| 235 | */ |
||
| 236 | public function testGetItems() |
||
| 237 | { |
||
| 238 | $cacheInstance = $this->instance; |
||
| 239 | $cacheInstance->clear(); |
||
| 240 | |||
| 241 | // Create a stub for the CacheItemInterface class. |
||
| 242 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 243 | ->getMock(); |
||
| 244 | |||
| 245 | $stub->method('get') |
||
| 246 | ->willReturn('foo'); |
||
| 247 | |||
| 248 | $stub->method('getKey') |
||
| 249 | ->willReturn('foo'); |
||
| 250 | |||
| 251 | // Create a stub for the CacheItemInterface class. |
||
| 252 | $stub2 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 253 | ->getMock(); |
||
| 254 | |||
| 255 | $stub2->method('get') |
||
| 256 | ->willReturn('bar'); |
||
| 257 | |||
| 258 | $stub2->method('getKey') |
||
| 259 | ->willReturn('bar'); |
||
| 260 | |||
| 261 | // Create a stub for the CacheItemInterface class. |
||
| 262 | $stub3 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 263 | ->getMock(); |
||
| 264 | |||
| 265 | $stub3->method('get') |
||
| 266 | ->willReturn('world'); |
||
| 267 | |||
| 268 | $stub3->method('getKey') |
||
| 269 | ->willReturn('hello'); |
||
| 270 | |||
| 271 | $samples = array($stub, $stub2, $stub3); |
||
| 272 | $expectedSamples = array('foo' => 'foo', 'bar' => 'bar', 'hello' => 'world'); |
||
| 273 | $moreSamples = $samples; |
||
| 274 | |||
| 275 | // Create a stub for the CacheItemInterface class. |
||
| 276 | $stub4 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 277 | ->getMock(); |
||
| 278 | |||
| 279 | $stub4->method('get') |
||
| 280 | ->willReturn('bar'); |
||
| 281 | |||
| 282 | $stub4->method('getKey') |
||
| 283 | ->willReturn('next'); |
||
| 284 | |||
| 285 | $moreSamples[] = $stub4; |
||
| 286 | $lessSamples = $samples; |
||
| 287 | $badSampleKeys = array('foobar', 'barfoo', 'helloworld'); |
||
| 288 | |||
| 289 | // Pop an item from the array |
||
| 290 | array_pop($lessSamples); |
||
| 291 | |||
| 292 | $keys = array('foo', 'bar', 'hello'); |
||
| 293 | |||
| 294 | foreach ($samples as $poolItem) |
||
| 295 | { |
||
| 296 | $cacheInstance->save($poolItem); |
||
| 297 | } |
||
| 298 | |||
| 299 | $results = $cacheInstance->getItems($keys); |
||
| 300 | $this->assertSameSize($samples, $results, __LINE__); |
||
| 301 | $this->assertNotSameSize($moreSamples, $results, __LINE__); |
||
| 302 | $this->assertNotSameSize($lessSamples, $results, __LINE__); |
||
| 303 | |||
| 304 | /** @var CacheItemInterface $item */ |
||
| 305 | foreach ($results as $item) |
||
| 306 | { |
||
| 307 | $itemKey = $item->getKey(); |
||
| 308 | $itemValue = $item->get(); |
||
| 309 | $this->assertEquals($itemValue, $expectedSamples[$itemKey], __LINE__); |
||
| 310 | } |
||
| 311 | |||
| 312 | // Even if no keys are set, we should still$ have an array of keys |
||
| 313 | $badResults = $cacheInstance->getItems($badSampleKeys); |
||
| 314 | $this->assertSameSize($badSampleKeys, $badResults, __LINE__); |
||
| 315 | } |
||
| 316 | |||
| 317 | /** |
||
| 318 | * Tests the Joomla\Cache\Cache::testDeleteItems method. |
||
| 319 | * |
||
| 320 | * @return void |
||
| 321 | * |
||
| 322 | * @covers Joomla\Cache\Cache::testDeleteItems |
||
| 323 | * @since 1.0 |
||
| 324 | */ |
||
| 325 | public function testDeleteItems() |
||
| 326 | { |
||
| 327 | $cacheInstance = $this->instance; |
||
| 328 | $cacheInstance->clear(); |
||
| 329 | |||
| 330 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 331 | ->getMock(); |
||
| 332 | |||
| 333 | $stub->method('get') |
||
| 334 | ->willReturn('bars'); |
||
| 335 | |||
| 336 | $stub->method('getKey') |
||
| 337 | ->willReturn('foo'); |
||
| 338 | |||
| 339 | // Create a stub for the CacheItemInterface class. |
||
| 340 | $stub2 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 341 | ->getMock(); |
||
| 342 | |||
| 343 | $stub2->method('get') |
||
| 344 | ->willReturn('google'); |
||
| 345 | |||
| 346 | $stub2->method('getKey') |
||
| 347 | ->willReturn('goo'); |
||
| 348 | |||
| 349 | // Create a stub for the CacheItemInterface class. |
||
| 350 | $stub3 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 351 | ->getMock(); |
||
| 352 | |||
| 353 | $stub3->method('get') |
||
| 354 | ->willReturn('world'); |
||
| 355 | |||
| 356 | $stub3->method('getKey') |
||
| 357 | ->willReturn('hello'); |
||
| 358 | |||
| 359 | $samples = array($stub, $stub2, $stub3); |
||
| 360 | |||
| 361 | foreach ($samples as $cacheItem) |
||
| 362 | { |
||
| 363 | $cacheInstance->save($cacheItem); |
||
| 364 | } |
||
| 365 | |||
| 366 | $trueSampleKeys = array('foo', 'goo', 'hello'); |
||
| 367 | |||
| 368 | $sampleKeys = array_merge( |
||
| 369 | $trueSampleKeys, |
||
| 370 | array('foobar') |
||
| 371 | ); |
||
| 372 | $results = $cacheInstance->deleteItems($sampleKeys); |
||
| 373 | |||
| 374 | foreach ($results as $key => $removed) |
||
| 375 | { |
||
| 376 | $this->assertTrue($removed, "The $key key should be removed even when it does not exist."); |
||
| 377 | } |
||
| 378 | } |
||
| 379 | |||
| 380 | /** |
||
| 381 | * Tests the Joomla\Cache\Cache::deleteItem method. |
||
| 382 | * |
||
| 383 | * @return void |
||
| 384 | * |
||
| 385 | * @covers Joomla\Cache\Cache::deleteItem |
||
| 386 | * @covers Joomla\Cache\Memcached::deleteItem |
||
| 387 | * @covers Joomla\Cache\Memcached::connect |
||
| 388 | * @since 1.0 |
||
| 389 | */ |
||
| 390 | public function testDeleteItem() |
||
| 391 | { |
||
| 392 | $cacheInstance = $this->instance; |
||
| 393 | $cacheInstance->clear(); |
||
| 394 | |||
| 395 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 396 | ->getMock(); |
||
| 397 | |||
| 398 | $stub->method('get') |
||
| 399 | ->willReturn('bars'); |
||
| 400 | |||
| 401 | $stub->method('getKey') |
||
| 402 | ->willReturn('foo2'); |
||
| 403 | |||
| 404 | // Create a stub for the CacheItemInterface class. |
||
| 405 | $stub2 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 406 | ->getMock(); |
||
| 407 | |||
| 408 | $stub2->method('get') |
||
| 409 | ->willReturn('google'); |
||
| 410 | |||
| 411 | $stub2->method('getKey') |
||
| 412 | ->willReturn('goo2'); |
||
| 413 | |||
| 414 | // Create a stub for the CacheItemInterface class. |
||
| 415 | $stub3 = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 416 | ->getMock(); |
||
| 417 | |||
| 418 | $stub3->method('get') |
||
| 419 | ->willReturn('world'); |
||
| 420 | |||
| 421 | $stub3->method('getKey') |
||
| 422 | ->willReturn('hello2'); |
||
| 423 | |||
| 424 | $samples = array($stub, $stub2, $stub3); |
||
| 425 | |||
| 426 | foreach ($samples as $cacheItem) |
||
| 427 | { |
||
| 428 | $cacheInstance->save($cacheItem); |
||
| 429 | } |
||
| 430 | |||
| 431 | $getFoo = $cacheInstance->getItem('foo2'); |
||
| 432 | $this->assertTrue($getFoo->isHit(), __LINE__); |
||
| 433 | $removeFoo = $cacheInstance->deleteItem('foo2'); |
||
| 434 | $this->assertTrue($removeFoo, __LINE__); |
||
| 435 | $removeFoobar = $cacheInstance->deleteItem('foobar'); |
||
| 436 | $this->assertTrue($removeFoobar, __LINE__); |
||
| 437 | $getResult = $cacheInstance->getItem('foo2'); |
||
| 438 | $this->assertFalse($getResult->isHit(), __LINE__); |
||
| 439 | } |
||
| 440 | |||
| 441 | /** |
||
| 442 | * Tests the Joomla\Cache\Cache::setOption method. |
||
| 443 | * |
||
| 444 | * @return void |
||
| 445 | * |
||
| 446 | * @covers Joomla\Cache\Cache::getOption |
||
| 447 | * @covers Joomla\Cache\Cache::setOption |
||
| 448 | * @since 1.0 |
||
| 449 | */ |
||
| 450 | public function testSetOption() |
||
| 451 | { |
||
| 452 | $cacheInstance = $this->instance; |
||
| 453 | $this->assertSame($cacheInstance, $cacheInstance->setOption('foo', 'bar'), 'Checks chaining'); |
||
| 454 | $this->assertEquals('bar', $cacheInstance->getOption('foo')); |
||
| 455 | } |
||
| 456 | |||
| 457 | /** |
||
| 458 | * Tests the Joomla\Cache\Cache::hasItem method. |
||
| 459 | * |
||
| 460 | * @return void |
||
| 461 | * |
||
| 462 | * @covers Joomla\Cache\Cache::hasItem |
||
| 463 | * @covers Joomla\Cache\Memcached::hasItem |
||
| 464 | * @since 1.1.3 |
||
| 465 | */ |
||
| 466 | public function testHasItem() |
||
| 467 | { |
||
| 468 | $cacheInstance = $this->instance; |
||
| 469 | $cacheInstance->clear(); |
||
| 470 | |||
| 471 | $this->assertFalse( |
||
| 472 | $cacheInstance->hasItem('foobar'), |
||
| 473 | __LINE__ |
||
| 474 | ); |
||
| 475 | |||
| 476 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 477 | ->getMock(); |
||
| 478 | |||
| 479 | $stub->method('get') |
||
| 480 | ->willReturn('barfoo'); |
||
| 481 | |||
| 482 | $stub->method('getKey') |
||
| 483 | ->willReturn('foobar'); |
||
| 484 | |||
| 485 | $this->assertTrue( |
||
| 486 | $cacheInstance->save($stub), |
||
| 487 | __LINE__ |
||
| 488 | ); |
||
| 489 | |||
| 490 | $this->assertTrue( |
||
| 491 | $cacheInstance->hasItem('foobar'), |
||
| 492 | __LINE__ |
||
| 493 | ); |
||
| 494 | } |
||
| 495 | |||
| 496 | /** |
||
| 497 | * Tests for the correct Psr\Cache return values. |
||
| 498 | * |
||
| 499 | * @return void |
||
| 500 | * |
||
| 501 | * @coversNothing |
||
| 502 | * @since 1.0 |
||
| 503 | */ |
||
| 504 | public function testPsrCache() |
||
| 505 | { |
||
| 506 | $cacheInstance = $this->instance; |
||
| 507 | $cacheClass = get_class($cacheInstance); |
||
| 508 | $interfaces = class_implements($cacheClass); |
||
| 509 | $psrInterface = 'Psr\\Cache\\CacheItemPoolInterface'; |
||
| 510 | $targetClass = $this->cacheClass; |
||
| 511 | $this->assertArrayHasKey($psrInterface, $interfaces, __LINE__); |
||
| 512 | $cacheClass = get_class($cacheInstance); |
||
| 513 | $this->assertEquals($cacheClass, $targetClass, __LINE__); |
||
| 514 | |||
| 515 | // Create a stub for the CacheItemInterface class. |
||
| 516 | $stub = $this->getMockBuilder('\\Psr\\Cache\\CacheItemInterface') |
||
| 517 | ->getMock(); |
||
| 518 | |||
| 519 | $stub->method('get') |
||
| 520 | ->willReturn('bar'); |
||
| 521 | |||
| 522 | $stub->method('getKey') |
||
| 523 | ->willReturn('foo'); |
||
| 524 | |||
| 525 | $this->assertInternalType('boolean', $cacheInstance->clear(), 'Checking clear.'); |
||
| 526 | $this->assertInternalType('boolean', $cacheInstance->save($stub), 'Checking set.'); |
||
| 527 | $this->assertInternalType('string', $cacheInstance->getItem('foo')->get(), 'Checking get.'); |
||
| 528 | $this->assertInternalType('boolean', $cacheInstance->deleteItem('foo'), 'Checking remove.'); |
||
| 529 | $this->assertInternalType('array', $cacheInstance->getItems(array('foo')), 'Checking getMultiple.'); |
||
| 530 | $this->assertInternalType('array', $cacheInstance->deleteItems(array('foo')), 'Checking removeMultiple.'); |
||
| 531 | } |
||
| 532 | |||
| 533 | /** |
||
| 534 | * Setup the tests. |
||
| 535 | * |
||
| 536 | * @return void |
||
| 537 | * |
||
| 538 | * @since 1.0 |
||
| 539 | */ |
||
| 540 | protected function setUp() |
||
| 541 | { |
||
| 542 | $options = $this->cacheOptions; |
||
| 543 | $className = $this->cacheClass; |
||
| 544 | |||
| 545 | try |
||
| 546 | { |
||
| 547 | $cacheInstance = new $className($options); |
||
| 548 | } |
||
| 549 | catch (\RuntimeException $e) |
||
| 550 | { |
||
| 551 | $this->markTestSkipped(); |
||
| 552 | } |
||
| 553 | |||
| 554 | $this->instance =& $cacheInstance; |
||
| 555 | |||
| 556 | parent::setUp(); |
||
| 557 | } |
||
| 558 | } |
||
| 559 |