diff options
-rw-r--r-- | application/History.php | 16 | ||||
-rw-r--r-- | application/NetscapeBookmarkUtils.php | 16 | ||||
-rw-r--r-- | tests/NetscapeBookmarkUtils/BookmarkImportTest.php | 81 |
3 files changed, 65 insertions, 48 deletions
diff --git a/application/History.php b/application/History.php index 116b9264..5e3b1b72 100644 --- a/application/History.php +++ b/application/History.php | |||
@@ -16,6 +16,7 @@ | |||
16 | * - UPDATED: link updated | 16 | * - UPDATED: link updated |
17 | * - DELETED: link deleted | 17 | * - DELETED: link deleted |
18 | * - SETTINGS: the settings have been updated through the UI. | 18 | * - SETTINGS: the settings have been updated through the UI. |
19 | * - IMPORT: bulk links import | ||
19 | * | 20 | * |
20 | * Note: new events are put at the beginning of the file and history array. | 21 | * Note: new events are put at the beginning of the file and history array. |
21 | */ | 22 | */ |
@@ -42,6 +43,11 @@ class History | |||
42 | const SETTINGS = 'SETTINGS'; | 43 | const SETTINGS = 'SETTINGS'; |
43 | 44 | ||
44 | /** | 45 | /** |
46 | * @var string Action key: a bulk import has been processed. | ||
47 | */ | ||
48 | const IMPORT = 'IMPORT'; | ||
49 | |||
50 | /** | ||
45 | * @var string History file path. | 51 | * @var string History file path. |
46 | */ | 52 | */ |
47 | protected $historyFilePath; | 53 | protected $historyFilePath; |
@@ -122,6 +128,16 @@ class History | |||
122 | } | 128 | } |
123 | 129 | ||
124 | /** | 130 | /** |
131 | * Add Event: bulk import. | ||
132 | * | ||
133 | * Note: we don't store links add/update one by one since it can have a huge impact on performances. | ||
134 | */ | ||
135 | public function importLinks() | ||
136 | { | ||
137 | $this->addEvent(self::IMPORT); | ||
138 | } | ||
139 | |||
140 | /** | ||
125 | * Save a new event and write it in the history file. | 141 | * Save a new event and write it in the history file. |
126 | * | 142 | * |
127 | * @param string $status Event key, should be defined as constant. | 143 | * @param string $status Event key, should be defined as constant. |
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index 2a10ff22..31796367 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php | |||
@@ -66,6 +66,7 @@ class NetscapeBookmarkUtils | |||
66 | * @param int $importCount how many links were imported | 66 | * @param int $importCount how many links were imported |
67 | * @param int $overwriteCount how many links were overwritten | 67 | * @param int $overwriteCount how many links were overwritten |
68 | * @param int $skipCount how many links were skipped | 68 | * @param int $skipCount how many links were skipped |
69 | * @param int $duration how many seconds did the import take | ||
69 | * | 70 | * |
70 | * @return string Summary of the bookmark import status | 71 | * @return string Summary of the bookmark import status |
71 | */ | 72 | */ |
@@ -74,14 +75,16 @@ class NetscapeBookmarkUtils | |||
74 | $filesize, | 75 | $filesize, |
75 | $importCount=0, | 76 | $importCount=0, |
76 | $overwriteCount=0, | 77 | $overwriteCount=0, |
77 | $skipCount=0 | 78 | $skipCount=0, |
79 | $duration=0 | ||
78 | ) | 80 | ) |
79 | { | 81 | { |
80 | $status = 'File '.$filename.' ('.$filesize.' bytes) '; | 82 | $status = 'File '.$filename.' ('.$filesize.' bytes) '; |
81 | if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { | 83 | if ($importCount == 0 && $overwriteCount == 0 && $skipCount == 0) { |
82 | $status .= 'has an unknown file format. Nothing was imported.'; | 84 | $status .= 'has an unknown file format. Nothing was imported.'; |
83 | } else { | 85 | } else { |
84 | $status .= 'was successfully processed: '.$importCount.' links imported, '; | 86 | $status .= 'was successfully processed in '. $duration .' seconds: '; |
87 | $status .= $importCount.' links imported, '; | ||
85 | $status .= $overwriteCount.' links overwritten, '; | 88 | $status .= $overwriteCount.' links overwritten, '; |
86 | $status .= $skipCount.' links skipped.'; | 89 | $status .= $skipCount.' links skipped.'; |
87 | } | 90 | } |
@@ -101,6 +104,7 @@ class NetscapeBookmarkUtils | |||
101 | */ | 104 | */ |
102 | public static function import($post, $files, $linkDb, $conf, $history) | 105 | public static function import($post, $files, $linkDb, $conf, $history) |
103 | { | 106 | { |
107 | $start = time(); | ||
104 | $filename = $files['filetoupload']['name']; | 108 | $filename = $files['filetoupload']['name']; |
105 | $filesize = $files['filetoupload']['size']; | 109 | $filesize = $files['filetoupload']['size']; |
106 | $data = file_get_contents($files['filetoupload']['tmp_name']); | 110 | $data = file_get_contents($files['filetoupload']['tmp_name']); |
@@ -184,7 +188,6 @@ class NetscapeBookmarkUtils | |||
184 | $linkDb[$existingLink['id']] = $newLink; | 188 | $linkDb[$existingLink['id']] = $newLink; |
185 | $importCount++; | 189 | $importCount++; |
186 | $overwriteCount++; | 190 | $overwriteCount++; |
187 | $history->updateLink($newLink); | ||
188 | continue; | 191 | continue; |
189 | } | 192 | } |
190 | 193 | ||
@@ -196,16 +199,19 @@ class NetscapeBookmarkUtils | |||
196 | $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); | 199 | $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); |
197 | $linkDb[$newLink['id']] = $newLink; | 200 | $linkDb[$newLink['id']] = $newLink; |
198 | $importCount++; | 201 | $importCount++; |
199 | $history->addLink($newLink); | ||
200 | } | 202 | } |
201 | 203 | ||
202 | $linkDb->save($conf->get('resource.page_cache')); | 204 | $linkDb->save($conf->get('resource.page_cache')); |
205 | $history->importLinks(); | ||
206 | |||
207 | $duration = time() - $start; | ||
203 | return self::importStatus( | 208 | return self::importStatus( |
204 | $filename, | 209 | $filename, |
205 | $filesize, | 210 | $filesize, |
206 | $importCount, | 211 | $importCount, |
207 | $overwriteCount, | 212 | $overwriteCount, |
208 | $skipCount | 213 | $skipCount, |
214 | $duration | ||
209 | ); | 215 | ); |
210 | } | 216 | } |
211 | } | 217 | } |
diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php index 5fc1d1e8..4961aa2c 100644 --- a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php +++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php | |||
@@ -132,8 +132,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
132 | public function testImportInternetExplorerEncoding() | 132 | public function testImportInternetExplorerEncoding() |
133 | { | 133 | { |
134 | $files = file2array('internet_explorer_encoding.htm'); | 134 | $files = file2array('internet_explorer_encoding.htm'); |
135 | $this->assertEquals( | 135 | $this->assertStringMatchesFormat( |
136 | 'File internet_explorer_encoding.htm (356 bytes) was successfully processed:' | 136 | 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:' |
137 | .' 1 links imported, 0 links overwritten, 0 links skipped.', | 137 | .' 1 links imported, 0 links overwritten, 0 links skipped.', |
138 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) | 138 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) |
139 | ); | 139 | ); |
@@ -161,8 +161,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
161 | public function testImportNested() | 161 | public function testImportNested() |
162 | { | 162 | { |
163 | $files = file2array('netscape_nested.htm'); | 163 | $files = file2array('netscape_nested.htm'); |
164 | $this->assertEquals( | 164 | $this->assertStringMatchesFormat( |
165 | 'File netscape_nested.htm (1337 bytes) was successfully processed:' | 165 | 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:' |
166 | .' 8 links imported, 0 links overwritten, 0 links skipped.', | 166 | .' 8 links imported, 0 links overwritten, 0 links skipped.', |
167 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) | 167 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) |
168 | ); | 168 | ); |
@@ -283,8 +283,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
283 | public function testImportDefaultPrivacyNoPost() | 283 | public function testImportDefaultPrivacyNoPost() |
284 | { | 284 | { |
285 | $files = file2array('netscape_basic.htm'); | 285 | $files = file2array('netscape_basic.htm'); |
286 | $this->assertEquals( | 286 | $this->assertStringMatchesFormat( |
287 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 287 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
288 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 288 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
289 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) | 289 | NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history) |
290 | ); | 290 | ); |
@@ -328,8 +328,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
328 | { | 328 | { |
329 | $post = array('privacy' => 'default'); | 329 | $post = array('privacy' => 'default'); |
330 | $files = file2array('netscape_basic.htm'); | 330 | $files = file2array('netscape_basic.htm'); |
331 | $this->assertEquals( | 331 | $this->assertStringMatchesFormat( |
332 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 332 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
333 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 333 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
334 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 334 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
335 | ); | 335 | ); |
@@ -372,8 +372,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
372 | { | 372 | { |
373 | $post = array('privacy' => 'public'); | 373 | $post = array('privacy' => 'public'); |
374 | $files = file2array('netscape_basic.htm'); | 374 | $files = file2array('netscape_basic.htm'); |
375 | $this->assertEquals( | 375 | $this->assertStringMatchesFormat( |
376 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 376 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
377 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 377 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
378 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 378 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
379 | ); | 379 | ); |
@@ -396,8 +396,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
396 | { | 396 | { |
397 | $post = array('privacy' => 'private'); | 397 | $post = array('privacy' => 'private'); |
398 | $files = file2array('netscape_basic.htm'); | 398 | $files = file2array('netscape_basic.htm'); |
399 | $this->assertEquals( | 399 | $this->assertStringMatchesFormat( |
400 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 400 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
401 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 401 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
402 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 402 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
403 | ); | 403 | ); |
@@ -422,8 +422,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
422 | 422 | ||
423 | // import links as private | 423 | // import links as private |
424 | $post = array('privacy' => 'private'); | 424 | $post = array('privacy' => 'private'); |
425 | $this->assertEquals( | 425 | $this->assertStringMatchesFormat( |
426 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 426 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
427 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 427 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
428 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 428 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
429 | ); | 429 | ); |
@@ -442,8 +442,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
442 | 'privacy' => 'public', | 442 | 'privacy' => 'public', |
443 | 'overwrite' => 'true' | 443 | 'overwrite' => 'true' |
444 | ); | 444 | ); |
445 | $this->assertEquals( | 445 | $this->assertStringMatchesFormat( |
446 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 446 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
447 | .' 2 links imported, 2 links overwritten, 0 links skipped.', | 447 | .' 2 links imported, 2 links overwritten, 0 links skipped.', |
448 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 448 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
449 | ); | 449 | ); |
@@ -468,8 +468,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
468 | 468 | ||
469 | // import links as public | 469 | // import links as public |
470 | $post = array('privacy' => 'public'); | 470 | $post = array('privacy' => 'public'); |
471 | $this->assertEquals( | 471 | $this->assertStringMatchesFormat( |
472 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 472 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
473 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 473 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
474 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 474 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
475 | ); | 475 | ); |
@@ -489,8 +489,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
489 | 'privacy' => 'private', | 489 | 'privacy' => 'private', |
490 | 'overwrite' => 'true' | 490 | 'overwrite' => 'true' |
491 | ); | 491 | ); |
492 | $this->assertEquals( | 492 | $this->assertStringMatchesFormat( |
493 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 493 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
494 | .' 2 links imported, 2 links overwritten, 0 links skipped.', | 494 | .' 2 links imported, 2 links overwritten, 0 links skipped.', |
495 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 495 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
496 | ); | 496 | ); |
@@ -513,8 +513,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
513 | { | 513 | { |
514 | $post = array('privacy' => 'public'); | 514 | $post = array('privacy' => 'public'); |
515 | $files = file2array('netscape_basic.htm'); | 515 | $files = file2array('netscape_basic.htm'); |
516 | $this->assertEquals( | 516 | $this->assertStringMatchesFormat( |
517 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 517 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
518 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 518 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
519 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 519 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
520 | ); | 520 | ); |
@@ -523,8 +523,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
523 | 523 | ||
524 | // re-import as private, DO NOT enable overwriting | 524 | // re-import as private, DO NOT enable overwriting |
525 | $post = array('privacy' => 'private'); | 525 | $post = array('privacy' => 'private'); |
526 | $this->assertEquals( | 526 | $this->assertStringMatchesFormat( |
527 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 527 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
528 | .' 0 links imported, 0 links overwritten, 2 links skipped.', | 528 | .' 0 links imported, 0 links overwritten, 2 links skipped.', |
529 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 529 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
530 | ); | 530 | ); |
@@ -542,8 +542,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
542 | 'default_tags' => 'tag1,tag2 tag3' | 542 | 'default_tags' => 'tag1,tag2 tag3' |
543 | ); | 543 | ); |
544 | $files = file2array('netscape_basic.htm'); | 544 | $files = file2array('netscape_basic.htm'); |
545 | $this->assertEquals( | 545 | $this->assertStringMatchesFormat( |
546 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 546 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
547 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 547 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
548 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 548 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
549 | ); | 549 | ); |
@@ -569,8 +569,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
569 | 'default_tags' => 'tag1&,tag2 "tag3"' | 569 | 'default_tags' => 'tag1&,tag2 "tag3"' |
570 | ); | 570 | ); |
571 | $files = file2array('netscape_basic.htm'); | 571 | $files = file2array('netscape_basic.htm'); |
572 | $this->assertEquals( | 572 | $this->assertStringMatchesFormat( |
573 | 'File netscape_basic.htm (482 bytes) was successfully processed:' | 573 | 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:' |
574 | .' 2 links imported, 0 links overwritten, 0 links skipped.', | 574 | .' 2 links imported, 0 links overwritten, 0 links skipped.', |
575 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) | 575 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history) |
576 | ); | 576 | ); |
@@ -594,8 +594,8 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
594 | public function testImportSameDate() | 594 | public function testImportSameDate() |
595 | { | 595 | { |
596 | $files = file2array('same_date.htm'); | 596 | $files = file2array('same_date.htm'); |
597 | $this->assertEquals( | 597 | $this->assertStringMatchesFormat( |
598 | 'File same_date.htm (453 bytes) was successfully processed:' | 598 | 'File same_date.htm (453 bytes) was successfully processed in %d seconds:' |
599 | .' 3 links imported, 0 links overwritten, 0 links skipped.', | 599 | .' 3 links imported, 0 links overwritten, 0 links skipped.', |
600 | NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->conf, $this->history) | 600 | NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->conf, $this->history) |
601 | ); | 601 | ); |
@@ -622,24 +622,19 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase | |||
622 | 'overwrite' => 'true', | 622 | 'overwrite' => 'true', |
623 | ]; | 623 | ]; |
624 | $files = file2array('netscape_basic.htm'); | 624 | $files = file2array('netscape_basic.htm'); |
625 | $nbLinks = 2; | ||
626 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); | 625 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); |
627 | $history = $this->history->getHistory(); | 626 | $history = $this->history->getHistory(); |
628 | $this->assertEquals($nbLinks, count($history)); | 627 | $this->assertEquals(1, count($history)); |
629 | foreach ($history as $value) { | 628 | $this->assertEquals(History::IMPORT, $history[0]['event']); |
630 | $this->assertEquals(History::CREATED, $value['event']); | 629 | $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']); |
631 | $this->assertTrue(new DateTime('-5 seconds') < $value['datetime']); | ||
632 | $this->assertTrue(is_int($value['id'])); | ||
633 | } | ||
634 | 630 | ||
635 | // re-import as private, enable overwriting | 631 | // re-import as private, enable overwriting |
636 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); | 632 | NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history); |
637 | $history = $this->history->getHistory(); | 633 | $history = $this->history->getHistory(); |
638 | $this->assertEquals($nbLinks * 2, count($history)); | 634 | $this->assertEquals(2, count($history)); |
639 | for ($i = 0 ; $i < $nbLinks ; $i++) { | 635 | $this->assertEquals(History::IMPORT, $history[0]['event']); |
640 | $this->assertEquals(History::UPDATED, $history[$i]['event']); | 636 | $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']); |
641 | $this->assertTrue(new DateTime('-5 seconds') < $history[$i]['datetime']); | 637 | $this->assertEquals(History::IMPORT, $history[1]['event']); |
642 | $this->assertTrue(is_int($history[$i]['id'])); | 638 | $this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']); |
643 | } | ||
644 | } | 639 | } |
645 | } | 640 | } |