ContextMenuTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. using System.Globalization;
  2. using System.Threading;
  3. using Xunit;
  4. using Xunit.Abstractions;
  5. using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
  6. namespace Terminal.Gui.Core {
  7. public class ContextMenuTests {
  8. readonly ITestOutputHelper output;
  9. public ContextMenuTests (ITestOutputHelper output)
  10. {
  11. this.output = output;
  12. }
  13. [Fact]
  14. [AutoInitShutdown]
  15. public void ContextMenu_Constructors ()
  16. {
  17. var cm = new ContextMenu ();
  18. Assert.Equal (new Point (0, 0), cm.Position);
  19. Assert.Empty (cm.MenuItems.Children);
  20. Assert.Null (cm.Host);
  21. cm.Position = new Point (20, 10);
  22. cm.MenuItems = new MenuBarItem (new MenuItem [] {
  23. new MenuItem ("First", "", null)
  24. });
  25. Assert.Equal (new Point (20, 10), cm.Position);
  26. Assert.Single (cm.MenuItems.Children);
  27. cm = new ContextMenu (5, 10,
  28. new MenuBarItem (new MenuItem [] {
  29. new MenuItem ("One", "", null),
  30. new MenuItem ("Two", "", null)
  31. })
  32. );
  33. Assert.Equal (new Point (5, 10), cm.Position);
  34. Assert.Equal (2, cm.MenuItems.Children.Length);
  35. Assert.Null (cm.Host);
  36. cm = new ContextMenu (new View () { X = 5, Y = 10 },
  37. new MenuBarItem (new MenuItem [] {
  38. new MenuItem ("One", "", null),
  39. new MenuItem ("Two", "", null)
  40. })
  41. );
  42. Assert.Equal (new Point (5, 10), cm.Position);
  43. Assert.Equal (2, cm.MenuItems.Children.Length);
  44. Assert.NotNull (cm.Host);
  45. }
  46. [Fact]
  47. [AutoInitShutdown]
  48. public void Show_Hide_IsShow ()
  49. {
  50. var cm = new ContextMenu (10, 5,
  51. new MenuBarItem (new MenuItem [] {
  52. new MenuItem ("One", "", null),
  53. new MenuItem ("Two", "", null)
  54. })
  55. );
  56. cm.Show ();
  57. Assert.True (ContextMenu.IsShow);
  58. Application.Begin (Application.Top);
  59. var expected = @"
  60. ┌──────┐
  61. │ One │
  62. │ Two │
  63. └──────┘
  64. ";
  65. GraphViewTests.AssertDriverContentsAre (expected, output);
  66. cm.Hide ();
  67. Assert.False (ContextMenu.IsShow);
  68. Application.Refresh ();
  69. expected = "";
  70. GraphViewTests.AssertDriverContentsAre (expected, output);
  71. }
  72. [Fact]
  73. [AutoInitShutdown]
  74. public void Position_Changing ()
  75. {
  76. var cm = new ContextMenu (10, 5,
  77. new MenuBarItem (new MenuItem [] {
  78. new MenuItem ("One", "", null),
  79. new MenuItem ("Two", "", null)
  80. })
  81. );
  82. cm.Show ();
  83. Application.Begin (Application.Top);
  84. var expected = @"
  85. ┌──────┐
  86. │ One │
  87. │ Two │
  88. └──────┘
  89. ";
  90. GraphViewTests.AssertDriverContentsAre (expected, output);
  91. cm.Position = new Point (5, 10);
  92. cm.Show ();
  93. Application.Refresh ();
  94. expected = @"
  95. ┌──────┐
  96. │ One │
  97. │ Two │
  98. └──────┘
  99. ";
  100. GraphViewTests.AssertDriverContentsAre (expected, output);
  101. }
  102. [Fact]
  103. [AutoInitShutdown]
  104. public void MenuItens_Changing ()
  105. {
  106. var cm = new ContextMenu (10, 5,
  107. new MenuBarItem (new MenuItem [] {
  108. new MenuItem ("One", "", null),
  109. new MenuItem ("Two", "", null)
  110. })
  111. );
  112. cm.Show ();
  113. Application.Begin (Application.Top);
  114. var expected = @"
  115. ┌──────┐
  116. │ One │
  117. │ Two │
  118. └──────┘
  119. ";
  120. GraphViewTests.AssertDriverContentsAre (expected, output);
  121. cm.MenuItems = new MenuBarItem (new MenuItem [] {
  122. new MenuItem ("First", "", null),
  123. new MenuItem ("Second", "", null),
  124. new MenuItem ("Third", "", null)
  125. });
  126. cm.Show ();
  127. Application.Refresh ();
  128. expected = @"
  129. ┌─────────┐
  130. │ First │
  131. │ Second │
  132. │ Third │
  133. └─────────┘
  134. ";
  135. GraphViewTests.AssertDriverContentsAre (expected, output);
  136. }
  137. [Fact, AutoInitShutdown]
  138. public void Key_Changing ()
  139. {
  140. var lbl = new Label ("Original");
  141. var cm = new ContextMenu ();
  142. lbl.KeyPress += (e) => {
  143. if (e.KeyEvent.Key == cm.Key) {
  144. lbl.Text = "Replaced";
  145. e.Handled = true;
  146. }
  147. };
  148. var top = Application.Top;
  149. top.Add (lbl);
  150. Application.Begin (top);
  151. Assert.True (lbl.ProcessKey (new KeyEvent (cm.Key, new KeyModifiers ())));
  152. Assert.Equal ("Replaced", lbl.Text);
  153. lbl.Text = "Original";
  154. cm.Key = Key.Space | Key.CtrlMask;
  155. Assert.True (lbl.ProcessKey (new KeyEvent (cm.Key, new KeyModifiers ())));
  156. Assert.Equal ("Replaced", lbl.Text);
  157. }
  158. [Fact, AutoInitShutdown]
  159. public void MouseFlags_Changing ()
  160. {
  161. var lbl = new Label ("Original");
  162. var cm = new ContextMenu ();
  163. lbl.MouseClick += (e) => {
  164. if (e.MouseEvent.Flags == cm.MouseFlags) {
  165. lbl.Text = "Replaced";
  166. e.Handled = true;
  167. }
  168. };
  169. var top = Application.Top;
  170. top.Add (lbl);
  171. Application.Begin (top);
  172. Assert.True (lbl.OnMouseEvent (new MouseEvent () { Flags = cm.MouseFlags }));
  173. Assert.Equal ("Replaced", lbl.Text);
  174. lbl.Text = "Original";
  175. cm.MouseFlags = MouseFlags.Button2Clicked;
  176. Assert.True (lbl.OnMouseEvent (new MouseEvent () { Flags = cm.MouseFlags }));
  177. Assert.Equal ("Replaced", lbl.Text);
  178. }
  179. [Fact, AutoInitShutdown]
  180. public void KeyChanged_Event ()
  181. {
  182. var oldKey = Key.Null;
  183. var cm = new ContextMenu ();
  184. cm.KeyChanged += (e) => oldKey = e;
  185. cm.Key = Key.Space | Key.CtrlMask;
  186. Assert.Equal (Key.Space | Key.CtrlMask, cm.Key);
  187. Assert.Equal (Key.F10 | Key.ShiftMask, oldKey);
  188. }
  189. [Fact, AutoInitShutdown]
  190. public void MouseFlagsChanged_Event ()
  191. {
  192. var oldMouseFlags = new MouseFlags ();
  193. var cm = new ContextMenu ();
  194. cm.MouseFlagsChanged += (e) => oldMouseFlags = e;
  195. cm.MouseFlags = MouseFlags.Button2Clicked;
  196. Assert.Equal (MouseFlags.Button2Clicked, cm.MouseFlags);
  197. Assert.Equal (MouseFlags.Button3Clicked, oldMouseFlags);
  198. }
  199. [Fact, AutoInitShutdown]
  200. public void Show_Ensures_Display_Inside_The_Container_But_Preserves_Position ()
  201. {
  202. var cm = new ContextMenu (80, 25,
  203. new MenuBarItem (new MenuItem [] {
  204. new MenuItem ("One", "", null),
  205. new MenuItem ("Two", "", null)
  206. })
  207. );
  208. Assert.Equal (new Point (80, 25), cm.Position);
  209. cm.Show ();
  210. Assert.Equal (new Point (80, 25), cm.Position);
  211. Application.Begin (Application.Top);
  212. var expected = @"
  213. ┌──────┐
  214. │ One │
  215. │ Two │
  216. └──────┘
  217. ";
  218. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  219. Assert.Equal (new Rect (72, 21, 80, 4), pos);
  220. cm.Hide ();
  221. Assert.Equal (new Point (80, 25), cm.Position);
  222. }
  223. [Fact, AutoInitShutdown]
  224. public void Show_Ensures_Display_Inside_The_Container_Without_Overlap_The_Host ()
  225. {
  226. var view = new View ("View") {
  227. X = Pos.AnchorEnd (10),
  228. Y = Pos.AnchorEnd (1),
  229. Width = 10,
  230. Height = 1
  231. };
  232. var cm = new ContextMenu (view,
  233. new MenuBarItem (new MenuItem [] {
  234. new MenuItem ("One", "", null),
  235. new MenuItem ("Two", "", null)
  236. })
  237. );
  238. Application.Top.Add (view);
  239. Application.Begin (Application.Top);
  240. Assert.Equal (new Rect (70, 24, 10, 1), view.Frame);
  241. Assert.Equal (new Point (0, 0), cm.Position);
  242. cm.Show ();
  243. Assert.Equal (new Point (70, 24), cm.Position);
  244. Application.Top.Redraw (Application.Top.Bounds);
  245. var expected = @"
  246. ┌──────┐
  247. │ One │
  248. │ Two │
  249. └──────┘
  250. View
  251. ";
  252. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  253. Assert.Equal (new Rect (70, 20, 78, 5), pos);
  254. cm.Hide ();
  255. Assert.Equal (new Point (70, 24), cm.Position);
  256. }
  257. [Fact, AutoInitShutdown]
  258. public void Show_Display_Below_The_Bottom_Host_If_Has_Enough_Space ()
  259. {
  260. var view = new View ("View") { X = 10, Y = 5, Width = 10, Height = 1 };
  261. var cm = new ContextMenu (view,
  262. new MenuBarItem (new MenuItem [] {
  263. new MenuItem ("One", "", null),
  264. new MenuItem ("Two", "", null)
  265. })
  266. );
  267. Application.Top.Add (view);
  268. Application.Begin (Application.Top);
  269. Assert.Equal (new Point (10, 5), cm.Position);
  270. cm.Show ();
  271. Application.Top.Redraw (Application.Top.Bounds);
  272. Assert.Equal (new Point (10, 5), cm.Position);
  273. var expected = @"
  274. View
  275. ┌──────┐
  276. │ One │
  277. │ Two │
  278. └──────┘
  279. ";
  280. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  281. Assert.Equal (new Rect (10, 5, 18, 5), pos);
  282. cm.Hide ();
  283. Assert.Equal (new Point (10, 5), cm.Position);
  284. cm.Host.X = 5;
  285. cm.Host.Y = 10;
  286. cm.Host.Height = 3;
  287. cm.Show ();
  288. Application.Top.Redraw (Application.Top.Bounds);
  289. Assert.Equal (new Point (5, 12), cm.Position);
  290. expected = @"
  291. View
  292. ┌──────┐
  293. │ One │
  294. │ Two │
  295. └──────┘
  296. ";
  297. pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  298. Assert.Equal (new Rect (5, 10, 13, 7), pos);
  299. cm.Hide ();
  300. Assert.Equal (new Point (5, 12), cm.Position);
  301. }
  302. [Fact, AutoInitShutdown]
  303. public void Show_Display_At_Zero_If_The_Toplevel_Width_Is_Less_Than_The_Menu_Width ()
  304. {
  305. var cm = new ContextMenu (0, 0,
  306. new MenuBarItem (new MenuItem [] {
  307. new MenuItem ("One", "", null),
  308. new MenuItem ("Two", "", null)
  309. })
  310. );
  311. Assert.Equal (new Point (0, 0), cm.Position);
  312. cm.Show ();
  313. Assert.Equal (new Point (0, 0), cm.Position);
  314. Application.Begin (Application.Top);
  315. ((FakeDriver)Application.Driver).SetBufferSize (5, 25);
  316. var expected = @"
  317. ┌────
  318. │ One
  319. │ Two
  320. └────
  321. ";
  322. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  323. Assert.Equal (new Rect (0, 1, 5, 4), pos);
  324. cm.Hide ();
  325. Assert.Equal (new Point (0, 0), cm.Position);
  326. }
  327. [Fact, AutoInitShutdown]
  328. public void Show_Display_At_Zero_If_The_Toplevel_Height_Is_Less_Than_The_Menu_Height ()
  329. {
  330. var cm = new ContextMenu (0, 0,
  331. new MenuBarItem (new MenuItem [] {
  332. new MenuItem ("One", "", null),
  333. new MenuItem ("Two", "", null)
  334. })
  335. );
  336. Assert.Equal (new Point (0, 0), cm.Position);
  337. cm.Show ();
  338. Assert.Equal (new Point (0, 0), cm.Position);
  339. Application.Begin (Application.Top);
  340. ((FakeDriver)Application.Driver).SetBufferSize (80, 4);
  341. var expected = @"
  342. ┌──────┐
  343. │ One │
  344. │ Two │
  345. ";
  346. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  347. Assert.Equal (new Rect (0, 1, 8, 3), pos);
  348. cm.Hide ();
  349. Assert.Equal (new Point (0, 0), cm.Position);
  350. }
  351. [Fact, AutoInitShutdown]
  352. public void Hide_Is_Invoke_At_Container_Closing ()
  353. {
  354. var cm = new ContextMenu (80, 25,
  355. new MenuBarItem (new MenuItem [] {
  356. new MenuItem ("One", "", null),
  357. new MenuItem ("Two", "", null)
  358. })
  359. );
  360. var top = Application.Top;
  361. Application.Begin (top);
  362. top.Running = true;
  363. Assert.False (ContextMenu.IsShow);
  364. cm.Show ();
  365. Assert.True (ContextMenu.IsShow);
  366. top.RequestStop ();
  367. Assert.False (ContextMenu.IsShow);
  368. }
  369. [Fact, AutoInitShutdown]
  370. public void ForceMinimumPosToZero_True_False ()
  371. {
  372. var cm = new ContextMenu (-1, -2,
  373. new MenuBarItem (new MenuItem [] {
  374. new MenuItem ("One", "", null),
  375. new MenuItem ("Two", "", null)
  376. })
  377. );
  378. Assert.Equal (new Point (-1, -2), cm.Position);
  379. cm.Show ();
  380. Assert.Equal (new Point (-1, -2), cm.Position);
  381. Application.Begin (Application.Top);
  382. var expected = @"
  383. ┌──────┐
  384. │ One │
  385. │ Two │
  386. └──────┘
  387. ";
  388. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  389. Assert.Equal (new Rect (0, 1, 8, 4), pos);
  390. cm.ForceMinimumPosToZero = false;
  391. cm.Show ();
  392. Assert.Equal (new Point (-1, -2), cm.Position);
  393. Application.Refresh ();
  394. expected = @"
  395. One │
  396. Two │
  397. ──────┘
  398. ";
  399. pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  400. Assert.Equal (new Rect (1, 0, 7, 3), pos);
  401. }
  402. [Fact, AutoInitShutdown]
  403. public void ContextMenu_Is_Closed_If_Another_MenuBar_Is_Open_Or_Vice_Versa ()
  404. {
  405. var cm = new ContextMenu (10, 5,
  406. new MenuBarItem (new MenuItem [] {
  407. new MenuItem ("One", "", null),
  408. new MenuItem ("Two", "", null)
  409. })
  410. );
  411. var menu = new MenuBar (new MenuBarItem [] {
  412. new MenuBarItem ("File", "", null),
  413. new MenuBarItem ("Edit", "", null)
  414. });
  415. Application.Top.Add (menu);
  416. Assert.Null (Application.mouseGrabView);
  417. cm.Show ();
  418. Assert.True (ContextMenu.IsShow);
  419. Assert.Equal (cm.MenuBar, Application.mouseGrabView);
  420. Assert.False (menu.IsMenuOpen);
  421. Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
  422. Assert.False (ContextMenu.IsShow);
  423. Assert.Equal (menu, Application.mouseGrabView);
  424. Assert.True (menu.IsMenuOpen);
  425. cm.Show ();
  426. Assert.True (ContextMenu.IsShow);
  427. Assert.Equal (cm.MenuBar, Application.mouseGrabView);
  428. Assert.False (menu.IsMenuOpen);
  429. Assert.False (menu.OnKeyDown (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
  430. Assert.True (menu.OnKeyUp (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
  431. Assert.False (ContextMenu.IsShow);
  432. Assert.Equal (menu, Application.mouseGrabView);
  433. Assert.True (menu.IsMenuOpen);
  434. cm.Show ();
  435. Assert.True (ContextMenu.IsShow);
  436. Assert.Equal (cm.MenuBar, Application.mouseGrabView);
  437. Assert.False (menu.IsMenuOpen);
  438. Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu }));
  439. Assert.True (ContextMenu.IsShow);
  440. Assert.Equal (cm.MenuBar, Application.mouseGrabView);
  441. Assert.False (menu.IsMenuOpen);
  442. Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu }));
  443. Assert.False (ContextMenu.IsShow);
  444. Assert.Equal (menu, Application.mouseGrabView);
  445. Assert.True (menu.IsMenuOpen);
  446. }
  447. [Fact, AutoInitShutdown]
  448. public void ContextMenu_On_Toplevel_With_A_MenuBar_TextField_StatusBar ()
  449. {
  450. Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
  451. var menu = new MenuBar (new MenuBarItem [] {
  452. new MenuBarItem ("File", "", null),
  453. new MenuBarItem ("Edit", "", null)
  454. });
  455. var label = new Label ("Label:") {
  456. X = 2,
  457. Y = 3
  458. };
  459. var tf = new TextField ("TextField") {
  460. X = Pos.Right (label) + 1,
  461. Y = Pos.Top (label),
  462. Width = 20
  463. };
  464. var statusBar = new StatusBar (new StatusItem [] {
  465. new StatusItem(Key.F1, "~F1~ Help", null),
  466. new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", null)
  467. });
  468. Application.Top.Add (menu, label, tf, statusBar);
  469. Application.Begin (Application.Top);
  470. ((FakeDriver)Application.Driver).SetBufferSize (45, 17);
  471. Assert.Equal (new Rect (9, 3, 20, 1), tf.Frame);
  472. Assert.True (tf.HasFocus);
  473. tf.ContextMenu.Show ();
  474. Assert.True (ContextMenu.IsShow);
  475. Assert.Equal (new Point (9, 3), tf.ContextMenu.Position);
  476. Application.Top.Redraw (Application.Top.Bounds);
  477. var expected = @"
  478. File Edit
  479. Label: TextField
  480. ┌────────────────────────────┐
  481. │ Select All Ctrl+T │
  482. │ Delete All Ctrl+Shift+D │
  483. │ Copy Ctrl+C │
  484. │ Cut Ctrl+X │
  485. │ Paste Ctrl+V │
  486. │ Undo Ctrl+Z │
  487. │ Redo Ctrl+Y │
  488. └────────────────────────────┘
  489. F1 Help │ ^Q Quit
  490. ";
  491. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  492. Assert.Equal (new Rect (2, 0, 39, 17), pos);
  493. }
  494. [Fact, AutoInitShutdown]
  495. public void ContextMenu_On_Toplevel_With_A_MenuBar_Window_TextField_StatusBar ()
  496. {
  497. Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
  498. var menu = new MenuBar (new MenuBarItem [] {
  499. new MenuBarItem ("File", "", null),
  500. new MenuBarItem ("Edit", "", null)
  501. });
  502. var label = new Label ("Label:") {
  503. X = 2,
  504. Y = 3
  505. };
  506. var tf = new TextField ("TextField") {
  507. X = Pos.Right (label) + 1,
  508. Y = Pos.Top (label),
  509. Width = 20
  510. };
  511. var win = new Window ("Window");
  512. win.Add (label, tf);
  513. var statusBar = new StatusBar (new StatusItem [] {
  514. new StatusItem(Key.F1, "~F1~ Help", null),
  515. new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", null)
  516. });
  517. Application.Top.Add (menu, win, statusBar);
  518. Application.Begin (Application.Top);
  519. ((FakeDriver)Application.Driver).SetBufferSize (45, 17);
  520. Assert.Equal (new Rect (9, 3, 20, 1), tf.Frame);
  521. Assert.True (tf.HasFocus);
  522. tf.ContextMenu.Show ();
  523. Assert.True (ContextMenu.IsShow);
  524. Assert.Equal (new Point (10, 5), tf.ContextMenu.Position);
  525. Application.Top.Redraw (Application.Top.Bounds);
  526. var expected = @"
  527. File Edit
  528. ┌ Window ───────────────────────────────────┐
  529. │ │
  530. │ │
  531. │ │
  532. │ Label: TextField │
  533. │ ┌────────────────────────────┐ │
  534. │ │ Select All Ctrl+T │ │
  535. │ │ Delete All Ctrl+Shift+D │ │
  536. │ │ Copy Ctrl+C │ │
  537. │ │ Cut Ctrl+X │ │
  538. │ │ Paste Ctrl+V │ │
  539. │ │ Undo Ctrl+Z │ │
  540. │ │ Redo Ctrl+Y │ │
  541. │ └────────────────────────────┘ │
  542. └───────────────────────────────────────────┘
  543. F1 Help │ ^Q Quit
  544. ";
  545. var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
  546. Assert.Equal (new Rect (2, 0, 45, 17), pos);
  547. }
  548. }
  549. }