Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/System/LoggerFinder/internal/SimpleConsoleLoggerTest/SimpleConsoleLoggerTest.java
41171 views
1
/*
2
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
import java.io.ByteArrayOutputStream;
24
import java.io.IOException;
25
import java.io.PrintStream;
26
import java.io.UncheckedIOException;
27
import java.util.Collections;
28
import java.util.Enumeration;
29
import java.util.ResourceBundle;
30
import java.util.concurrent.ConcurrentHashMap;
31
import java.util.concurrent.atomic.AtomicBoolean;
32
import java.util.concurrent.atomic.AtomicLong;
33
import java.util.function.Supplier;
34
import java.lang.System.Logger;
35
import java.lang.System.Logger.Level;
36
import java.util.EnumSet;
37
import java.util.HashMap;
38
import java.util.Locale;
39
import java.util.Map;
40
import jdk.internal.logger.SimpleConsoleLogger;
41
import jdk.internal.logger.SurrogateLogger;
42
import sun.util.logging.PlatformLogger;
43
44
/**
45
* @test
46
* @bug 8140364
47
* @summary JDK implementation specific unit test for SimpleConsoleLogger.
48
* Tests the behavior of SimpleConsoleLogger.
49
* @modules java.base/sun.util.logging
50
* java.base/jdk.internal.logger
51
* @build SimpleConsoleLoggerTest
52
* @run main/othervm SimpleConsoleLoggerTest
53
* @run main/othervm -Djdk.system.logger.level=OFF SimpleConsoleLoggerTest
54
* @run main/othervm -Djdk.system.logger.level=ERROR SimpleConsoleLoggerTest
55
* @run main/othervm -Djdk.system.logger.level=WARNING SimpleConsoleLoggerTest
56
* @run main/othervm -Djdk.system.logger.level=INFO SimpleConsoleLoggerTest
57
* @run main/othervm -Djdk.system.logger.level=DEBUG SimpleConsoleLoggerTest
58
* @run main/othervm -Djdk.system.logger.level=TRACE SimpleConsoleLoggerTest
59
* @run main/othervm -Djdk.system.logger.level=ALL SimpleConsoleLoggerTest
60
* @run main/othervm -Djdk.system.logger.level=WOMBAT SimpleConsoleLoggerTest
61
* @run main/othervm -Djdk.system.logger.level SimpleConsoleLoggerTest
62
* @run main/othervm -Djdk.system.logger.level=FINEST SimpleConsoleLoggerTest
63
* @run main/othervm -Djdk.system.logger.level=DEBUG -Djava.util.logging.SimpleFormatter.format=++++_%2$s%n%4$s:_%5$s%6$s%n SimpleConsoleLoggerTest
64
* @run main/othervm -Djdk.system.logger.level=DEBUG -Djdk.system.logger.format=++++_%2$s%n%4$s:_%5$s%6$s%n SimpleConsoleLoggerTest
65
*
66
* @author danielfuchs
67
*/
68
public class SimpleConsoleLoggerTest {
69
70
static final RuntimePermission LOGGERFINDER_PERMISSION =
71
new RuntimePermission("loggerFinder");
72
final static boolean VERBOSE = false;
73
74
public static class MyBundle extends ResourceBundle {
75
76
final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
77
78
@Override
79
protected Object handleGetObject(String key) {
80
if (key.contains(" (translated)")) {
81
throw new RuntimeException("Unexpected key: " + key);
82
}
83
return map.computeIfAbsent(key, k -> k.toUpperCase(Locale.ROOT) + " (translated)");
84
}
85
86
@Override
87
public Enumeration<String> getKeys() {
88
return Collections.enumeration(map.keySet());
89
}
90
91
}
92
public static class MyLoggerBundle extends MyBundle {
93
94
}
95
96
97
static class ErrorStream extends PrintStream {
98
99
static AtomicBoolean forward = new AtomicBoolean();
100
ByteArrayOutputStream out;
101
String saved = "";
102
public ErrorStream(ByteArrayOutputStream out) {
103
super(out);
104
this.out = out;
105
}
106
107
@Override
108
public void write(int b) {
109
super.write(b);
110
if (forward.get()) err.write(b);
111
}
112
113
@Override
114
public void write(byte[] b) throws IOException {
115
super.write(b);
116
if (forward.get()) err.write(b);
117
}
118
119
@Override
120
public void write(byte[] buf, int off, int len) {
121
super.write(buf, off, len);
122
if (forward.get()) err.write(buf, off, len);
123
}
124
125
public String peek() {
126
flush();
127
return out.toString();
128
}
129
130
public String drain() {
131
flush();
132
String res = out.toString();
133
out.reset();
134
return res;
135
}
136
137
public void store() {
138
flush();
139
saved = out.toString();
140
out.reset();
141
}
142
143
public void restore() {
144
out.reset();
145
try {
146
out.write(saved.getBytes());
147
} catch(IOException io) {
148
throw new UncheckedIOException(io);
149
}
150
}
151
152
static final PrintStream err = System.err;
153
static final ErrorStream errorStream = new ErrorStream(new ByteArrayOutputStream());
154
}
155
156
private static StringBuilder appendProperty(StringBuilder b, String name) {
157
String value = System.getProperty(name);
158
if (value == null) return b;
159
return b.append(name).append("=").append(value).append('\n');
160
}
161
162
public static void main(String[] args) {
163
Locale.setDefault(Locale.ENGLISH);
164
System.setErr(ErrorStream.errorStream);
165
try {
166
test(args);
167
} finally {
168
try {
169
System.setErr(ErrorStream.err);
170
} catch (Error | RuntimeException x) {
171
x.printStackTrace(ErrorStream.err);
172
}
173
}
174
}
175
176
177
public static void test(String[] args) {
178
179
ErrorStream.errorStream.restore();
180
String l = System.getProperty("jdk.system.logger.level");
181
String f = System.getProperty("jdk.system.logger.format");
182
String jf = System.getProperty("java.util.logging.SimpleFormatter.format");
183
System.out.println("Running test: "
184
+ "\n\tjdk.system.logger.level=\"" + l + "\""
185
+ "\n\tjdk.system.logger.format=\"" + f + "\""
186
+ "\n\tjava.util.logging.SimpleFormatter.format=\"" + jf + "\"");
187
188
test(l,f,jf);
189
System.out.println("\nPASSED: tested " + SEQUENCER.get() + " test cases");
190
}
191
192
static final AtomicLong SEQUENCER = new AtomicLong();
193
public static void test(String defaultLevel, String defaultFormat, String julFormat) {
194
195
final Map<Logger, String> loggerDescMap = new HashMap<>();
196
197
SimpleConsoleLogger simple = SimpleConsoleLogger.makeSimpleLogger("test.logger");
198
loggerDescMap.put(simple, "SimpleConsoleLogger.makeSimpleLogger(\"test.logger\")");
199
SimpleConsoleLogger temporary = SurrogateLogger.makeSurrogateLogger("test.logger");
200
loggerDescMap.put(temporary, "SurrogateLogger.makeSimpleLogger(\"test.logger\")");
201
202
Level level;
203
try {
204
level = defaultLevel == null ? null : Level.valueOf(defaultLevel);
205
} catch (IllegalArgumentException ex) {
206
level = null;
207
}
208
testLogger(loggerDescMap, simple, level, false, defaultFormat);
209
testLogger(loggerDescMap, temporary, null, true, julFormat);
210
}
211
212
public static class Foo {
213
214
}
215
216
static void verbose(String msg) {
217
if (VERBOSE) {
218
System.out.println(msg);
219
}
220
}
221
222
static String getName(Level level, boolean usePlatformLevel) {
223
if (usePlatformLevel) {
224
return PlatformLogger.toPlatformLevel(level).name();
225
} else {
226
return level.getName();
227
}
228
}
229
230
// Calls the 8 methods defined on Logger and verify the
231
// parameters received by the underlying TestProvider.LoggerImpl
232
// logger.
233
private static void testLogger(Map<Logger, String> loggerDescMap,
234
SimpleConsoleLogger simple,
235
Level defaultLevel,
236
boolean usePlatformLevel,
237
String defaultFormat) {
238
239
System.out.println("Testing " + loggerDescMap.get(simple) + " [" + simple +"]");
240
241
String formatStrMarker = defaultFormat == null ? ""
242
: defaultFormat.startsWith("++++") ? "++++" : "";
243
String unexpectedMarker = defaultFormat == null ? "++++"
244
: defaultFormat.startsWith("++++") ? "????" : "++++";
245
String formatStrSpec = defaultFormat == null ? "[date]"
246
: defaultFormat.startsWith("++++") ? "++++" : "????";
247
String sep = defaultFormat == null ? ": " : ":_";
248
String sepw = defaultFormat == null ? " " : "_";
249
250
Foo foo = new Foo();
251
String fooMsg = foo.toString();
252
for (Level loggerLevel : defaultLevel == null
253
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
254
for (Level messageLevel : Level.values()) {
255
ErrorStream.errorStream.drain();
256
String desc = "logger.log(messageLevel, foo): loggerLevel="
257
+ loggerLevel+", messageLevel="+messageLevel;
258
SEQUENCER.incrementAndGet();
259
simple.log(messageLevel, foo);
260
if (loggerLevel == Level.OFF || messageLevel == Level.OFF
261
|| messageLevel.compareTo(loggerLevel) < 0) {
262
if (!ErrorStream.errorStream.peek().isEmpty()) {
263
throw new RuntimeException("unexpected event in queue for "
264
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
265
}
266
} else {
267
String logged = ErrorStream.errorStream.drain();
268
String expected = getName(messageLevel, usePlatformLevel) + sep + fooMsg;
269
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
270
|| !logged.contains(formatStrMarker)
271
|| logged.contains(unexpectedMarker)
272
|| !logged.contains(expected)) {
273
throw new RuntimeException("mismatch for " + desc
274
+ "\n\texpected:" + "\n<<<<\n"
275
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
276
+ expected
277
+ "\n>>>>"
278
+ "\n\t actual:"
279
+ "\n<<<<\n" + logged + ">>>>\n");
280
} else {
281
verbose("Got expected results for "
282
+ desc + "\n<<<<\n" + logged + ">>>>\n");
283
}
284
}
285
}
286
}
287
288
String msg = "blah";
289
for (Level loggerLevel : defaultLevel == null
290
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
291
for (Level messageLevel : Level.values()) {
292
String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
293
+ loggerLevel+", messageLevel="+messageLevel;
294
SEQUENCER.incrementAndGet();
295
simple.log(messageLevel, msg);
296
if (loggerLevel == Level.OFF || messageLevel == Level.OFF
297
|| messageLevel.compareTo(loggerLevel) < 0) {
298
if (!ErrorStream.errorStream.peek().isEmpty()) {
299
throw new RuntimeException("unexpected event in queue for "
300
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
301
}
302
} else {
303
String logged = ErrorStream.errorStream.drain();
304
String expected = getName(messageLevel, usePlatformLevel) + sep + msg;
305
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
306
|| !logged.contains(formatStrMarker)
307
|| logged.contains(unexpectedMarker)
308
|| !logged.contains(expected)) {
309
throw new RuntimeException("mismatch for " + desc
310
+ "\n\texpected:" + "\n<<<<\n"
311
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
312
+ expected
313
+ "\n>>>>"
314
+ "\n\t actual:"
315
+ "\n<<<<\n" + logged + ">>>>\n");
316
} else {
317
verbose("Got expected results for "
318
+ desc + "\n<<<<\n" + logged + ">>>>\n");
319
}
320
}
321
}
322
}
323
324
Supplier<String> fooSupplier = new Supplier<String>() {
325
@Override
326
public String get() {
327
return this.toString();
328
}
329
};
330
331
for (Level loggerLevel : defaultLevel == null
332
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
333
for (Level messageLevel : Level.values()) {
334
String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
335
+ loggerLevel+", messageLevel="+messageLevel;
336
SEQUENCER.incrementAndGet();
337
simple.log(messageLevel, fooSupplier);
338
if (loggerLevel == Level.OFF || messageLevel == Level.OFF
339
|| messageLevel.compareTo(loggerLevel) < 0) {
340
if (!ErrorStream.errorStream.peek().isEmpty()) {
341
throw new RuntimeException("unexpected event in queue for "
342
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
343
}
344
} else {
345
String logged = ErrorStream.errorStream.drain();
346
String expected = getName(messageLevel, usePlatformLevel) + sep + fooSupplier.get();
347
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
348
|| !logged.contains(formatStrMarker)
349
|| logged.contains(unexpectedMarker)
350
|| !logged.contains(expected)) {
351
throw new RuntimeException("mismatch for " + desc
352
+ "\n\texpected:" + "\n<<<<\n"
353
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
354
+ expected
355
+ "\n>>>>"
356
+ "\n\t actual:"
357
+ "\n<<<<\n" + logged + ">>>>\n");
358
} else {
359
verbose("Got expected results for "
360
+ desc + "\n<<<<\n" + logged + ">>>>\n");
361
}
362
}
363
}
364
}
365
366
367
String format = "two params [{1} {2}]";
368
Object arg1 = foo;
369
Object arg2 = msg;
370
for (Level loggerLevel : defaultLevel == null
371
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
372
for (Level messageLevel : Level.values()) {
373
String desc = "logger.log(messageLevel, format, params...): loggerLevel="
374
+ loggerLevel+", messageLevel="+messageLevel;
375
SEQUENCER.incrementAndGet();
376
simple.log(messageLevel, format, foo, msg);
377
if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
378
if (!ErrorStream.errorStream.peek().isEmpty()) {
379
throw new RuntimeException("unexpected event in queue for "
380
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
381
}
382
} else {
383
String logged = ErrorStream.errorStream.drain();
384
String msgFormat = format;
385
String text = java.text.MessageFormat.format(msgFormat, foo, msg);
386
String expected = getName(messageLevel, usePlatformLevel) + sep + text;
387
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
388
|| !logged.contains(formatStrMarker)
389
|| !logged.contains(expected)) {
390
throw new RuntimeException("mismatch for " + desc
391
+ "\n\texpected:" + "\n<<<<\n"
392
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
393
+ expected
394
+ "\n>>>>"
395
+ "\n\t actual:"
396
+ "\n<<<<\n" + logged + ">>>>\n");
397
} else {
398
verbose("Got expected results for "
399
+ desc + "\n<<<<\n" + logged + ">>>>\n");
400
}
401
}
402
}
403
}
404
405
Throwable thrown = new Exception("OK: log me!");
406
for (Level loggerLevel : defaultLevel == null
407
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
408
for (Level messageLevel : Level.values()) {
409
String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
410
+ loggerLevel+", messageLevel="+messageLevel;
411
SEQUENCER.incrementAndGet();
412
simple.log(messageLevel, msg, thrown);
413
if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
414
if (!ErrorStream.errorStream.peek().isEmpty()) {
415
throw new RuntimeException("unexpected event in queue for "
416
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
417
}
418
} else {
419
String logged = ErrorStream.errorStream.drain();
420
ByteArrayOutputStream baos = new ByteArrayOutputStream();
421
thrown.printStackTrace(new PrintStream(baos));
422
String text = baos.toString();
423
String expected = getName(messageLevel, usePlatformLevel) + sep + msg;
424
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
425
|| !logged.contains(formatStrMarker)
426
|| !logged.contains(expected)
427
|| logged.contains(unexpectedMarker)
428
|| !logged.contains(text)) {
429
throw new RuntimeException("mismatch for " + desc
430
+ "\n\texpected:" + "\n<<<<\n"
431
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
432
+ msg +"\n"
433
+ text
434
+ ">>>>"
435
+ "\n\t actual:"
436
+ "\n<<<<\n" + logged + ">>>>\n");
437
} else {
438
verbose("Got expected results for "
439
+ desc + "\n<<<<\n" + logged + ">>>>\n");
440
}
441
}
442
}
443
}
444
445
446
for (Level loggerLevel : defaultLevel == null
447
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
448
for (Level messageLevel : Level.values()) {
449
String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
450
+ loggerLevel+", messageLevel="+messageLevel;
451
SEQUENCER.incrementAndGet();
452
simple.log(messageLevel, fooSupplier, thrown);
453
if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
454
if (!ErrorStream.errorStream.peek().isEmpty()) {
455
throw new RuntimeException("unexpected event in queue for "
456
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
457
}
458
} else {
459
String logged = ErrorStream.errorStream.drain();
460
ByteArrayOutputStream baos = new ByteArrayOutputStream();
461
thrown.printStackTrace(new PrintStream(baos));
462
String text = baos.toString();
463
String expected = getName(messageLevel, usePlatformLevel) + sep + fooSupplier.get();
464
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
465
|| !logged.contains(formatStrMarker)
466
|| !logged.contains(expected)
467
|| logged.contains(unexpectedMarker)
468
|| !logged.contains(text)) {
469
throw new RuntimeException("mismatch for " + desc
470
+ "\n\texpected:" + "\n<<<<\n"
471
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
472
+ expected +"\n"
473
+ text
474
+ ">>>>"
475
+ "\n\t actual:"
476
+ "\n<<<<\n" + logged + ">>>>\n");
477
} else {
478
verbose("Got expected results for "
479
+ desc + "\n<<<<\n" + logged + ">>>>\n");
480
}
481
}
482
}
483
}
484
485
ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
486
for (Level loggerLevel : defaultLevel == null
487
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
488
for (Level messageLevel : Level.values()) {
489
String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
490
+ loggerLevel+", messageLevel="+messageLevel;
491
SEQUENCER.incrementAndGet();
492
simple.log(messageLevel, bundle, format, foo, msg);
493
if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
494
if (!ErrorStream.errorStream.peek().isEmpty()) {
495
throw new RuntimeException("unexpected event in queue for "
496
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
497
}
498
} else {
499
String logged = ErrorStream.errorStream.drain();
500
String text = java.text.MessageFormat.format(bundle.getString(format), foo, msg);
501
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
502
|| !logged.contains(formatStrMarker)
503
|| logged.contains(unexpectedMarker)
504
|| !logged.contains(getName(messageLevel, usePlatformLevel) + sep + text)) {
505
throw new RuntimeException("mismatch for " + desc
506
+ "\n\texpected:" + "\n<<<<\n"
507
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
508
+ getName(messageLevel, usePlatformLevel) + " " + text
509
+ "\n>>>>"
510
+ "\n\t actual:"
511
+ "\n<<<<\n" + logged + ">>>>\n");
512
} else {
513
verbose("Got expected results for "
514
+ desc + "\n<<<<\n" + logged + ">>>>\n");
515
}
516
}
517
}
518
}
519
520
for (Level loggerLevel : defaultLevel == null
521
? EnumSet.of(Level.INFO) : EnumSet.of(defaultLevel)) {
522
for (Level messageLevel : Level.values()) {
523
String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
524
+ loggerLevel+", messageLevel="+messageLevel;
525
SEQUENCER.incrementAndGet();
526
simple.log(messageLevel, bundle, msg, thrown);
527
if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
528
if (!ErrorStream.errorStream.peek().isEmpty()) {
529
throw new RuntimeException("unexpected event in queue for "
530
+ desc +": " + "\n\t" + ErrorStream.errorStream.drain());
531
}
532
} else {
533
String logged = ErrorStream.errorStream.drain();
534
String textMsg = bundle.getString(msg);
535
ByteArrayOutputStream baos = new ByteArrayOutputStream();
536
thrown.printStackTrace(new PrintStream(baos));
537
String text = baos.toString();
538
String expected = getName(messageLevel, usePlatformLevel) + sep + textMsg;
539
if (!logged.contains("SimpleConsoleLoggerTest testLogger")
540
|| !logged.contains(formatStrMarker)
541
|| !logged.contains(expected)
542
|| logged.contains(unexpectedMarker)
543
|| !logged.contains(text)) {
544
throw new RuntimeException("mismatch for " + desc
545
+ "\n\texpected:" + "\n<<<<\n"
546
+ formatStrSpec + sepw + "SimpleConsoleLoggerTest testLogger\n"
547
+ expected +"\n"
548
+ text
549
+ ">>>>"
550
+ "\n\t actual:"
551
+ "\n<<<<\n" + logged + ">>>>\n");
552
} else {
553
verbose("Got expected results for "
554
+ desc + "\n<<<<\n" + logged + ">>>>\n");
555
}
556
}
557
}
558
}
559
560
}
561
}
562
563