OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // The dart:mirrors library provides reflective access for Dart program. | 5 // The dart:mirrors library provides reflective access for Dart program. |
6 // | |
7 // For the purposes of the mirrors library, we adopt a naming | |
8 // convention with respect to getters and setters. Specifically, for | |
9 // some variable or field... | |
10 // | |
11 // var myField; | |
12 // | |
13 // ...the getter is named 'myField' and the setter is named | |
14 // 'myField='. This allows us to assign unique names to getters and | |
15 // setters for the purposes of member lookup. | |
16 | 6 |
17 // #library("mirrors"); | 7 library dart.mirrors; |
18 | 8 |
19 /** | 9 part "mirror_classes.dart"; |
20 * A [MirrorSystem] is the main interface used to reflect on a set of | |
21 * associated libraries. | |
22 * | |
23 * At runtime each running isolate has a distinct [MirrorSystem]. | |
24 * | |
25 * It is also possible to have a [MirrorSystem] which represents a set | |
26 * of libraries which are not running -- perhaps at compile-time. In | |
27 * this case, all available reflective functionality would be | |
28 * supported, but runtime functionality (such as invoking a function | |
29 * or inspecting the contents of a variable) would fail dynamically. | |
30 */ | |
31 abstract class MirrorSystem { | |
32 /** | |
33 * An immutable map from from library names to mirrors for all | |
34 * libraries known to this mirror system. | |
35 */ | |
36 Map<String, LibraryMirror> get libraries; | |
37 | |
38 /** | |
39 * A mirror on the isolate associated with this [MirrorSystem]. | |
40 * This may be null if this mirror system is not running. | |
41 */ | |
42 IsolateMirror get isolate; | |
43 | |
44 /** | |
45 * A mirror on the [:dynamic:] type. | |
46 */ | |
47 TypeMirror get dynamicType; | |
48 | |
49 /** | |
50 * A mirror on the [:void:] type. | |
51 */ | |
52 TypeMirror get voidType; | |
53 } | |
54 | |
55 /** | |
56 * Returns a [MirrorSystem] for the current isolate. | |
57 */ | |
58 MirrorSystem currentMirrorSystem() { | |
59 return _Mirrors.currentMirrorSystem(); | |
60 } | |
61 | |
62 /** | |
63 * Creates a [MirrorSystem] for the isolate which is listening on | |
64 * the [SendPort]. | |
65 */ | |
66 Future<MirrorSystem> mirrorSystemOf(SendPort port) { | |
67 return _Mirrors.mirrorSystemOf(port); | |
68 } | |
69 | |
70 /** | |
71 * Returns an [InstanceMirror] for some Dart language object. | |
72 * | |
73 * This only works if this mirror system is associated with the | |
74 * current running isolate. | |
75 */ | |
76 InstanceMirror reflect(Object reflectee) { | |
77 return _Mirrors.reflect(reflectee); | |
78 } | |
79 | |
80 /** | |
81 * A [Mirror] reflects some Dart language entity. | |
82 * | |
83 * Every [Mirror] originates from some [MirrorSystem]. | |
84 */ | |
85 abstract class Mirror { | |
86 /** | |
87 * The [MirrorSystem] that contains this mirror. | |
88 */ | |
89 MirrorSystem get mirrors; | |
90 } | |
91 | |
92 /** | |
93 * An [IsolateMirror] reflects an isolate. | |
94 */ | |
95 abstract class IsolateMirror implements Mirror { | |
96 /** | |
97 * A unique name used to refer to an isolate in debugging messages. | |
98 */ | |
99 String get debugName; | |
100 | |
101 /** | |
102 * Does this mirror reflect the currently running isolate? | |
103 */ | |
104 bool get isCurrent; | |
105 | |
106 /** | |
107 * A mirror on the root library for this isolate. | |
108 */ | |
109 LibraryMirror get rootLibrary; | |
110 } | |
111 | |
112 /** | |
113 * A [DeclarationMirror] reflects some entity declared in a Dart program. | |
114 */ | |
115 abstract class DeclarationMirror implements Mirror { | |
116 /** | |
117 * The simple name for this Dart language entity. | |
118 * | |
119 * The simple name is in most cases the the identifier name of the | |
120 * entity, such as 'method' for a method [:void method() {...}:] or | |
121 * 'mylibrary' for a [:#library('mylibrary');:] declaration. | |
122 */ | |
123 String get simpleName; | |
124 | |
125 /** | |
126 * The fully-qualified name for this Dart language entity. | |
127 * | |
128 * This name is qualified by the name of the owner. For instance, | |
129 * the qualified name of a method 'method' in class 'Class' in | |
130 * library 'library' is 'library.Class.method'. | |
131 * | |
132 * TODO(turnidge): Specify whether this name is unique. Currently | |
133 * this is a gray area due to lack of clarity over whether library | |
134 * names are unique. | |
135 */ | |
136 String get qualifiedName; | |
137 | |
138 /** | |
139 * A mirror on the owner of this function. This is the declaration | |
140 * immediately surrounding the reflectee. | |
141 * | |
142 * Note that for libraries, the owner will be [:null:]. | |
143 */ | |
144 DeclarationMirror get owner; | |
145 | |
146 /** | |
147 * Is this declaration private? | |
148 * | |
149 * Note that for libraries, this will be [:false:]. | |
150 */ | |
151 bool get isPrivate; | |
152 | |
153 /** | |
154 * Is this declaration top-level? | |
155 * | |
156 * This is defined to be equivalent to: | |
157 * [:mirror.owner != null && mirror.owner is LibraryMirror:] | |
158 */ | |
159 bool get isTopLevel; | |
160 | |
161 /** | |
162 * The source location of this Dart language entity. | |
163 */ | |
164 SourceLocation get location; | |
165 } | |
166 | |
167 /** | |
168 * An [ObjectMirror] is a common superinterface of [InstanceMirror], | |
169 * [ClassMirror], and [LibraryMirror] that represents their shared | |
170 * functionality. | |
171 * | |
172 * For the purposes of the mirrors library, these types are all | |
173 * object-like, in that they support method invocation and field | |
174 * access. Real Dart objects are represented by the [InstanceMirror] | |
175 * type. | |
176 * | |
177 * See [InstanceMirror], [ClassMirror], and [LibraryMirror]. | |
178 */ | |
179 abstract class ObjectMirror implements Mirror { | |
180 /** | |
181 * Invokes the named function and returns a mirror on the result. | |
182 * | |
183 * TODO(turnidge): Properly document. | |
184 * TODO(turnidge): Handle ambiguous names. | |
185 * TODO(turnidge): Handle optional & named arguments. | |
186 */ | |
187 Future<InstanceMirror> invoke(String memberName, | |
188 List<Object> positionalArguments, | |
189 [Map<String,Object> namedArguments]); | |
190 | |
191 /** | |
192 * Invokes a getter and returns a mirror on the result. The getter | |
193 * can be the implicit getter for a field or a user-defined getter | |
194 * method. | |
195 * | |
196 * TODO(turnidge): Handle ambiguous names. | |
197 */ | |
198 Future<InstanceMirror> getField(String fieldName); | |
199 | |
200 /** | |
201 * Invokes a setter and returns a mirror on the result. The setter | |
202 * may be either the implicit setter for a non-final field or a | |
203 * user-defined setter method. | |
204 * | |
205 * TODO(turnidge): Handle ambiguous names. | |
206 */ | |
207 Future<InstanceMirror> setField(String fieldName, Object value); | |
208 } | |
209 | |
210 /** | |
211 * An [InstanceMirror] reflects an instance of a Dart language object. | |
212 */ | |
213 abstract class InstanceMirror implements ObjectMirror { | |
214 /** | |
215 * A mirror on the type of the reflectee. | |
216 */ | |
217 ClassMirror get type; | |
218 | |
219 /** | |
220 * Does [reflectee] contain the instance reflected by this mirror? | |
221 * This will always be true in the local case (reflecting instances | |
222 * in the same isolate), but only true in the remote case if this | |
223 * mirror reflects a simple value. | |
224 * | |
225 * A value is simple if one of the following holds: | |
226 * - the value is null | |
227 * - the value is of type [num] | |
228 * - the value is of type [bool] | |
229 * - the value is of type [String] | |
230 */ | |
231 bool get hasReflectee; | |
232 | |
233 /** | |
234 * If the [InstanceMirror] reflects an instance it is meaningful to | |
235 * have a local reference to, we provide access to the actual | |
236 * instance here. | |
237 * | |
238 * If you access [reflectee] when [hasReflectee] is false, an | |
239 * exception is thrown. | |
240 */ | |
241 get reflectee; | |
242 } | |
243 | |
244 /** | |
245 * A [ClosureMirror] reflects a closure. | |
246 * | |
247 * A [ClosureMirror] provides access to its captured variables and | |
248 * provides the ability to execute its reflectee. | |
249 */ | |
250 abstract class ClosureMirror implements InstanceMirror { | |
251 /** | |
252 * A mirror on the function associated with this closure. | |
253 */ | |
254 MethodMirror get function; | |
255 | |
256 /** | |
257 * The source code for this closure, if available. Otherwise null. | |
258 * | |
259 * TODO(turnidge): Would this just be available in function? | |
260 */ | |
261 String get source; | |
262 | |
263 /** | |
264 * Executes the closure. The arguments given in the descriptor need to | |
265 * be InstanceMirrors or simple values. | |
266 * | |
267 * A value is simple if one of the following holds: | |
268 * - the value is null | |
269 * - the value is of type [num] | |
270 * - the value is of type [bool] | |
271 * - the value is of type [String] | |
272 */ | |
273 Future<InstanceMirror> apply(List<Object> positionalArguments, | |
274 [Map<String,Object> namedArguments]); | |
275 | |
276 /** | |
277 * Looks up the value of a name in the scope of the closure. The | |
278 * result is a mirror on that value. | |
279 */ | |
280 Future<InstanceMirror> findInContext(String name); | |
281 } | |
282 | |
283 /** | |
284 * A [LibraryMirror] reflects a Dart language library, providing | |
285 * access to the variables, functions, and classes of the | |
286 * library. | |
287 */ | |
288 abstract class LibraryMirror implements DeclarationMirror, ObjectMirror { | |
289 /** | |
290 * The url of the library. | |
291 * | |
292 * TODO(turnidge): Document where this url comes from. Will this | |
293 * value be sensible? | |
294 */ | |
295 String get url; | |
296 | |
297 /** | |
298 * An immutable map from from names to mirrors for all members in | |
299 * this library. | |
300 * | |
301 * The members of a library are its top-level classes, | |
302 * functions, variables, getters, and setters. | |
303 */ | |
304 Map<String, Mirror> get members; | |
305 | |
306 /** | |
307 * An immutable map from names to mirrors for all class | |
308 * declarations in this library. | |
309 */ | |
310 Map<String, ClassMirror> get classes; | |
311 | |
312 /** | |
313 * An immutable map from names to mirrors for all function, getter, | |
314 * and setter declarations in this library. | |
315 */ | |
316 Map<String, MethodMirror> get functions; | |
317 | |
318 /** | |
319 * An immutable map from names to mirrors for all getter | |
320 * declarations in this library. | |
321 */ | |
322 Map<String, MethodMirror> get getters; | |
323 | |
324 /** | |
325 * An immutable map from names to mirrors for all setter | |
326 * declarations in this library. | |
327 */ | |
328 Map<String, MethodMirror> get setters; | |
329 | |
330 /** | |
331 * An immutable map from names to mirrors for all variable | |
332 * declarations in this library. | |
333 */ | |
334 Map<String, VariableMirror> get variables; | |
335 } | |
336 | |
337 /** | |
338 * A [TypeMirror] reflects a Dart language class, typedef | |
339 * or type variable. | |
340 */ | |
341 abstract class TypeMirror implements DeclarationMirror { | |
342 } | |
343 | |
344 /** | |
345 * A [ClassMirror] reflects a Dart language class. | |
346 */ | |
347 abstract class ClassMirror implements TypeMirror, ObjectMirror { | |
348 /** | |
349 * A mirror on the superclass on the reflectee. | |
350 * | |
351 * If this type is [:Object:] or a typedef, the superClass will be | |
352 * null. | |
353 */ | |
354 ClassMirror get superclass; | |
355 | |
356 /** | |
357 * A list of mirrors on the superinterfaces of the reflectee. | |
358 */ | |
359 List<ClassMirror> get superinterfaces; | |
360 | |
361 /** | |
362 * An immutable map from from names to mirrors for all members of | |
363 * this type. | |
364 * | |
365 * The members of a type are its methods, fields, getters, and | |
366 * setters. Note that constructors and type variables are not | |
367 * considered to be members of a type. | |
368 * | |
369 * This does not include inherited members. | |
370 */ | |
371 Map<String, Mirror> get members; | |
372 | |
373 /** | |
374 * An immutable map from names to mirrors for all method, | |
375 * declarations for this type. This does not include getters and | |
376 * setters. | |
377 */ | |
378 Map<String, MethodMirror> get methods; | |
379 | |
380 /** | |
381 * An immutable map from names to mirrors for all getter | |
382 * declarations for this type. | |
383 */ | |
384 Map<String, MethodMirror> get getters; | |
385 | |
386 /** | |
387 * An immutable map from names to mirrors for all setter | |
388 * declarations for this type. | |
389 */ | |
390 Map<String, MethodMirror> get setters; | |
391 | |
392 /** | |
393 * An immutable map from names to mirrors for all variable | |
394 * declarations for this type. | |
395 */ | |
396 Map<String, VariableMirror> get variables; | |
397 | |
398 /** | |
399 * An immutable map from names to mirrors for all constructor | |
400 * declarations for this type. | |
401 */ | |
402 Map<String, MethodMirror> get constructors; | |
403 | |
404 /** | |
405 * An immutable map from names to mirrors for all type variables for | |
406 * this type. | |
407 * | |
408 * This map preserves the order of declaration of the type variables. | |
409 */ | |
410 Map<String, TypeVariableMirror> get typeVariables; | |
411 | |
412 /** | |
413 * An immutable map from names to mirrors for all type arguments for | |
414 * this type. | |
415 * | |
416 * This map preserves the order of declaration of the type variables. | |
417 */ | |
418 Map<String, TypeMirror> get typeArguments; | |
419 | |
420 /** | |
421 * Is this the original declaration of this type? | |
422 * | |
423 * For most classes, they are their own original declaration. For | |
424 * generic classes, however, there is a distinction between the | |
425 * original class declaration, which has unbound type variables, and | |
426 * the instantiations of generic classes, which have bound type | |
427 * variables. | |
428 */ | |
429 bool get isOriginalDeclaration; | |
430 | |
431 /** | |
432 * A mirror on the original declaration of this type. | |
433 * | |
434 * For most classes, they are their own original declaration. For | |
435 * generic classes, however, there is a distinction between the | |
436 * original class declaration, which has unbound type variables, and | |
437 * the instantiations of generic classes, which have bound type | |
438 * variables. | |
439 */ | |
440 ClassMirror get originalDeclaration; | |
441 | |
442 /** | |
443 * Invokes the named constructor and returns a mirror on the result. | |
444 * | |
445 * TODO(turnidge): Properly document. | |
446 */ | |
447 Future<InstanceMirror> newInstance(String constructorName, | |
448 List<Object> positionalArguments, | |
449 [Map<String,Object> namedArguments]); | |
450 | |
451 /** | |
452 * Does this mirror represent a class? | |
453 * | |
454 * TODO(turnidge): This functions goes away after the | |
455 * class/interface changes. | |
456 */ | |
457 bool get isClass; | |
458 | |
459 /** | |
460 * A mirror on the default factory class or null if there is none. | |
461 * | |
462 * TODO(turnidge): This functions goes away after the | |
463 * class/interface changes. | |
464 */ | |
465 ClassMirror get defaultFactory; | |
466 } | |
467 | |
468 /** | |
469 * A [FunctionTypeMirror] represents the type of a function in the | |
470 * Dart language. | |
471 */ | |
472 abstract class FunctionTypeMirror implements ClassMirror { | |
473 /** | |
474 * The return type of the reflectee. | |
475 */ | |
476 TypeMirror get returnType; | |
477 | |
478 /** | |
479 * A list of the parameter types of the reflectee. | |
480 */ | |
481 List<ParameterMirror> get parameters; | |
482 | |
483 /** | |
484 * A mirror on the [:call:] method for the reflectee. | |
485 * | |
486 * TODO(turnidge): What is this and what is it for? | |
487 */ | |
488 MethodMirror get callMethod; | |
489 } | |
490 | |
491 /** | |
492 * A [TypeVariableMirror] represents a type parameter of a generic | |
493 * type. | |
494 */ | |
495 abstract class TypeVariableMirror extends TypeMirror { | |
496 /** | |
497 * A mirror on the type that is the upper bound of this type variable. | |
498 */ | |
499 TypeMirror get upperBound; | |
500 } | |
501 | |
502 /** | |
503 * A [TypedefMirror] represents a typedef in a Dart language program. | |
504 */ | |
505 abstract class TypedefMirror implements ClassMirror { | |
506 /** | |
507 * The defining type for this typedef. | |
508 * | |
509 * For instance [:void f(int):] is the value for [:typedef void f(int):]. | |
510 */ | |
511 TypeMirror get value; | |
512 } | |
513 | |
514 /** | |
515 * A [MethodMirror] reflects a Dart language function, method, | |
516 * constructor, getter, or setter. | |
517 */ | |
518 abstract class MethodMirror implements DeclarationMirror { | |
519 /** | |
520 * A mirror on the return type for the reflectee. | |
521 */ | |
522 TypeMirror get returnType; | |
523 | |
524 /** | |
525 * A list of mirrors on the parameters for the reflectee. | |
526 */ | |
527 List<ParameterMirror> get parameters; | |
528 | |
529 /** | |
530 * Is the reflectee static? | |
531 * | |
532 * For the purposes of the mirrors library, a top-level function is | |
533 * considered static. | |
534 */ | |
535 bool get isStatic; | |
536 | |
537 /** | |
538 * Is the reflectee abstract? | |
539 */ | |
540 bool get isAbstract; | |
541 | |
542 /** | |
543 * Is the reflectee a regular function or method? | |
544 * | |
545 * A function or method is regular if it is not a getter, setter, or | |
546 * constructor. Note that operators, by this definition, are | |
547 * regular methods. | |
548 */ | |
549 bool get isRegularMethod; | |
550 | |
551 /** | |
552 * Is the reflectee an operator? | |
553 */ | |
554 bool get isOperator; | |
555 | |
556 /** | |
557 * Is the reflectee a getter? | |
558 */ | |
559 bool get isGetter; | |
560 | |
561 /** | |
562 * Is the reflectee a setter? | |
563 */ | |
564 bool get isSetter; | |
565 | |
566 /** | |
567 * Is the reflectee a constructor? | |
568 */ | |
569 bool get isConstructor; | |
570 | |
571 /** | |
572 * The constructor name for named constructors and factory methods. | |
573 * | |
574 * For unnamed constructors, this is the empty string. For | |
575 * non-constructors, this is the empty string. | |
576 * | |
577 * For example, [:'bar':] is the constructor name for constructor | |
578 * [:Foo.bar:] of type [:Foo:]. | |
579 */ | |
580 String get constructorName; | |
581 | |
582 /** | |
583 * Is the reflectee a const constructor? | |
584 */ | |
585 bool get isConstConstructor; | |
586 | |
587 /** | |
588 * Is the reflectee a generative constructor? | |
589 */ | |
590 bool get isGenerativeConstructor; | |
591 | |
592 /** | |
593 * Is the reflectee a redirecting constructor? | |
594 */ | |
595 bool get isRedirectingConstructor; | |
596 | |
597 /** | |
598 * Is the reflectee a factory constructor? | |
599 */ | |
600 bool get isFactoryConstructor; | |
601 } | |
602 | |
603 /** | |
604 * A [VariableMirror] reflects a Dart language variable declaration. | |
605 */ | |
606 abstract class VariableMirror implements DeclarationMirror { | |
607 /** | |
608 * A mirror on the type of the reflectee. | |
609 */ | |
610 TypeMirror get type; | |
611 | |
612 /** | |
613 * Is the reflectee a static variable? | |
614 * | |
615 * For the purposes of the mirror library, top-level variables are | |
616 * implicitly declared static. | |
617 */ | |
618 bool get isStatic; | |
619 | |
620 /** | |
621 * Is the reflectee a final variable? | |
622 */ | |
623 bool get isFinal; | |
624 } | |
625 | |
626 /** | |
627 * A [ParameterMirror] reflects a Dart formal parameter declaration. | |
628 */ | |
629 abstract class ParameterMirror implements VariableMirror { | |
630 /** | |
631 * A mirror on the type of this parameter. | |
632 */ | |
633 TypeMirror get type; | |
634 | |
635 /** | |
636 * Is this parameter optional? | |
637 */ | |
638 bool get isOptional; | |
639 | |
640 /** | |
641 * Is this parameter named? | |
642 */ | |
643 bool get isNamed; | |
644 | |
645 /** | |
646 * Does this parameter have a default value? | |
647 */ | |
648 bool get hasDefaultValue; | |
649 | |
650 /** | |
651 * A mirror on the default value for this parameter, if it exists. | |
652 * | |
653 * TODO(turnidge): String may not be a good representation of this | |
654 * at runtime. | |
655 */ | |
656 String get defaultValue; | |
657 } | |
658 | |
659 /** | |
660 * A [SourceLocation] describes the span of an entity in Dart source code. | |
661 */ | |
662 abstract class SourceLocation { | |
663 } | |
664 | |
665 /** | |
666 * When an error occurs during the mirrored execution of code, a | |
667 * [MirroredError] is thrown. | |
668 * | |
669 * In general, there are three main classes of failure that can happen | |
670 * during mirrored execution of code in some isolate: | |
671 * | |
672 * - An exception is thrown but not caught. This is caught by the | |
673 * mirrors framework and a [MirroredUncaughtExceptionError] is | |
674 * created and thrown. | |
675 * | |
676 * - A compile-time error occurs, such as a syntax error. This is | |
677 * suppressed by the mirrors framework and a | |
678 * [MirroredCompilationError] is created and thrown. | |
679 * | |
680 * - A truly fatal error occurs, causing the isolate to be exited. If | |
681 * the reflector and reflectee share the same isolate, then they | |
682 * will both suffer. If the reflector and reflectee are in distinct | |
683 * isolates, then we hope to provide some information about the | |
684 * isolate death, but this has yet to be implemented. | |
685 * | |
686 * TODO(turnidge): Specify the behavior for remote fatal errors. | |
687 */ | |
688 abstract class MirroredError implements Exception { | |
689 } | |
690 | |
691 /** | |
692 * When an uncaught exception occurs during the mirrored execution | |
693 * of code, a [MirroredUncaughtExceptionError] is thrown. | |
694 * | |
695 * This exception contains a mirror on the original exception object. | |
696 * It also contains an object which can be used to recover the | |
697 * stacktrace. | |
698 */ | |
699 class MirroredUncaughtExceptionError extends MirroredError { | |
700 MirroredUncaughtExceptionError(this.exception_mirror, | |
701 this.exception_string, | |
702 this.stacktrace) {} | |
703 | |
704 /** A mirror on the exception object. */ | |
705 final InstanceMirror exception_mirror; | |
706 | |
707 /** The result of toString() for the exception object. */ | |
708 final String exception_string; | |
709 | |
710 /** A stacktrace object for the uncaught exception. */ | |
711 final Object stacktrace; | |
712 | |
713 String toString() { | |
714 return | |
715 "Uncaught exception during mirrored execution: <${exception_string}>"; | |
716 } | |
717 } | |
718 | |
719 /** | |
720 * When a compile-time error occurs during the mirrored execution | |
721 * of code, a [MirroredCompilationError] is thrown. | |
722 * | |
723 * This exception includes the compile-time error message that would | |
724 * have been displayed to the user, if the function had not been | |
725 * invoked via mirror. | |
726 */ | |
727 class MirroredCompilationError extends MirroredError { | |
728 MirroredCompilationError(this.message) {} | |
729 | |
730 final String message; | |
731 | |
732 String toString() { | |
733 return "Compile-time error during mirrored execution: <$message>"; | |
734 } | |
735 } | |
736 | |
737 /** | |
738 * A [MirrorException] is used to indicate errors within the mirrors | |
739 * framework. | |
740 */ | |
741 class MirrorException implements Exception { | |
742 const MirrorException(String this._message); | |
743 String toString() => "MirrorException: '$_message'"; | |
744 final String _message; | |
745 } | |
OLD | NEW |