1 /* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 import static com.google.common.truth.Truth.assertThat; 21 import static java.util.Arrays.asList; 22 23 import com.google.common.annotations.GwtCompatible; 24 import com.google.common.annotations.GwtIncompatible; 25 import com.google.common.collect.testing.ListTestSuiteBuilder; 26 import com.google.common.collect.testing.MinimalCollection; 27 import com.google.common.collect.testing.SetTestSuiteBuilder; 28 import com.google.common.collect.testing.TestStringListGenerator; 29 import com.google.common.collect.testing.TestStringSetGenerator; 30 import com.google.common.collect.testing.features.CollectionFeature; 31 import com.google.common.collect.testing.features.CollectionSize; 32 import com.google.common.collect.testing.google.MultisetTestSuiteBuilder; 33 import com.google.common.collect.testing.google.TestStringMultisetGenerator; 34 import com.google.common.collect.testing.google.UnmodifiableCollectionTests; 35 import com.google.common.testing.EqualsTester; 36 import com.google.common.testing.NullPointerTester; 37 import com.google.common.testing.SerializableTester; 38 import java.util.ArrayList; 39 import java.util.Collection; 40 import java.util.HashSet; 41 import java.util.Iterator; 42 import java.util.List; 43 import java.util.Set; 44 import junit.framework.Test; 45 import junit.framework.TestCase; 46 import junit.framework.TestSuite; 47 48 /** 49 * Tests for {@link ImmutableMultiset}. 50 * 51 * @author Jared Levy 52 */ 53 @GwtCompatible(emulated = true) 54 public class ImmutableMultisetTest extends TestCase { 55 56 @GwtIncompatible // suite // TODO(cpovirk): add to collect/gwt/suites suite()57 public static Test suite() { 58 TestSuite suite = new TestSuite(); 59 suite.addTestSuite(ImmutableMultisetTest.class); 60 61 suite.addTest( 62 MultisetTestSuiteBuilder.using( 63 new TestStringMultisetGenerator() { 64 @Override 65 protected Multiset<String> create(String[] elements) { 66 return ImmutableMultiset.copyOf(elements); 67 } 68 }) 69 .named("ImmutableMultiset") 70 .withFeatures( 71 CollectionSize.ANY, 72 CollectionFeature.SERIALIZABLE_INCLUDING_VIEWS, 73 CollectionFeature.ALLOWS_NULL_QUERIES) 74 .createTestSuite()); 75 76 suite.addTest( 77 SetTestSuiteBuilder.using( 78 new TestStringSetGenerator() { 79 @Override 80 protected Set<String> create(String[] elements) { 81 return ImmutableMultiset.copyOf(elements).elementSet(); 82 } 83 }) 84 .named("ImmutableMultiset, element set") 85 .withFeatures( 86 CollectionSize.ANY, 87 CollectionFeature.SERIALIZABLE, 88 CollectionFeature.ALLOWS_NULL_QUERIES) 89 .createTestSuite()); 90 91 suite.addTest( 92 ListTestSuiteBuilder.using( 93 new TestStringListGenerator() { 94 @Override 95 protected List<String> create(String[] elements) { 96 return ImmutableMultiset.copyOf(elements).asList(); 97 } 98 99 @Override 100 public List<String> order(List<String> insertionOrder) { 101 List<String> order = new ArrayList<>(); 102 for (String s : insertionOrder) { 103 int index = order.indexOf(s); 104 if (index == -1) { 105 order.add(s); 106 } else { 107 order.add(index, s); 108 } 109 } 110 return order; 111 } 112 }) 113 .named("ImmutableMultiset.asList") 114 .withFeatures( 115 CollectionSize.ANY, 116 CollectionFeature.SERIALIZABLE, 117 CollectionFeature.ALLOWS_NULL_QUERIES) 118 .createTestSuite()); 119 120 suite.addTest( 121 ListTestSuiteBuilder.using( 122 new TestStringListGenerator() { 123 @Override 124 protected List<String> create(String[] elements) { 125 Set<String> set = new HashSet<>(); 126 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 127 for (String s : elements) { 128 checkArgument(set.add(s)); 129 builder.addCopies(s, 2); 130 } 131 ImmutableSet<String> elementSet = 132 (ImmutableSet<String>) builder.build().elementSet(); 133 return elementSet.asList(); 134 } 135 }) 136 .named("ImmutableMultiset.elementSet.asList") 137 .withFeatures( 138 CollectionSize.ANY, 139 CollectionFeature.REJECTS_DUPLICATES_AT_CREATION, 140 CollectionFeature.SERIALIZABLE, 141 CollectionFeature.ALLOWS_NULL_QUERIES) 142 .createTestSuite()); 143 144 return suite; 145 } 146 testCreation_noArgs()147 public void testCreation_noArgs() { 148 Multiset<String> multiset = ImmutableMultiset.of(); 149 assertTrue(multiset.isEmpty()); 150 } 151 testCreation_oneElement()152 public void testCreation_oneElement() { 153 Multiset<String> multiset = ImmutableMultiset.of("a"); 154 assertEquals(HashMultiset.create(asList("a")), multiset); 155 } 156 testCreation_twoElements()157 public void testCreation_twoElements() { 158 Multiset<String> multiset = ImmutableMultiset.of("a", "b"); 159 assertEquals(HashMultiset.create(asList("a", "b")), multiset); 160 } 161 testCreation_threeElements()162 public void testCreation_threeElements() { 163 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "c"); 164 assertEquals(HashMultiset.create(asList("a", "b", "c")), multiset); 165 } 166 testCreation_fourElements()167 public void testCreation_fourElements() { 168 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "c", "d"); 169 assertEquals(HashMultiset.create(asList("a", "b", "c", "d")), multiset); 170 } 171 testCreation_fiveElements()172 public void testCreation_fiveElements() { 173 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "c", "d", "e"); 174 assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e")), multiset); 175 } 176 testCreation_sixElements()177 public void testCreation_sixElements() { 178 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "c", "d", "e", "f"); 179 assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e", "f")), multiset); 180 } 181 testCreation_sevenElements()182 public void testCreation_sevenElements() { 183 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "c", "d", "e", "f", "g"); 184 assertEquals(HashMultiset.create(asList("a", "b", "c", "d", "e", "f", "g")), multiset); 185 } 186 testCreation_emptyArray()187 public void testCreation_emptyArray() { 188 String[] array = new String[0]; 189 Multiset<String> multiset = ImmutableMultiset.copyOf(array); 190 assertTrue(multiset.isEmpty()); 191 } 192 testCreation_arrayOfOneElement()193 public void testCreation_arrayOfOneElement() { 194 String[] array = new String[] {"a"}; 195 Multiset<String> multiset = ImmutableMultiset.copyOf(array); 196 assertEquals(HashMultiset.create(asList("a")), multiset); 197 } 198 testCreation_arrayOfArray()199 public void testCreation_arrayOfArray() { 200 String[] array = new String[] {"a"}; 201 Multiset<String[]> multiset = ImmutableMultiset.<String[]>of(array); 202 Multiset<String[]> expected = HashMultiset.create(); 203 expected.add(array); 204 assertEquals(expected, multiset); 205 } 206 testCreation_arrayContainingOnlyNull()207 public void testCreation_arrayContainingOnlyNull() { 208 String[] array = new String[] {null}; 209 try { 210 ImmutableMultiset.copyOf(array); 211 fail(); 212 } catch (NullPointerException expected) { 213 } 214 } 215 testCopyOf_collection_empty()216 public void testCopyOf_collection_empty() { 217 // "<String>" is required to work around a javac 1.5 bug. 218 Collection<String> c = MinimalCollection.<String>of(); 219 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 220 assertTrue(multiset.isEmpty()); 221 } 222 testCopyOf_collection_oneElement()223 public void testCopyOf_collection_oneElement() { 224 Collection<String> c = MinimalCollection.of("a"); 225 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 226 assertEquals(HashMultiset.create(asList("a")), multiset); 227 } 228 testCopyOf_collection_general()229 public void testCopyOf_collection_general() { 230 Collection<String> c = MinimalCollection.of("a", "b", "a"); 231 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 232 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 233 } 234 testCopyOf_collectionContainingNull()235 public void testCopyOf_collectionContainingNull() { 236 Collection<String> c = MinimalCollection.of("a", null, "b"); 237 try { 238 ImmutableMultiset.copyOf(c); 239 fail(); 240 } catch (NullPointerException expected) { 241 } 242 } 243 testCopyOf_multiset_empty()244 public void testCopyOf_multiset_empty() { 245 Multiset<String> c = HashMultiset.create(); 246 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 247 assertTrue(multiset.isEmpty()); 248 } 249 testCopyOf_multiset_oneElement()250 public void testCopyOf_multiset_oneElement() { 251 Multiset<String> c = HashMultiset.create(asList("a")); 252 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 253 assertEquals(HashMultiset.create(asList("a")), multiset); 254 } 255 testCopyOf_multiset_general()256 public void testCopyOf_multiset_general() { 257 Multiset<String> c = HashMultiset.create(asList("a", "b", "a")); 258 Multiset<String> multiset = ImmutableMultiset.copyOf(c); 259 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 260 } 261 testCopyOf_multisetContainingNull()262 public void testCopyOf_multisetContainingNull() { 263 Multiset<String> c = HashMultiset.create(asList("a", null, "b")); 264 try { 265 ImmutableMultiset.copyOf(c); 266 fail(); 267 } catch (NullPointerException expected) { 268 } 269 } 270 testCopyOf_iterator_empty()271 public void testCopyOf_iterator_empty() { 272 Iterator<String> iterator = Iterators.emptyIterator(); 273 Multiset<String> multiset = ImmutableMultiset.copyOf(iterator); 274 assertTrue(multiset.isEmpty()); 275 } 276 testCopyOf_iterator_oneElement()277 public void testCopyOf_iterator_oneElement() { 278 Iterator<String> iterator = Iterators.singletonIterator("a"); 279 Multiset<String> multiset = ImmutableMultiset.copyOf(iterator); 280 assertEquals(HashMultiset.create(asList("a")), multiset); 281 } 282 testCopyOf_iterator_general()283 public void testCopyOf_iterator_general() { 284 Iterator<String> iterator = asList("a", "b", "a").iterator(); 285 Multiset<String> multiset = ImmutableMultiset.copyOf(iterator); 286 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 287 } 288 testCopyOf_iteratorContainingNull()289 public void testCopyOf_iteratorContainingNull() { 290 Iterator<String> iterator = asList("a", null, "b").iterator(); 291 try { 292 ImmutableMultiset.copyOf(iterator); 293 fail(); 294 } catch (NullPointerException expected) { 295 } 296 } 297 298 private static class CountingIterable implements Iterable<String> { 299 int count = 0; 300 301 @Override iterator()302 public Iterator<String> iterator() { 303 count++; 304 return asList("a", "b", "a").iterator(); 305 } 306 } 307 testCopyOf_plainIterable()308 public void testCopyOf_plainIterable() { 309 CountingIterable iterable = new CountingIterable(); 310 Multiset<String> multiset = ImmutableMultiset.copyOf(iterable); 311 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 312 assertEquals(1, iterable.count); 313 } 314 testCopyOf_hashMultiset()315 public void testCopyOf_hashMultiset() { 316 Multiset<String> iterable = HashMultiset.create(asList("a", "b", "a")); 317 Multiset<String> multiset = ImmutableMultiset.copyOf(iterable); 318 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 319 } 320 testCopyOf_treeMultiset()321 public void testCopyOf_treeMultiset() { 322 Multiset<String> iterable = TreeMultiset.create(asList("a", "b", "a")); 323 Multiset<String> multiset = ImmutableMultiset.copyOf(iterable); 324 assertEquals(HashMultiset.create(asList("a", "b", "a")), multiset); 325 } 326 testCopyOf_shortcut_empty()327 public void testCopyOf_shortcut_empty() { 328 Collection<String> c = ImmutableMultiset.of(); 329 assertSame(c, ImmutableMultiset.copyOf(c)); 330 } 331 testCopyOf_shortcut_singleton()332 public void testCopyOf_shortcut_singleton() { 333 Collection<String> c = ImmutableMultiset.of("a"); 334 assertSame(c, ImmutableMultiset.copyOf(c)); 335 } 336 testCopyOf_shortcut_immutableMultiset()337 public void testCopyOf_shortcut_immutableMultiset() { 338 Collection<String> c = ImmutableMultiset.of("a", "b", "c"); 339 assertSame(c, ImmutableMultiset.copyOf(c)); 340 } 341 testBuilderAdd()342 public void testBuilderAdd() { 343 ImmutableMultiset<String> multiset = 344 new ImmutableMultiset.Builder<String>().add("a").add("b").add("a").add("c").build(); 345 assertEquals(HashMultiset.create(asList("a", "b", "a", "c")), multiset); 346 } 347 testBuilderAddAll()348 public void testBuilderAddAll() { 349 List<String> a = asList("a", "b"); 350 List<String> b = asList("c", "d"); 351 ImmutableMultiset<String> multiset = 352 new ImmutableMultiset.Builder<String>().addAll(a).addAll(b).build(); 353 assertEquals(HashMultiset.create(asList("a", "b", "c", "d")), multiset); 354 } 355 testBuilderAddAllHashMultiset()356 public void testBuilderAddAllHashMultiset() { 357 Multiset<String> a = HashMultiset.create(asList("a", "b", "b")); 358 Multiset<String> b = HashMultiset.create(asList("c", "b")); 359 ImmutableMultiset<String> multiset = 360 new ImmutableMultiset.Builder<String>().addAll(a).addAll(b).build(); 361 assertEquals(HashMultiset.create(asList("a", "b", "b", "b", "c")), multiset); 362 } 363 testBuilderAddAllImmutableMultiset()364 public void testBuilderAddAllImmutableMultiset() { 365 Multiset<String> a = ImmutableMultiset.of("a", "b", "b"); 366 Multiset<String> b = ImmutableMultiset.of("c", "b"); 367 ImmutableMultiset<String> multiset = 368 new ImmutableMultiset.Builder<String>().addAll(a).addAll(b).build(); 369 assertEquals(HashMultiset.create(asList("a", "b", "b", "b", "c")), multiset); 370 } 371 testBuilderAddAllTreeMultiset()372 public void testBuilderAddAllTreeMultiset() { 373 Multiset<String> a = TreeMultiset.create(asList("a", "b", "b")); 374 Multiset<String> b = TreeMultiset.create(asList("c", "b")); 375 ImmutableMultiset<String> multiset = 376 new ImmutableMultiset.Builder<String>().addAll(a).addAll(b).build(); 377 assertEquals(HashMultiset.create(asList("a", "b", "b", "b", "c")), multiset); 378 } 379 testBuilderAddAllIterator()380 public void testBuilderAddAllIterator() { 381 Iterator<String> iterator = asList("a", "b", "a", "c").iterator(); 382 ImmutableMultiset<String> multiset = 383 new ImmutableMultiset.Builder<String>().addAll(iterator).build(); 384 assertEquals(HashMultiset.create(asList("a", "b", "a", "c")), multiset); 385 } 386 testBuilderAddCopies()387 public void testBuilderAddCopies() { 388 ImmutableMultiset<String> multiset = 389 new ImmutableMultiset.Builder<String>() 390 .addCopies("a", 2) 391 .addCopies("b", 3) 392 .addCopies("c", 0) 393 .build(); 394 assertEquals(HashMultiset.create(asList("a", "a", "b", "b", "b")), multiset); 395 } 396 testBuilderSetCount()397 public void testBuilderSetCount() { 398 ImmutableMultiset<String> multiset = 399 new ImmutableMultiset.Builder<String>().add("a").setCount("a", 2).setCount("b", 3).build(); 400 assertEquals(HashMultiset.create(asList("a", "a", "b", "b", "b")), multiset); 401 } 402 testBuilderAddHandlesNullsCorrectly()403 public void testBuilderAddHandlesNullsCorrectly() { 404 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 405 try { 406 builder.add((String) null); 407 fail("expected NullPointerException"); 408 } catch (NullPointerException expected) { 409 } 410 } 411 testBuilderAddAllHandlesNullsCorrectly()412 public void testBuilderAddAllHandlesNullsCorrectly() { 413 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 414 try { 415 builder.addAll((Collection<String>) null); 416 fail("expected NullPointerException"); 417 } catch (NullPointerException expected) { 418 } 419 420 builder = ImmutableMultiset.builder(); 421 List<String> listWithNulls = asList("a", null, "b"); 422 try { 423 builder.addAll(listWithNulls); 424 fail("expected NullPointerException"); 425 } catch (NullPointerException expected) { 426 } 427 428 builder = ImmutableMultiset.builder(); 429 Multiset<String> multisetWithNull = LinkedHashMultiset.create(asList("a", null, "b")); 430 try { 431 builder.addAll(multisetWithNull); 432 fail("expected NullPointerException"); 433 } catch (NullPointerException expected) { 434 } 435 } 436 testBuilderAddCopiesHandlesNullsCorrectly()437 public void testBuilderAddCopiesHandlesNullsCorrectly() { 438 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 439 try { 440 builder.addCopies(null, 2); 441 fail("expected NullPointerException"); 442 } catch (NullPointerException expected) { 443 } 444 } 445 testBuilderAddCopiesIllegal()446 public void testBuilderAddCopiesIllegal() { 447 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 448 try { 449 builder.addCopies("a", -2); 450 fail("expected IllegalArgumentException"); 451 } catch (IllegalArgumentException expected) { 452 } 453 } 454 testBuilderSetCountHandlesNullsCorrectly()455 public void testBuilderSetCountHandlesNullsCorrectly() { 456 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 457 try { 458 builder.setCount(null, 2); 459 fail("expected NullPointerException"); 460 } catch (NullPointerException expected) { 461 } 462 } 463 testBuilderSetCountIllegal()464 public void testBuilderSetCountIllegal() { 465 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 466 try { 467 builder.setCount("a", -2); 468 fail("expected IllegalArgumentException"); 469 } catch (IllegalArgumentException expected) { 470 } 471 } 472 473 @GwtIncompatible // NullPointerTester testNullPointers()474 public void testNullPointers() { 475 NullPointerTester tester = new NullPointerTester(); 476 tester.testAllPublicStaticMethods(ImmutableMultiset.class); 477 } 478 479 @GwtIncompatible // SerializableTester testSerialization_empty()480 public void testSerialization_empty() { 481 Collection<String> c = ImmutableMultiset.of(); 482 assertSame(c, SerializableTester.reserialize(c)); 483 } 484 485 @GwtIncompatible // SerializableTester testSerialization_multiple()486 public void testSerialization_multiple() { 487 Collection<String> c = ImmutableMultiset.of("a", "b", "a"); 488 Collection<String> copy = SerializableTester.reserializeAndAssert(c); 489 assertThat(copy).containsExactly("a", "a", "b").inOrder(); 490 } 491 492 @GwtIncompatible // SerializableTester testSerialization_elementSet()493 public void testSerialization_elementSet() { 494 Multiset<String> c = ImmutableMultiset.of("a", "b", "a"); 495 Collection<String> copy = LenientSerializableTester.reserializeAndAssertLenient(c.elementSet()); 496 assertThat(copy).containsExactly("a", "b").inOrder(); 497 } 498 499 @GwtIncompatible // SerializableTester testSerialization_entrySet()500 public void testSerialization_entrySet() { 501 Multiset<String> c = ImmutableMultiset.of("a", "b", "c"); 502 SerializableTester.reserializeAndAssert(c.entrySet()); 503 } 504 testEquals_immutableMultiset()505 public void testEquals_immutableMultiset() { 506 Collection<String> c = ImmutableMultiset.of("a", "b", "a"); 507 assertEquals(c, ImmutableMultiset.of("a", "b", "a")); 508 assertEquals(c, ImmutableMultiset.of("a", "a", "b")); 509 assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b")); 510 assertThat(c).isNotEqualTo(ImmutableMultiset.of("a", "b", "c", "d")); 511 } 512 testIterationOrder()513 public void testIterationOrder() { 514 Collection<String> c = ImmutableMultiset.of("a", "b", "a"); 515 assertThat(c).containsExactly("a", "a", "b").inOrder(); 516 assertThat(ImmutableMultiset.of("c", "b", "a", "c").elementSet()) 517 .containsExactly("c", "b", "a") 518 .inOrder(); 519 } 520 testMultisetWrites()521 public void testMultisetWrites() { 522 Multiset<String> multiset = ImmutableMultiset.of("a", "b", "a"); 523 UnmodifiableCollectionTests.assertMultisetIsUnmodifiable(multiset, "test"); 524 } 525 testAsList()526 public void testAsList() { 527 ImmutableMultiset<String> multiset = ImmutableMultiset.of("a", "a", "b", "b", "b"); 528 ImmutableList<String> list = multiset.asList(); 529 assertEquals(ImmutableList.of("a", "a", "b", "b", "b"), list); 530 assertEquals(2, list.indexOf("b")); 531 assertEquals(4, list.lastIndexOf("b")); 532 } 533 534 @GwtIncompatible // SerializableTester testSerialization_asList()535 public void testSerialization_asList() { 536 ImmutableMultiset<String> multiset = ImmutableMultiset.of("a", "a", "b", "b", "b"); 537 SerializableTester.reserializeAndAssert(multiset.asList()); 538 } 539 testEquals()540 public void testEquals() { 541 new EqualsTester() 542 .addEqualityGroup(ImmutableMultiset.of(), ImmutableMultiset.of()) 543 .addEqualityGroup(ImmutableMultiset.of(1), ImmutableMultiset.of(1)) 544 .addEqualityGroup(ImmutableMultiset.of(1, 1), ImmutableMultiset.of(1, 1)) 545 .addEqualityGroup(ImmutableMultiset.of(1, 2, 1), ImmutableMultiset.of(2, 1, 1)) 546 .testEquals(); 547 } 548 testIterationOrderThroughBuilderRemovals()549 public void testIterationOrderThroughBuilderRemovals() { 550 ImmutableMultiset.Builder<String> builder = ImmutableMultiset.builder(); 551 builder.addCopies("a", 2); 552 builder.add("b"); 553 builder.add("c"); 554 builder.setCount("b", 0); 555 ImmutableMultiset<String> multiset = builder.build(); 556 assertThat(multiset.elementSet()).containsExactly("a", "c").inOrder(); 557 builder.add("b"); 558 assertThat(builder.build().elementSet()).containsExactly("a", "c", "b").inOrder(); 559 assertThat(multiset.elementSet()).containsExactly("a", "c").inOrder(); 560 } 561 } 562