| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library test.services.completion.util; | 5 library test.services.completion.util; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, | 9 import 'package:analysis_server/src/protocol.dart' as protocol show Element, |
| 10 ElementKind; | 10 ElementKind; |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 | 452 |
| 453 // If the unit has been resolved, then finish the completion | 453 // If the unit has been resolved, then finish the completion |
| 454 LibraryElement library = context.getLibraryElement(testSource); | 454 LibraryElement library = context.getLibraryElement(testSource); |
| 455 if (library != null) { | 455 if (library != null) { |
| 456 CompilationUnit unit = | 456 CompilationUnit unit = |
| 457 context.getResolvedCompilationUnit(testSource, library); | 457 context.getResolvedCompilationUnit(testSource, library); |
| 458 if (unit != null) { | 458 if (unit != null) { |
| 459 request.unit = unit; | 459 request.unit = unit; |
| 460 request.node = | 460 request.node = |
| 461 new NodeLocator.con1(completionOffset).searchWithin(unit); | 461 new NodeLocator.con1(completionOffset).searchWithin(unit); |
| 462 if (request.node is SimpleIdentifier) { |
| 463 request.replacementOffset = request.node.offset; |
| 464 request.replacementLength = request.node.length; |
| 465 } else { |
| 466 request.replacementOffset = request.offset; |
| 467 request.replacementLength = 0; |
| 468 } |
| 469 if (request.replacementOffset == null) { |
| 470 fail('expected non null'); |
| 471 } |
| 462 resolved = true; | 472 resolved = true; |
| 463 if (!fullAnalysis) { | 473 if (!fullAnalysis) { |
| 464 break; | 474 break; |
| 465 } | 475 } |
| 466 } | 476 } |
| 467 } | 477 } |
| 468 | 478 |
| 469 result = context.performAnalysisTask(); | 479 result = context.performAnalysisTask(); |
| 470 } | 480 } |
| 471 if (!resolved) { | 481 if (!resolved) { |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 String bar() => true; | 883 String bar() => true; |
| 874 void main() {expect(foo: ^)}'''); | 884 void main() {expect(foo: ^)}'''); |
| 875 computeFast(); | 885 computeFast(); |
| 876 return computeFull((bool result) { | 886 return computeFull((bool result) { |
| 877 assertSuggestLocalFunction('bar', 'String'); | 887 assertSuggestLocalFunction('bar', 'String'); |
| 878 assertSuggestImportedFunction('hasLength', 'bool'); | 888 assertSuggestImportedFunction('hasLength', 'bool'); |
| 879 assertNotSuggested('main'); | 889 assertNotSuggested('main'); |
| 880 }); | 890 }); |
| 881 } | 891 } |
| 882 | 892 |
| 893 test_AsExpression() { |
| 894 // SimpleIdentifier TypeName AsExpression |
| 895 addTestSource(''' |
| 896 class A {var b; X _c; foo() {var a; (a as ^).foo();}'''); |
| 897 computeFast(); |
| 898 return computeFull((bool result) { |
| 899 assertNotSuggested('b'); |
| 900 assertNotSuggested('_c'); |
| 901 assertSuggestImportedClass('Object'); |
| 902 assertSuggestLocalClass('A'); |
| 903 assertNotSuggested('=='); |
| 904 }); |
| 905 } |
| 906 |
| 883 test_AssignmentExpression_name() { | 907 test_AssignmentExpression_name() { |
| 884 // SimpleIdentifier VariableDeclaration VariableDeclarationList | 908 // SimpleIdentifier VariableDeclaration VariableDeclarationList |
| 885 // VariableDeclarationStatement Block | 909 // VariableDeclarationStatement Block |
| 886 addTestSource('class A {} main() {int a; int ^b = 1;}'); | 910 addTestSource('class A {} main() {int a; int ^b = 1;}'); |
| 887 computeFast(); | 911 computeFast(); |
| 888 return computeFull((bool result) { | 912 return computeFull((bool result) { |
| 889 assertNoSuggestions(); | 913 assertNoSuggestions(); |
| 890 }); | 914 }); |
| 891 } | 915 } |
| 892 | 916 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 assertLocalSuggestMethod('b', 'X', 'void'); | 1018 assertLocalSuggestMethod('b', 'X', 'void'); |
| 995 assertSuggestLocalVariable('f', null); | 1019 assertSuggestLocalVariable('f', null); |
| 996 // Don't suggest locals out of scope | 1020 // Don't suggest locals out of scope |
| 997 assertNotSuggested('r'); | 1021 assertNotSuggested('r'); |
| 998 assertNotSuggested('x'); | 1022 assertNotSuggested('x'); |
| 999 | 1023 |
| 1000 assertSuggestImportedClass('A'); | 1024 assertSuggestImportedClass('A'); |
| 1001 assertNotSuggested('_B'); | 1025 assertNotSuggested('_B'); |
| 1002 assertSuggestImportedClass('C'); | 1026 assertSuggestImportedClass('C'); |
| 1003 // hidden element suggested as low relevance | 1027 // hidden element suggested as low relevance |
| 1004 assertSuggestImportedClass('D', CompletionRelevance.LOW); | 1028 // but imported results are partially filtered |
| 1005 assertSuggestImportedFunction('D1', null, true, CompletionRelevance.LOW); | 1029 //assertSuggestImportedClass('D', CompletionRelevance.LOW); |
| 1030 //assertSuggestImportedFunction('D1', null, true, CompletionRelevance.LOW)
; |
| 1006 assertSuggestLocalFunction('D2', 'Z'); | 1031 assertSuggestLocalFunction('D2', 'Z'); |
| 1007 assertSuggestImportedClass('EE'); | 1032 assertSuggestImportedClass('EE'); |
| 1008 // hidden element suggested as low relevance | 1033 // hidden element suggested as low relevance |
| 1009 assertSuggestImportedClass('F', CompletionRelevance.LOW); | 1034 //assertSuggestImportedClass('F', CompletionRelevance.LOW); |
| 1010 assertSuggestLibraryPrefix('g'); | 1035 assertSuggestLibraryPrefix('g'); |
| 1011 assertNotSuggested('G'); | 1036 assertNotSuggested('G'); |
| 1012 assertSuggestImportedClass('H', CompletionRelevance.LOW); | 1037 //assertSuggestImportedClass('H', CompletionRelevance.LOW); |
| 1013 assertSuggestImportedClass('Object'); | 1038 assertSuggestImportedClass('Object'); |
| 1014 assertSuggestImportedFunction('min', 'num', false); | 1039 assertSuggestImportedFunction('min', 'num', false); |
| 1015 assertSuggestImportedFunction( | 1040 //assertSuggestImportedFunction( |
| 1016 'max', | 1041 // 'max', |
| 1017 'num', | 1042 // 'num', |
| 1018 false, | 1043 // false, |
| 1019 CompletionRelevance.LOW); | 1044 // CompletionRelevance.LOW); |
| 1020 assertSuggestTopLevelVarGetterSetter('T1', 'String'); | 1045 assertSuggestTopLevelVarGetterSetter('T1', 'String'); |
| 1021 assertNotSuggested('_T2'); | 1046 assertNotSuggested('_T2'); |
| 1022 assertSuggestImportedTopLevelVar('T3', 'int', CompletionRelevance.LOW); | 1047 //assertSuggestImportedTopLevelVar('T3', 'int', CompletionRelevance.LOW); |
| 1023 assertNotSuggested('_T4'); | 1048 assertNotSuggested('_T4'); |
| 1024 assertSuggestLocalTopLevelVar('T5', 'int'); | 1049 assertSuggestLocalTopLevelVar('T5', 'int'); |
| 1025 assertSuggestLocalTopLevelVar('_T6', null); | 1050 assertSuggestLocalTopLevelVar('_T6', null); |
| 1026 assertNotSuggested('=='); | 1051 assertNotSuggested('=='); |
| 1027 // TODO (danrubel) suggest HtmlElement as low relevance | 1052 // TODO (danrubel) suggest HtmlElement as low relevance |
| 1028 assertNotSuggested('HtmlElement'); | 1053 assertNotSuggested('HtmlElement'); |
| 1029 }); | 1054 }); |
| 1030 } | 1055 } |
| 1031 | 1056 |
| 1057 test_Block_identifier_partial() { |
| 1058 addSource('/testAB.dart', ''' |
| 1059 export "dart:math" hide max; |
| 1060 class A {int x;} |
| 1061 @deprecated D1() {int x;} |
| 1062 class _B { }'''); |
| 1063 addSource('/testCD.dart', ''' |
| 1064 String T1; |
| 1065 var _T2; |
| 1066 class C { } |
| 1067 class D { }'''); |
| 1068 addSource('/testEEF.dart', ''' |
| 1069 class EE { } |
| 1070 class F { }'''); |
| 1071 addSource('/testG.dart', 'class G { }'); |
| 1072 addSource('/testH.dart', ''' |
| 1073 class H { } |
| 1074 int T3; |
| 1075 var _T4;'''); // not imported |
| 1076 addTestSource(''' |
| 1077 import "/testAB.dart"; |
| 1078 import "/testCD.dart" hide D; |
| 1079 import "/testEEF.dart" show EE; |
| 1080 import "/testG.dart" as g; |
| 1081 int T5; |
| 1082 var _T6; |
| 1083 Z D2() {int x;} |
| 1084 class X {a() {var f; {var x;} D^ var r;} void b() { }} |
| 1085 class Z { }'''); |
| 1086 computeFast(); |
| 1087 return computeFull((bool result) { |
| 1088 |
| 1089 assertSuggestLocalClass('X'); |
| 1090 assertSuggestLocalClass('Z'); |
| 1091 assertLocalSuggestMethod('a', 'X', null); |
| 1092 assertLocalSuggestMethod('b', 'X', 'void'); |
| 1093 assertSuggestLocalVariable('f', null); |
| 1094 // Don't suggest locals out of scope |
| 1095 assertNotSuggested('r'); |
| 1096 assertNotSuggested('x'); |
| 1097 |
| 1098 // imported elements are portially filtered |
| 1099 //assertSuggestImportedClass('A'); |
| 1100 assertNotSuggested('_B'); |
| 1101 //assertSuggestImportedClass('C'); |
| 1102 // hidden element suggested as low relevance |
| 1103 assertSuggestImportedClass('D', CompletionRelevance.LOW); |
| 1104 assertSuggestImportedFunction('D1', null, true, CompletionRelevance.LOW); |
| 1105 assertSuggestLocalFunction('D2', 'Z'); |
| 1106 //assertSuggestImportedClass('EE'); |
| 1107 // hidden element suggested as low relevance |
| 1108 //assertSuggestImportedClass('F', CompletionRelevance.LOW); |
| 1109 //assertSuggestLibraryPrefix('g'); |
| 1110 assertNotSuggested('G'); |
| 1111 //assertSuggestImportedClass('H', CompletionRelevance.LOW); |
| 1112 //assertSuggestImportedClass('Object'); |
| 1113 //assertSuggestImportedFunction('min', 'num', false); |
| 1114 //assertSuggestImportedFunction( |
| 1115 // 'max', |
| 1116 // 'num', |
| 1117 // false, |
| 1118 // CompletionRelevance.LOW); |
| 1119 //assertSuggestTopLevelVarGetterSetter('T1', 'String'); |
| 1120 assertNotSuggested('_T2'); |
| 1121 //assertSuggestImportedTopLevelVar('T3', 'int', CompletionRelevance.LOW); |
| 1122 assertNotSuggested('_T4'); |
| 1123 //assertSuggestLocalTopLevelVar('T5', 'int'); |
| 1124 //assertSuggestLocalTopLevelVar('_T6', null); |
| 1125 assertNotSuggested('=='); |
| 1126 // TODO (danrubel) suggest HtmlElement as low relevance |
| 1127 assertNotSuggested('HtmlElement'); |
| 1128 }); |
| 1129 } |
| 1130 |
| 1032 test_Block_inherited_imported() { | 1131 test_Block_inherited_imported() { |
| 1033 // Block BlockFunctionBody MethodDeclaration ClassDeclaration | 1132 // Block BlockFunctionBody MethodDeclaration ClassDeclaration |
| 1034 addSource('/testB.dart', ''' | 1133 addSource('/testB.dart', ''' |
| 1035 lib B; | 1134 lib B; |
| 1036 class F { var f1; f2() { } } | 1135 class F { var f1; f2() { } } |
| 1037 class E extends F { var e1; e2() { } } | 1136 class E extends F { var e1; e2() { } } |
| 1038 class I { int i1; i2() { } } | 1137 class I { int i1; i2() { } } |
| 1039 class M { var m1; int m2() { } }'''); | 1138 class M { var m1; int m2() { } }'''); |
| 1040 addTestSource(''' | 1139 addTestSource(''' |
| 1041 import "/testB.dart"; | 1140 import "/testB.dart"; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 class A {var b; X _c;} | 1249 class A {var b; X _c;} |
| 1151 class X{} | 1250 class X{} |
| 1152 main() {A a; a^..b}'''); | 1251 main() {A a; a^..b}'''); |
| 1153 computeFast(); | 1252 computeFast(); |
| 1154 return computeFull((bool result) { | 1253 return computeFull((bool result) { |
| 1155 assertNotSuggested('b'); | 1254 assertNotSuggested('b'); |
| 1156 assertNotSuggested('_c'); | 1255 assertNotSuggested('_c'); |
| 1157 assertSuggestLocalVariable('a', 'A'); | 1256 assertSuggestLocalVariable('a', 'A'); |
| 1158 assertSuggestLocalClass('A'); | 1257 assertSuggestLocalClass('A'); |
| 1159 assertSuggestLocalClass('X'); | 1258 assertSuggestLocalClass('X'); |
| 1160 assertSuggestImportedClass('Object'); | 1259 // top level results are partially filtered |
| 1260 //assertSuggestImportedClass('Object'); |
| 1161 assertNotSuggested('=='); | 1261 assertNotSuggested('=='); |
| 1162 }); | 1262 }); |
| 1163 } | 1263 } |
| 1164 | 1264 |
| 1165 test_CatchClause_typed() { | 1265 test_CatchClause_typed() { |
| 1166 // Block CatchClause TryStatement | 1266 // Block CatchClause TryStatement |
| 1167 addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}'); | 1267 addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}'); |
| 1168 computeFast(); | 1268 computeFast(); |
| 1169 return computeFull((bool result) { | 1269 return computeFull((bool result) { |
| 1170 assertSuggestParameter('e', 'E'); | 1270 assertSuggestParameter('e', 'E'); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 test_ExpressionStatement_identifier() { | 1444 test_ExpressionStatement_identifier() { |
| 1345 // SimpleIdentifier ExpressionStatement Block | 1445 // SimpleIdentifier ExpressionStatement Block |
| 1346 addSource('/testA.dart', ''' | 1446 addSource('/testA.dart', ''' |
| 1347 _B F1() { } | 1447 _B F1() { } |
| 1348 class A {int x;} | 1448 class A {int x;} |
| 1349 class _B { }'''); | 1449 class _B { }'''); |
| 1350 addTestSource(''' | 1450 addTestSource(''' |
| 1351 import "/testA.dart"; | 1451 import "/testA.dart"; |
| 1352 typedef int F2(int blat); | 1452 typedef int F2(int blat); |
| 1353 class Clz = Object with Object; | 1453 class Clz = Object with Object; |
| 1354 class C {foo(){O^} void bar() {}}'''); | 1454 class C {foo(){^} void bar() {}}'''); |
| 1355 computeFast(); | 1455 computeFast(); |
| 1356 return computeFull((bool result) { | 1456 return computeFull((bool result) { |
| 1357 assertSuggestImportedClass('A'); | 1457 assertSuggestImportedClass('A'); |
| 1358 assertSuggestImportedFunction('F1', '_B', false); | 1458 assertSuggestImportedFunction('F1', '_B', false); |
| 1359 assertSuggestLocalClass('C'); | 1459 assertSuggestLocalClass('C'); |
| 1360 assertSuggestLocalMethod('foo', 'C', null); | 1460 assertSuggestLocalMethod('foo', 'C', null); |
| 1361 assertSuggestLocalMethod('bar', 'C', 'void'); | 1461 assertSuggestLocalMethod('bar', 'C', 'void'); |
| 1362 assertSuggestLocalFunctionTypeAlias('F2', 'int'); | 1462 assertSuggestLocalFunctionTypeAlias('F2', 'int'); |
| 1363 assertSuggestLocalClassTypeAlias('Clz'); | 1463 assertSuggestLocalClassTypeAlias('Clz'); |
| 1364 assertSuggestLocalClass('C'); | 1464 assertSuggestLocalClass('C'); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1576 assertSuggestImportedClass('Object'); | 1676 assertSuggestImportedClass('Object'); |
| 1577 }); | 1677 }); |
| 1578 } | 1678 } |
| 1579 | 1679 |
| 1580 test_InterpolationExpression_block() { | 1680 test_InterpolationExpression_block() { |
| 1581 // SimpleIdentifier InterpolationExpression StringInterpolation | 1681 // SimpleIdentifier InterpolationExpression StringInterpolation |
| 1582 addTestSource('main() {String name; print("hello \${n^}");}'); | 1682 addTestSource('main() {String name; print("hello \${n^}");}'); |
| 1583 computeFast(); | 1683 computeFast(); |
| 1584 return computeFull((bool result) { | 1684 return computeFull((bool result) { |
| 1585 assertSuggestLocalVariable('name', 'String'); | 1685 assertSuggestLocalVariable('name', 'String'); |
| 1586 assertSuggestImportedClass('Object'); | 1686 // top level results are partially filtered |
| 1687 //assertSuggestImportedClass('Object'); |
| 1587 }); | 1688 }); |
| 1588 } | 1689 } |
| 1589 | 1690 |
| 1590 test_InterpolationExpression_prefix_selector() { | 1691 test_InterpolationExpression_prefix_selector() { |
| 1591 // SimpleIdentifier PrefixedIdentifier InterpolationExpression | 1692 // SimpleIdentifier PrefixedIdentifier InterpolationExpression |
| 1592 addTestSource('main() {String name; print("hello \${name.^}");}'); | 1693 addTestSource('main() {String name; print("hello \${name.^}");}'); |
| 1593 computeFast(); | 1694 computeFast(); |
| 1594 return computeFull((bool result) { | 1695 return computeFull((bool result) { |
| 1595 assertSuggestInvocationGetter('length', 'int'); | 1696 assertSuggestInvocationGetter('length', 'int'); |
| 1596 assertNotSuggested('name'); | 1697 assertNotSuggested('name'); |
| 1597 assertNotSuggested('Object'); | 1698 assertNotSuggested('Object'); |
| 1598 assertNotSuggested('=='); | 1699 assertNotSuggested('=='); |
| 1599 }); | 1700 }); |
| 1600 } | 1701 } |
| 1601 | 1702 |
| 1602 test_InterpolationExpression_prefix_target() { | 1703 test_InterpolationExpression_prefix_target() { |
| 1603 // SimpleIdentifier PrefixedIdentifier InterpolationExpression | 1704 // SimpleIdentifier PrefixedIdentifier InterpolationExpression |
| 1604 addTestSource('main() {String name; print("hello \${nam^e.length}");}'); | 1705 addTestSource('main() {String name; print("hello \${nam^e.length}");}'); |
| 1605 computeFast(); | 1706 computeFast(); |
| 1606 return computeFull((bool result) { | 1707 return computeFull((bool result) { |
| 1607 assertSuggestLocalVariable('name', 'String'); | 1708 assertSuggestLocalVariable('name', 'String'); |
| 1608 assertSuggestImportedClass('Object'); | 1709 // top level results are partially filtered |
| 1710 //assertSuggestImportedClass('Object'); |
| 1609 assertNotSuggested('length'); | 1711 assertNotSuggested('length'); |
| 1610 }); | 1712 }); |
| 1611 } | 1713 } |
| 1612 | 1714 |
| 1613 test_IsExpression() { | 1715 test_IsExpression() { |
| 1614 // SimpleIdentifier TypeName IsExpression IfStatement | 1716 // SimpleIdentifier TypeName IsExpression IfStatement |
| 1615 addSource('/testB.dart', ''' | 1717 addSource('/testB.dart', ''' |
| 1616 lib B; | 1718 lib B; |
| 1617 foo() { } | 1719 foo() { } |
| 1618 class X {X.c(); X._d(); z() {}}'''); | 1720 class X {X.c(); X._d(); z() {}}'''); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 main(){var a; if (a is ^)}'''); | 1757 main(){var a; if (a is ^)}'''); |
| 1656 computeFast(); | 1758 computeFast(); |
| 1657 return computeFull((bool result) { | 1759 return computeFull((bool result) { |
| 1658 assertNotSuggested('a'); | 1760 assertNotSuggested('a'); |
| 1659 assertNotSuggested('main'); | 1761 assertNotSuggested('main'); |
| 1660 assertSuggestLocalClass('A'); | 1762 assertSuggestLocalClass('A'); |
| 1661 assertSuggestImportedClass('Object'); | 1763 assertSuggestImportedClass('Object'); |
| 1662 }); | 1764 }); |
| 1663 } | 1765 } |
| 1664 | 1766 |
| 1767 test_IsExpression_type_partial() { |
| 1768 // SimpleIdentifier TypeName IsExpression IfStatement |
| 1769 addTestSource(''' |
| 1770 class A {int x; int y() => 0;} |
| 1771 main(){var a; if (a is Obj^)}'''); |
| 1772 computeFast(); |
| 1773 return computeFull((bool result) { |
| 1774 assertNotSuggested('a'); |
| 1775 assertNotSuggested('main'); |
| 1776 assertSuggestLocalClass('A'); |
| 1777 assertSuggestImportedClass('Object'); |
| 1778 }); |
| 1779 } |
| 1780 |
| 1665 test_Literal_string() { | 1781 test_Literal_string() { |
| 1666 // SimpleStringLiteral ExpressionStatement Block | 1782 // SimpleStringLiteral ExpressionStatement Block |
| 1667 addTestSource('class A {a() {"hel^lo"}}'); | 1783 addTestSource('class A {a() {"hel^lo"}}'); |
| 1668 computeFast(); | 1784 computeFast(); |
| 1669 return computeFull((bool result) { | 1785 return computeFull((bool result) { |
| 1670 assertNoSuggestions(); | 1786 assertNoSuggestions(); |
| 1671 }); | 1787 }); |
| 1672 } | 1788 } |
| 1673 | 1789 |
| 1674 test_MethodDeclaration_body_getters() { | 1790 test_MethodDeclaration_body_getters() { |
| (...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2085 assertNotSuggested('bar2'); | 2201 assertNotSuggested('bar2'); |
| 2086 assertNotSuggested('_B'); | 2202 assertNotSuggested('_B'); |
| 2087 assertSuggestLocalClass('Y'); | 2203 assertSuggestLocalClass('Y'); |
| 2088 assertSuggestLocalClass('C'); | 2204 assertSuggestLocalClass('C'); |
| 2089 assertSuggestLocalVariable('f', null); | 2205 assertSuggestLocalVariable('f', null); |
| 2090 assertNotSuggested('x'); | 2206 assertNotSuggested('x'); |
| 2091 assertNotSuggested('e'); | 2207 assertNotSuggested('e'); |
| 2092 }); | 2208 }); |
| 2093 } | 2209 } |
| 2094 } | 2210 } |
| OLD | NEW |