pattern_test.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright 2007 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.dom.patternTest');
  15. goog.setTestOnly('goog.dom.patternTest');
  16. goog.require('goog.dom');
  17. goog.require('goog.dom.NodeType');
  18. goog.require('goog.dom.TagWalkType');
  19. goog.require('goog.dom.pattern.AllChildren');
  20. goog.require('goog.dom.pattern.ChildMatches');
  21. goog.require('goog.dom.pattern.EndTag');
  22. goog.require('goog.dom.pattern.FullTag');
  23. goog.require('goog.dom.pattern.MatchType');
  24. goog.require('goog.dom.pattern.NodeType');
  25. goog.require('goog.dom.pattern.Repeat');
  26. goog.require('goog.dom.pattern.Sequence');
  27. goog.require('goog.dom.pattern.StartTag');
  28. goog.require('goog.dom.pattern.Text');
  29. goog.require('goog.testing.jsunit');
  30. // TODO(robbyw): write a test that checks if backtracking works in Sequence
  31. function testStartTag() {
  32. var pattern = new goog.dom.pattern.StartTag('DIV');
  33. assertEquals(
  34. 'StartTag(div) should match div', goog.dom.pattern.MatchType.MATCH,
  35. pattern.matchToken(
  36. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  37. assertEquals(
  38. 'StartTag(div) should not match span',
  39. goog.dom.pattern.MatchType.NO_MATCH,
  40. pattern.matchToken(
  41. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  42. assertEquals(
  43. 'StartTag(div) should not match /div',
  44. goog.dom.pattern.MatchType.NO_MATCH,
  45. pattern.matchToken(
  46. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  47. }
  48. function testStartTagCase() {
  49. var pattern = new goog.dom.pattern.StartTag('diV');
  50. assertEquals(
  51. 'StartTag(diV) should match div', goog.dom.pattern.MatchType.MATCH,
  52. pattern.matchToken(
  53. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  54. assertEquals(
  55. 'StartTag(diV) should not match span',
  56. goog.dom.pattern.MatchType.NO_MATCH,
  57. pattern.matchToken(
  58. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  59. }
  60. function testStartTagRegex() {
  61. var pattern = new goog.dom.pattern.StartTag(/D/);
  62. assertEquals(
  63. 'StartTag(/D/) should match div', goog.dom.pattern.MatchType.MATCH,
  64. pattern.matchToken(
  65. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  66. assertEquals(
  67. 'StartTag(/D/) should not match span',
  68. goog.dom.pattern.MatchType.NO_MATCH,
  69. pattern.matchToken(
  70. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  71. assertEquals(
  72. 'StartTag(/D/) should not match /div',
  73. goog.dom.pattern.MatchType.NO_MATCH,
  74. pattern.matchToken(
  75. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  76. }
  77. function testStartTagAttributes() {
  78. var pattern = new goog.dom.pattern.StartTag('DIV', {id: 'div1'});
  79. assertEquals(
  80. 'StartTag(div,id:div1) should match div1',
  81. goog.dom.pattern.MatchType.MATCH,
  82. pattern.matchToken(
  83. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  84. assertEquals(
  85. 'StartTag(div,id:div2) should not match div1',
  86. goog.dom.pattern.MatchType.NO_MATCH,
  87. pattern.matchToken(
  88. goog.dom.getElement('div2'), goog.dom.TagWalkType.START_TAG));
  89. }
  90. function testStartTagStyle() {
  91. var pattern = new goog.dom.pattern.StartTag('SPAN', null, {color: 'red'});
  92. assertEquals(
  93. 'StartTag(span,null,color:red) should match span1',
  94. goog.dom.pattern.MatchType.MATCH,
  95. pattern.matchToken(
  96. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  97. assertEquals(
  98. 'StartTag(span,null,color:blue) should not match span1',
  99. goog.dom.pattern.MatchType.NO_MATCH,
  100. pattern.matchToken(
  101. goog.dom.getElement('span2'), goog.dom.TagWalkType.START_TAG));
  102. }
  103. function testStartTagAttributeRegex() {
  104. var pattern = new goog.dom.pattern.StartTag('SPAN', {id: /span\d/});
  105. assertEquals(
  106. 'StartTag(span,id:/span\\d/) should match span1',
  107. goog.dom.pattern.MatchType.MATCH,
  108. pattern.matchToken(
  109. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  110. assertEquals(
  111. 'StartTag(span,id:/span\\d/) should match span2',
  112. goog.dom.pattern.MatchType.MATCH,
  113. pattern.matchToken(
  114. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  115. }
  116. function testEndTag() {
  117. var pattern = new goog.dom.pattern.EndTag('DIV');
  118. assertEquals(
  119. 'EndTag should match div', goog.dom.pattern.MatchType.MATCH,
  120. pattern.matchToken(
  121. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  122. }
  123. function testEndTagRegex() {
  124. var pattern = new goog.dom.pattern.EndTag(/D/);
  125. assertEquals(
  126. 'EndTag(/D/) should match /div', goog.dom.pattern.MatchType.MATCH,
  127. pattern.matchToken(
  128. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  129. assertEquals(
  130. 'EndTag(/D/) should not match /span', goog.dom.pattern.MatchType.NO_MATCH,
  131. pattern.matchToken(
  132. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  133. assertEquals(
  134. 'EndTag(/D/) should not match div', goog.dom.pattern.MatchType.NO_MATCH,
  135. pattern.matchToken(
  136. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  137. }
  138. function testChildMatches() {
  139. var pattern = new goog.dom.pattern.ChildMatches(
  140. new goog.dom.pattern.StartTag('DIV'), 2);
  141. assertEquals(
  142. 'ChildMatches should match div', goog.dom.pattern.MatchType.MATCHING,
  143. pattern.matchToken(
  144. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  145. assertEquals(
  146. 'ChildMatches should match /div', goog.dom.pattern.MatchType.MATCHING,
  147. pattern.matchToken(
  148. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  149. assertEquals(
  150. 'ChildMatches should match div', goog.dom.pattern.MatchType.MATCHING,
  151. pattern.matchToken(
  152. goog.dom.getElement('div2'), goog.dom.TagWalkType.START_TAG));
  153. assertEquals(
  154. 'ChildMatches should match /div', goog.dom.pattern.MatchType.MATCHING,
  155. pattern.matchToken(
  156. goog.dom.getElement('div2'), goog.dom.TagWalkType.END_TAG));
  157. assertEquals(
  158. 'ChildMatches should finish match at /body',
  159. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  160. pattern.matchToken(document.body, goog.dom.TagWalkType.END_TAG));
  161. assertEquals(
  162. 'ChildMatches should match div', goog.dom.pattern.MatchType.MATCHING,
  163. pattern.matchToken(
  164. goog.dom.getElement('div2'), goog.dom.TagWalkType.START_TAG));
  165. assertEquals(
  166. 'ChildMatches should match /div', goog.dom.pattern.MatchType.MATCHING,
  167. pattern.matchToken(
  168. goog.dom.getElement('div2'), goog.dom.TagWalkType.END_TAG));
  169. assertEquals(
  170. 'ChildMatches should fail to match at /body: not enough child matches',
  171. goog.dom.pattern.MatchType.NO_MATCH,
  172. pattern.matchToken(document.body, goog.dom.TagWalkType.END_TAG));
  173. }
  174. function testFullTag() {
  175. var pattern = new goog.dom.pattern.FullTag('DIV');
  176. assertEquals(
  177. 'FullTag(div) should match div', goog.dom.pattern.MatchType.MATCHING,
  178. pattern.matchToken(
  179. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  180. assertEquals(
  181. 'FullTag(div) should match /div', goog.dom.pattern.MatchType.MATCH,
  182. pattern.matchToken(
  183. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  184. assertEquals(
  185. 'FullTag(div) should start match at div',
  186. goog.dom.pattern.MatchType.MATCHING,
  187. pattern.matchToken(
  188. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  189. assertEquals(
  190. 'FullTag(div) should continue to match span',
  191. goog.dom.pattern.MatchType.MATCHING,
  192. pattern.matchToken(
  193. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  194. assertEquals(
  195. 'FullTag(div) should continue to match /span',
  196. goog.dom.pattern.MatchType.MATCHING,
  197. pattern.matchToken(
  198. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  199. assertEquals(
  200. 'FullTag(div) should finish match at /div',
  201. goog.dom.pattern.MatchType.MATCH,
  202. pattern.matchToken(
  203. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  204. }
  205. function testAllChildren() {
  206. var pattern = new goog.dom.pattern.AllChildren();
  207. assertEquals(
  208. 'AllChildren(div) should match div', goog.dom.pattern.MatchType.MATCHING,
  209. pattern.matchToken(
  210. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  211. assertEquals(
  212. 'AllChildren(div) should match /div', goog.dom.pattern.MatchType.MATCHING,
  213. pattern.matchToken(
  214. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  215. assertEquals(
  216. 'AllChildren(div) should match at /body',
  217. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  218. pattern.matchToken(document.body, goog.dom.TagWalkType.END_TAG));
  219. assertEquals(
  220. 'AllChildren(div) should start match at div',
  221. goog.dom.pattern.MatchType.MATCHING,
  222. pattern.matchToken(
  223. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  224. assertEquals(
  225. 'AllChildren(div) should continue to match span',
  226. goog.dom.pattern.MatchType.MATCHING,
  227. pattern.matchToken(
  228. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  229. assertEquals(
  230. 'AllChildren(div) should continue to match /span',
  231. goog.dom.pattern.MatchType.MATCHING,
  232. pattern.matchToken(
  233. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  234. assertEquals(
  235. 'AllChildren(div) should continue to match at /div',
  236. goog.dom.pattern.MatchType.MATCHING,
  237. pattern.matchToken(
  238. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  239. assertEquals(
  240. 'AllChildren(div) should finish match at /body',
  241. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  242. pattern.matchToken(document.body, goog.dom.TagWalkType.END_TAG));
  243. }
  244. function testText() {
  245. var pattern = new goog.dom.pattern.Text('Text');
  246. assertEquals(
  247. 'Text should match div3/text()', goog.dom.pattern.MatchType.MATCH,
  248. pattern.matchToken(
  249. goog.dom.getElement('div3').firstChild, goog.dom.TagWalkType.OTHER));
  250. assertEquals(
  251. 'Text should not match div4/text()', goog.dom.pattern.MatchType.NO_MATCH,
  252. pattern.matchToken(
  253. goog.dom.getElement('div4').firstChild, goog.dom.TagWalkType.OTHER));
  254. assertEquals(
  255. 'Text should not match div3', goog.dom.pattern.MatchType.NO_MATCH,
  256. pattern.matchToken(
  257. goog.dom.getElement('div3'), goog.dom.TagWalkType.START_TAG));
  258. }
  259. function testTextRegex() {
  260. var pattern = new goog.dom.pattern.Text(/Text/);
  261. assertEquals(
  262. 'Text(regex) should match div3/text()', goog.dom.pattern.MatchType.MATCH,
  263. pattern.matchToken(
  264. goog.dom.getElement('div3').firstChild, goog.dom.TagWalkType.OTHER));
  265. assertEquals(
  266. 'Text(regex) should match div4/text()', goog.dom.pattern.MatchType.MATCH,
  267. pattern.matchToken(
  268. goog.dom.getElement('div4').firstChild, goog.dom.TagWalkType.OTHER));
  269. }
  270. function testNodeType() {
  271. var pattern = new goog.dom.pattern.NodeType(goog.dom.NodeType.COMMENT);
  272. assertEquals(
  273. 'Comment matcher should match a comment',
  274. goog.dom.pattern.MatchType.MATCH,
  275. pattern.matchToken(
  276. goog.dom.getElement('nodeTypes').firstChild,
  277. goog.dom.TagWalkType.OTHER));
  278. assertEquals(
  279. 'Comment matcher should not match a text node',
  280. goog.dom.pattern.MatchType.NO_MATCH,
  281. pattern.matchToken(
  282. goog.dom.getElement('nodeTypes').lastChild,
  283. goog.dom.TagWalkType.OTHER));
  284. }
  285. function testSequence() {
  286. var pattern = new goog.dom.pattern.Sequence([
  287. new goog.dom.pattern.StartTag('DIV'), new goog.dom.pattern.StartTag('SPAN'),
  288. new goog.dom.pattern.EndTag('SPAN'), new goog.dom.pattern.EndTag('DIV')
  289. ]);
  290. assertEquals(
  291. 'Sequence[0] should match div1', goog.dom.pattern.MatchType.MATCHING,
  292. pattern.matchToken(
  293. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  294. assertEquals(
  295. 'Sequence[1] should match span1', goog.dom.pattern.MatchType.MATCHING,
  296. pattern.matchToken(
  297. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  298. assertEquals(
  299. 'Sequence[2] should match /span1', goog.dom.pattern.MatchType.MATCHING,
  300. pattern.matchToken(
  301. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  302. assertEquals(
  303. 'Sequence[3] should match /div1', goog.dom.pattern.MatchType.MATCH,
  304. pattern.matchToken(
  305. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  306. assertEquals(
  307. 'Sequence[0] should match div1 again',
  308. goog.dom.pattern.MatchType.MATCHING,
  309. pattern.matchToken(
  310. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  311. assertEquals(
  312. 'Sequence[1] should match span1 again',
  313. goog.dom.pattern.MatchType.MATCHING,
  314. pattern.matchToken(
  315. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  316. assertEquals(
  317. 'Sequence[2] should match /span1 again',
  318. goog.dom.pattern.MatchType.MATCHING,
  319. pattern.matchToken(
  320. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  321. assertEquals(
  322. 'Sequence[3] should match /div1 again', goog.dom.pattern.MatchType.MATCH,
  323. pattern.matchToken(
  324. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  325. assertEquals(
  326. 'Sequence[0] should match div1', goog.dom.pattern.MatchType.MATCHING,
  327. pattern.matchToken(
  328. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  329. assertEquals(
  330. 'Sequence[1] should not match div1', goog.dom.pattern.MatchType.NO_MATCH,
  331. pattern.matchToken(
  332. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  333. assertEquals(
  334. 'Sequence[0] should match div1 after failure',
  335. goog.dom.pattern.MatchType.MATCHING,
  336. pattern.matchToken(
  337. goog.dom.getElement('div1'), goog.dom.TagWalkType.START_TAG));
  338. assertEquals(
  339. 'Sequence[1] should match span1 after failure',
  340. goog.dom.pattern.MatchType.MATCHING,
  341. pattern.matchToken(
  342. goog.dom.getElement('span1'), goog.dom.TagWalkType.START_TAG));
  343. assertEquals(
  344. 'Sequence[2] should match /span1 after failure',
  345. goog.dom.pattern.MatchType.MATCHING,
  346. pattern.matchToken(
  347. goog.dom.getElement('span1'), goog.dom.TagWalkType.END_TAG));
  348. assertEquals(
  349. 'Sequence[3] should match /div1 after failure',
  350. goog.dom.pattern.MatchType.MATCH,
  351. pattern.matchToken(
  352. goog.dom.getElement('div1'), goog.dom.TagWalkType.END_TAG));
  353. }
  354. function testRepeat() {
  355. var pattern = new goog.dom.pattern.Repeat(new goog.dom.pattern.StartTag('B'));
  356. // Note: this test does not mimic an actual matcher because it is only
  357. // passing the START_TAG events.
  358. assertEquals(
  359. 'Repeat[B] should match b1', goog.dom.pattern.MatchType.MATCHING,
  360. pattern.matchToken(
  361. goog.dom.getElement('b1'), goog.dom.TagWalkType.START_TAG));
  362. assertEquals(
  363. 'Repeat[B] should match b2', goog.dom.pattern.MatchType.MATCHING,
  364. pattern.matchToken(
  365. goog.dom.getElement('b2'), goog.dom.TagWalkType.START_TAG));
  366. assertEquals(
  367. 'Repeat[B] should backtrack match i1',
  368. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  369. pattern.matchToken(
  370. goog.dom.getElement('i1'), goog.dom.TagWalkType.START_TAG));
  371. assertEquals('Repeat[B] should have match count of 2', 2, pattern.count);
  372. assertEquals(
  373. 'Repeat[B] should backtrack match i1 even with no b matches',
  374. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  375. pattern.matchToken(
  376. goog.dom.getElement('i1'), goog.dom.TagWalkType.START_TAG));
  377. assertEquals('Repeat[B] should have match count of 0', 0, pattern.count);
  378. }
  379. function testRepeatWithMinimum() {
  380. var pattern =
  381. new goog.dom.pattern.Repeat(new goog.dom.pattern.StartTag('B'), 1);
  382. // Note: this test does not mimic an actual matcher because it is only
  383. // passing the START_TAG events.
  384. assertEquals(
  385. 'Repeat[B,1] should match b1', goog.dom.pattern.MatchType.MATCHING,
  386. pattern.matchToken(
  387. goog.dom.getElement('b1'), goog.dom.TagWalkType.START_TAG));
  388. assertEquals(
  389. 'Repeat[B,1] should match b2', goog.dom.pattern.MatchType.MATCHING,
  390. pattern.matchToken(
  391. goog.dom.getElement('b2'), goog.dom.TagWalkType.START_TAG));
  392. assertEquals(
  393. 'Repeat[B,1] should backtrack match i1',
  394. goog.dom.pattern.MatchType.BACKTRACK_MATCH,
  395. pattern.matchToken(
  396. goog.dom.getElement('i1'), goog.dom.TagWalkType.START_TAG));
  397. assertEquals('Repeat[B,1] should have match count of 2', 2, pattern.count);
  398. assertEquals(
  399. 'Repeat[B,1] should not match i1', goog.dom.pattern.MatchType.NO_MATCH,
  400. pattern.matchToken(
  401. goog.dom.getElement('i1'), goog.dom.TagWalkType.START_TAG));
  402. }
  403. function testRepeatWithMaximum() {
  404. var pattern =
  405. new goog.dom.pattern.Repeat(new goog.dom.pattern.StartTag('B'), 1, 1);
  406. // Note: this test does not mimic an actual matcher because it is only
  407. // passing the START_TAG events.
  408. assertEquals(
  409. 'Repeat[B,1] should match b1', goog.dom.pattern.MatchType.MATCH,
  410. pattern.matchToken(
  411. goog.dom.getElement('b1'), goog.dom.TagWalkType.START_TAG));
  412. }
  413. function testSequenceBacktrack() {
  414. var pattern = new goog.dom.pattern.Sequence([
  415. new goog.dom.pattern.Repeat(new goog.dom.pattern.StartTag('SPAN')),
  416. new goog.dom.pattern.Text('X')
  417. ]);
  418. var root = goog.dom.getElement('span3');
  419. assertEquals(
  420. 'Sequence[Repeat[SPAN],"X"] should match span3',
  421. goog.dom.pattern.MatchType.MATCHING,
  422. pattern.matchToken(root, goog.dom.TagWalkType.START_TAG));
  423. assertEquals(
  424. 'Sequence[Repeat[SPAN],"X"] should match span3.firstChild',
  425. goog.dom.pattern.MatchType.MATCHING,
  426. pattern.matchToken(root.firstChild, goog.dom.TagWalkType.START_TAG));
  427. assertEquals(
  428. 'Sequence[Repeat[SPAN],"X"] should match span3.firstChild.firstChild',
  429. goog.dom.pattern.MatchType.MATCHING,
  430. pattern.matchToken(
  431. root.firstChild.firstChild, goog.dom.TagWalkType.START_TAG));
  432. assertEquals(
  433. 'Sequence[Repeat[SPAN],"X"] should finish match text node',
  434. goog.dom.pattern.MatchType.MATCH,
  435. pattern.matchToken(
  436. root.firstChild.firstChild.firstChild, goog.dom.TagWalkType.OTHER));
  437. }