blob: 34bb1f4e2e050ecf68be48f48cdc12f8946827d6 [file] [log] [blame]
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -07001/**
2 *
3 */
tomea961ff2014-10-01 12:45:15 -07004package org.onlab.onos.store.trivial.impl;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -07005
6import static org.junit.Assert.*;
7import static org.onlab.onos.net.Device.Type.SWITCH;
8import static org.onlab.onos.net.DeviceId.deviceId;
9import static org.onlab.onos.net.device.DeviceEvent.Type.*;
10
11import java.util.Arrays;
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.concurrent.CountDownLatch;
17import java.util.concurrent.TimeUnit;
18
19import org.junit.After;
20import org.junit.AfterClass;
21import org.junit.Before;
22import org.junit.BeforeClass;
23import org.junit.Ignore;
24import org.junit.Test;
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070025import org.onlab.onos.net.Annotations;
26import org.onlab.onos.net.DefaultAnnotations;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070027import org.onlab.onos.net.Device;
28import org.onlab.onos.net.DeviceId;
29import org.onlab.onos.net.Port;
30import org.onlab.onos.net.PortNumber;
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070031import org.onlab.onos.net.SparseAnnotations;
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070032import org.onlab.onos.net.device.DefaultDeviceDescription;
33import org.onlab.onos.net.device.DefaultPortDescription;
34import org.onlab.onos.net.device.DeviceDescription;
35import org.onlab.onos.net.device.DeviceEvent;
36import org.onlab.onos.net.device.DeviceStore;
37import org.onlab.onos.net.device.DeviceStoreDelegate;
38import org.onlab.onos.net.device.PortDescription;
39import org.onlab.onos.net.provider.ProviderId;
40
41import com.google.common.collect.Iterables;
42import com.google.common.collect.Sets;
43
44/**
45 * Test of the simple DeviceStore implementation.
46 */
47public class SimpleDeviceStoreTest {
48
49 private static final ProviderId PID = new ProviderId("of", "foo");
Yuta HIGUCHI8e493792014-10-01 19:36:32 -070050 private static final ProviderId PIDA = new ProviderId("of", "bar", true);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070051 private static final DeviceId DID1 = deviceId("of:foo");
52 private static final DeviceId DID2 = deviceId("of:bar");
53 private static final String MFR = "whitebox";
54 private static final String HW = "1.1.x";
55 private static final String SW1 = "3.8.1";
56 private static final String SW2 = "3.9.5";
57 private static final String SN = "43311-12345";
58
59 private static final PortNumber P1 = PortNumber.portNumber(1);
60 private static final PortNumber P2 = PortNumber.portNumber(2);
61 private static final PortNumber P3 = PortNumber.portNumber(3);
62
Yuta HIGUCHI55710e72014-10-02 14:58:32 -070063 private static final SparseAnnotations A1 = DefaultAnnotations.builder()
64 .set("A1", "a1")
65 .set("B1", "b1")
66 .build();
67 private static final SparseAnnotations A1_2 = DefaultAnnotations.builder()
68 .remove("A1")
69 .set("B3", "b3")
70 .build();
71 private static final SparseAnnotations A2 = DefaultAnnotations.builder()
72 .set("A2", "a2")
73 .set("B2", "b2")
74 .build();
75 private static final SparseAnnotations A2_2 = DefaultAnnotations.builder()
76 .remove("A2")
77 .set("B4", "b4")
78 .build();
79
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -070080 private SimpleDeviceStore simpleDeviceStore;
81 private DeviceStore deviceStore;
82
83
84
85 @BeforeClass
86 public static void setUpBeforeClass() throws Exception {
87 }
88
89 @AfterClass
90 public static void tearDownAfterClass() throws Exception {
91 }
92
93
94 @Before
95 public void setUp() throws Exception {
96 simpleDeviceStore = new SimpleDeviceStore();
97 simpleDeviceStore.activate();
98 deviceStore = simpleDeviceStore;
99 }
100
101 @After
102 public void tearDown() throws Exception {
103 simpleDeviceStore.deactivate();
104 }
105
106 private void putDevice(DeviceId deviceId, String swVersion) {
107 DeviceDescription description =
108 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
109 HW, swVersion, SN);
110 deviceStore.createOrUpdateDevice(PID, deviceId, description);
111 }
112
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700113 private void putDeviceAncillary(DeviceId deviceId, String swVersion) {
114 DeviceDescription description =
115 new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR,
116 HW, swVersion, SN);
117 deviceStore.createOrUpdateDevice(PIDA, deviceId, description);
118 }
119
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700120 private static void assertDevice(DeviceId id, String swVersion, Device device) {
121 assertNotNull(device);
122 assertEquals(id, device.id());
123 assertEquals(MFR, device.manufacturer());
124 assertEquals(HW, device.hwVersion());
125 assertEquals(swVersion, device.swVersion());
126 assertEquals(SN, device.serialNumber());
127 }
128
Yuta HIGUCHI39ede6a2014-10-03 15:23:33 -0700129 // TODO slice this out somewhere
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700130 /**
131 * Verifies that Annotations created by merging {@code annotations} is
132 * equal to actual Annotations.
133 *
134 * @param actual Annotations to check
135 * @param annotations
136 */
Yuta HIGUCHI39ede6a2014-10-03 15:23:33 -0700137 public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) {
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700138 DefaultAnnotations expected = DefaultAnnotations.builder().build();
139 for (SparseAnnotations a : annotations) {
140 expected = DefaultAnnotations.merge(expected, a);
141 }
142 assertEquals(expected.keys(), actual.keys());
143 for (String key : expected.keys()) {
144 assertEquals(expected.value(key), actual.value(key));
145 }
146 }
147
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700148 @Test
149 public final void testGetDeviceCount() {
150 assertEquals("initialy empty", 0, deviceStore.getDeviceCount());
151
152 putDevice(DID1, SW1);
153 putDevice(DID2, SW2);
154 putDevice(DID1, SW1);
155
156 assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount());
157 }
158
159 @Test
160 public final void testGetDevices() {
161 assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices()));
162
163 putDevice(DID1, SW1);
164 putDevice(DID2, SW2);
165 putDevice(DID1, SW1);
166
167 assertEquals("expect 2 uniq devices",
168 2, Iterables.size(deviceStore.getDevices()));
169
170 Map<DeviceId, Device> devices = new HashMap<>();
171 for (Device device : deviceStore.getDevices()) {
172 devices.put(device.id(), device);
173 }
174
175 assertDevice(DID1, SW1, devices.get(DID1));
176 assertDevice(DID2, SW2, devices.get(DID2));
177
178 // add case for new node?
179 }
180
181 @Test
182 public final void testGetDevice() {
183
184 putDevice(DID1, SW1);
185
186 assertDevice(DID1, SW1, deviceStore.getDevice(DID1));
187 assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2));
188 }
189
190 @Test
191 public final void testCreateOrUpdateDevice() {
192 DeviceDescription description =
193 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
194 HW, SW1, SN);
195 DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description);
196 assertEquals(DEVICE_ADDED, event.type());
197 assertDevice(DID1, SW1, event.subject());
198
199 DeviceDescription description2 =
200 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
201 HW, SW2, SN);
202 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
203 assertEquals(DEVICE_UPDATED, event2.type());
204 assertDevice(DID1, SW2, event2.subject());
205
206 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
207 }
208
209 @Test
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700210 public final void testCreateOrUpdateDeviceAncillary() {
211 DeviceDescription description =
212 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700213 HW, SW1, SN, A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700214 DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description);
215 assertEquals(DEVICE_ADDED, event.type());
216 assertDevice(DID1, SW1, event.subject());
217 assertEquals(PIDA, event.subject().providerId());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700218 assertAnnotationsEquals(event.subject().annotations(), A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700219 assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1));
220
221 DeviceDescription description2 =
222 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700223 HW, SW2, SN, A1);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700224 DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2);
225 assertEquals(DEVICE_UPDATED, event2.type());
226 assertDevice(DID1, SW2, event2.subject());
227 assertEquals(PID, event2.subject().providerId());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700228 assertAnnotationsEquals(event2.subject().annotations(), A1, A2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700229 assertTrue(deviceStore.isAvailable(DID1));
230
231 assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2));
232
233 // For now, Ancillary is ignored once primary appears
234 assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description));
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700235
236 // But, Ancillary annotations will be in effect
237 DeviceDescription description3 =
238 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
239 HW, SW1, SN, A2_2);
240 DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3);
241 assertEquals(DEVICE_UPDATED, event3.type());
242 // basic information will be the one from Primary
243 assertDevice(DID1, SW2, event3.subject());
244 assertEquals(PID, event3.subject().providerId());
245 // but annotation from Ancillary will be merged
246 assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2);
247 assertTrue(deviceStore.isAvailable(DID1));
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700248 }
249
250
251 @Test
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700252 public final void testMarkOffline() {
253
254 putDevice(DID1, SW1);
255 assertTrue(deviceStore.isAvailable(DID1));
256
257 DeviceEvent event = deviceStore.markOffline(DID1);
258 assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type());
259 assertDevice(DID1, SW1, event.subject());
260 assertFalse(deviceStore.isAvailable(DID1));
261
262 DeviceEvent event2 = deviceStore.markOffline(DID1);
263 assertNull("No change, no event", event2);
264}
265
266 @Test
267 public final void testUpdatePorts() {
268 putDevice(DID1, SW1);
269 List<PortDescription> pds = Arrays.<PortDescription>asList(
270 new DefaultPortDescription(P1, true),
271 new DefaultPortDescription(P2, true)
272 );
273
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700274 List<DeviceEvent> events = deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700275
276 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
277 for (DeviceEvent event : events) {
278 assertEquals(PORT_ADDED, event.type());
279 assertDevice(DID1, SW1, event.subject());
280 assertTrue("PortNumber is one of expected",
281 expectedPorts.remove(event.port().number()));
282 assertTrue("Port is enabled", event.port().isEnabled());
283 }
284 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
285
286
287 List<PortDescription> pds2 = Arrays.<PortDescription>asList(
288 new DefaultPortDescription(P1, false),
289 new DefaultPortDescription(P2, true),
290 new DefaultPortDescription(P3, true)
291 );
292
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700293 events = deviceStore.updatePorts(PID, DID1, pds2);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700294 assertFalse("event should be triggered", events.isEmpty());
295 for (DeviceEvent event : events) {
296 PortNumber num = event.port().number();
297 if (P1.equals(num)) {
298 assertEquals(PORT_UPDATED, event.type());
299 assertDevice(DID1, SW1, event.subject());
300 assertFalse("Port is disabled", event.port().isEnabled());
301 } else if (P2.equals(num)) {
302 fail("P2 event not expected.");
303 } else if (P3.equals(num)) {
304 assertEquals(PORT_ADDED, event.type());
305 assertDevice(DID1, SW1, event.subject());
306 assertTrue("Port is enabled", event.port().isEnabled());
307 } else {
308 fail("Unknown port number encountered: " + num);
309 }
310 }
311
312 List<PortDescription> pds3 = Arrays.<PortDescription>asList(
313 new DefaultPortDescription(P1, false),
314 new DefaultPortDescription(P2, true)
315 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700316 events = deviceStore.updatePorts(PID, DID1, pds3);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700317 assertFalse("event should be triggered", events.isEmpty());
318 for (DeviceEvent event : events) {
319 PortNumber num = event.port().number();
320 if (P1.equals(num)) {
321 fail("P1 event not expected.");
322 } else if (P2.equals(num)) {
323 fail("P2 event not expected.");
324 } else if (P3.equals(num)) {
325 assertEquals(PORT_REMOVED, event.type());
326 assertDevice(DID1, SW1, event.subject());
327 assertTrue("Port was enabled", event.port().isEnabled());
328 } else {
329 fail("Unknown port number encountered: " + num);
330 }
331 }
332
333 }
334
335 @Test
336 public final void testUpdatePortStatus() {
337 putDevice(DID1, SW1);
338 List<PortDescription> pds = Arrays.<PortDescription>asList(
339 new DefaultPortDescription(P1, true)
340 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700341 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700342
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700343 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1,
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700344 new DefaultPortDescription(P1, false));
345 assertEquals(PORT_UPDATED, event.type());
346 assertDevice(DID1, SW1, event.subject());
347 assertEquals(P1, event.port().number());
348 assertFalse("Port is disabled", event.port().isEnabled());
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700349
350 }
Yuta HIGUCHI39ede6a2014-10-03 15:23:33 -0700351
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700352 @Test
353 public final void testUpdatePortStatusAncillary() {
354 putDeviceAncillary(DID1, SW1);
355 putDevice(DID1, SW1);
356 List<PortDescription> pds = Arrays.<PortDescription>asList(
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700357 new DefaultPortDescription(P1, true, A1)
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700358 );
359 deviceStore.updatePorts(PID, DID1, pds);
360
361 DeviceEvent event = deviceStore.updatePortStatus(PID, DID1,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700362 new DefaultPortDescription(P1, false, A1_2));
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700363 assertEquals(PORT_UPDATED, event.type());
364 assertDevice(DID1, SW1, event.subject());
365 assertEquals(P1, event.port().number());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700366 assertAnnotationsEquals(event.port().annotations(), A1, A1_2);
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700367 assertFalse("Port is disabled", event.port().isEnabled());
368
369 DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1,
370 new DefaultPortDescription(P1, true));
371 assertNull("Ancillary is ignored if primary exists", event2);
372
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700373 // but, Ancillary annotation update will be notified
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700374 DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1,
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700375 new DefaultPortDescription(P1, true, A2));
376 assertEquals(PORT_UPDATED, event3.type());
Yuta HIGUCHI8e493792014-10-01 19:36:32 -0700377 assertDevice(DID1, SW1, event3.subject());
Yuta HIGUCHI55710e72014-10-02 14:58:32 -0700378 assertEquals(P1, event3.port().number());
379 assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2);
380 assertFalse("Port is disabled", event3.port().isEnabled());
381
382 // port only reported from Ancillary will be notified as down
383 DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1,
384 new DefaultPortDescription(P2, true));
385 assertEquals(PORT_ADDED, event4.type());
386 assertDevice(DID1, SW1, event4.subject());
387 assertEquals(P2, event4.port().number());
388 assertAnnotationsEquals(event4.port().annotations());
389 assertFalse("Port is disabled if not given from primary provider",
390 event4.port().isEnabled());
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700391 }
392
393 @Test
394 public final void testGetPorts() {
395 putDevice(DID1, SW1);
396 putDevice(DID2, SW1);
397 List<PortDescription> pds = Arrays.<PortDescription>asList(
398 new DefaultPortDescription(P1, true),
399 new DefaultPortDescription(P2, true)
400 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700401 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700402
403 Set<PortNumber> expectedPorts = Sets.newHashSet(P1, P2);
404 List<Port> ports = deviceStore.getPorts(DID1);
405 for (Port port : ports) {
406 assertTrue("Port is enabled", port.isEnabled());
407 assertTrue("PortNumber is one of expected",
408 expectedPorts.remove(port.number()));
409 }
410 assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty());
411
412
413 assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty());
414 }
415
416 @Test
417 public final void testGetPort() {
418 putDevice(DID1, SW1);
419 putDevice(DID2, SW1);
420 List<PortDescription> pds = Arrays.<PortDescription>asList(
421 new DefaultPortDescription(P1, true),
422 new DefaultPortDescription(P2, false)
423 );
Yuta HIGUCHI5f6739c2014-10-01 14:04:01 -0700424 deviceStore.updatePorts(PID, DID1, pds);
Yuta HIGUCHIf5712ff2014-09-27 23:52:37 -0700425
426 Port port1 = deviceStore.getPort(DID1, P1);
427 assertEquals(P1, port1.number());
428 assertTrue("Port is enabled", port1.isEnabled());
429
430 Port port2 = deviceStore.getPort(DID1, P2);
431 assertEquals(P2, port2.number());
432 assertFalse("Port is disabled", port2.isEnabled());
433
434 Port port3 = deviceStore.getPort(DID1, P3);
435 assertNull("P3 not expected", port3);
436 }
437
438 @Test
439 public final void testRemoveDevice() {
440 putDevice(DID1, SW1);
441 putDevice(DID2, SW1);
442
443 assertEquals(2, deviceStore.getDeviceCount());
444
445 DeviceEvent event = deviceStore.removeDevice(DID1);
446 assertEquals(DEVICE_REMOVED, event.type());
447 assertDevice(DID1, SW1, event.subject());
448
449 assertEquals(1, deviceStore.getDeviceCount());
450 }
451
452 // If Delegates should be called only on remote events,
453 // then Simple* should never call them, thus not test required.
454 // TODO add test for Port events when we have them
455 @Ignore("Ignore until Delegate spec. is clear.")
456 @Test
457 public final void testEvents() throws InterruptedException {
458 final CountDownLatch addLatch = new CountDownLatch(1);
459 DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() {
460 @Override
461 public void notify(DeviceEvent event) {
462 assertEquals(DEVICE_ADDED, event.type());
463 assertDevice(DID1, SW1, event.subject());
464 addLatch.countDown();
465 }
466 };
467 final CountDownLatch updateLatch = new CountDownLatch(1);
468 DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() {
469 @Override
470 public void notify(DeviceEvent event) {
471 assertEquals(DEVICE_UPDATED, event.type());
472 assertDevice(DID1, SW2, event.subject());
473 updateLatch.countDown();
474 }
475 };
476 final CountDownLatch removeLatch = new CountDownLatch(1);
477 DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() {
478 @Override
479 public void notify(DeviceEvent event) {
480 assertEquals(DEVICE_REMOVED, event.type());
481 assertDevice(DID1, SW2, event.subject());
482 removeLatch.countDown();
483 }
484 };
485
486 DeviceDescription description =
487 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
488 HW, SW1, SN);
489 deviceStore.setDelegate(checkAdd);
490 deviceStore.createOrUpdateDevice(PID, DID1, description);
491 assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS));
492
493
494 DeviceDescription description2 =
495 new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR,
496 HW, SW2, SN);
497 deviceStore.unsetDelegate(checkAdd);
498 deviceStore.setDelegate(checkUpdate);
499 deviceStore.createOrUpdateDevice(PID, DID1, description2);
500 assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS));
501
502 deviceStore.unsetDelegate(checkUpdate);
503 deviceStore.setDelegate(checkRemove);
504 deviceStore.removeDevice(DID1);
505 assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS));
506 }
507}