BoatRobotViewModel.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. using Aitex.Core.Util;
  2. using Caliburn.Micro.Core;
  3. using Caliburn.Micro;
  4. using FurnaceUI.Models;
  5. using FurnaceUI.Views.Operations;
  6. using MECF.Framework.Common.DataCenter;
  7. using MECF.Framework.Common.Equipment;
  8. using MECF.Framework.Common.OperationCenter;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using System.Windows.Controls;
  15. using OpenSEMI.ClientBase;
  16. namespace FurnaceUI.Views.Maintenances
  17. {
  18. public class BoatRobotViewModel : FurnaceUIViewModelBase
  19. {
  20. [Subscription("Rt.Status")]
  21. public string RtStatus { get; set; }
  22. [Subscription("PM1.IsProcessing")]
  23. public bool IsProcessing { get; set; }
  24. [Subscription("PM1.RunningMode")]
  25. public bool RunningModeIsDebug { get; set; }
  26. public bool IsSystemStaus => (RtStatus != "AutoRunning");
  27. #region ZAxis Data
  28. [Subscription("PM1.BoatElevatorServo.CurrentPosition")]
  29. public float BoatZAxisCurrentPosition { get; set; }
  30. [Subscription("PM1.BoatElevatorServo.CurrentSpeed")]
  31. public float BoatZAxisCurrentSpeed { get; set; }
  32. [Subscription("PM1.BoatElevatorServo.TargetPosition")]
  33. public float BoatZAxisTargetPosition { get; set; }
  34. [Subscription("PM1.BoatElevatorServo.IsReady")]
  35. public bool BoatZAxisIsReady { get; set; }
  36. [Subscription("PM1.AlarmSignaBoatZAxisWarning.Value")]
  37. public bool BoatZAxisIsWarning { get; set; }
  38. [Subscription("PM1.AlarmSignaBoatZAxisAlarm.Value")]
  39. public bool BoatZAxisIsAlarm { get; set; }
  40. [Subscription("PM1.BoatElevatorServo.AtPosition1")]
  41. public bool BoatZAxisAtPosition1 { get; set; }
  42. [Subscription("PM1.BoatElevatorServo.AtPosition2")]
  43. public bool BoatZAxisAtPosition2 { get; set; }
  44. [Subscription("PM1.BoatElevatorServo.AtPosition3")]
  45. public bool BoatZAxisAtPosition3 { get; set; }
  46. [Subscription("PM1.BoatElevatorServo.AtHomePosition")]
  47. public bool BoatZAxisAtHomePosition { get; set; }
  48. [Subscription("PM1.BoatElevatorServo.IsServoOn")]
  49. public bool BoatZAxisIsServoOn { get; set; }
  50. [Subscription("PM1.BoatElevatorServo.ErrorCode")]
  51. public string BoatZAxisErrorCode { get; set; }
  52. [Subscription("PM1.BoatElevatorServo.Status")]
  53. public string BoatZAxisStatus { get; set; }
  54. [Subscription("PM1.BoatElevatorServo.IsActionEnable")]
  55. public bool BoatZAxisIsActionEnable { get; set; }
  56. [Subscription("PM1.BoatElevatorServo.IsMoving")]
  57. public bool BoatZAxisIsMoving { get; set; }
  58. public double ZAxisProcessPosition { get; set; }
  59. public double ZAxisPosition5 { get; set; }
  60. public double ZAxisPosition4 { get; set; }
  61. public double ZAxisPosition3 { get; set; }
  62. public double ZAxisPosition2 { get; set; }
  63. public double ZAxisPosition1 { get; set; }
  64. public double ZAxisHomePosition { get; set; }
  65. public double ZAxisPositiveLimit { get; set; }
  66. public double ZAxisNegativeLimit { get; set; }
  67. public double ZAxisMoveSpeed { get; set; }
  68. public double ZAxisAcc { get; set; }
  69. public double ZAxisDec { get; set; }
  70. public double ZAxisJogSpeed { get; set; }
  71. public double ZAxisAccTime { get; set; }
  72. public double ZAxisDecTime { get; set; }
  73. private Dictionary<string, string> zPositionTranslate = new Dictionary<string, string>()
  74. {{"Position1","Position1" }, {"Position2","Position2" },{"Position3","Position3" }};
  75. #endregion
  76. #region RAxis Data
  77. [Subscription("PM1.BoatRotationServo.CurrentPosition")]
  78. public float BoatRAxisCurrentPosition { get; set; }
  79. [Subscription("PM1.BoatRotationServo.CurrentSpeed")]
  80. public float BoatRAxisCurrentSpeed { get; set; }
  81. [Subscription("PM1.BoatRotationServo.TargetPosition")]
  82. public float BoatRAxisTargetPosition { get; set; }
  83. [Subscription("PM1.BoatRotationServo.IsReady")]
  84. public bool BoatRAxisIsReady { get; set; }
  85. [Subscription("PM1.BoatRotationServo.IsMoving")]
  86. public bool BoatRAxisIsMoving { get; set; }
  87. [Subscription("PM1.BoatRotationServo.IsInitDone")]
  88. public bool BoatRAxisIsInitDone { get; set; }
  89. [Subscription("PM1.BoatRotationServo.IsHomeDone")]
  90. public bool BoatRAxisIsHomeDone { get; set; }
  91. [Subscription("PM1.BoatRotationServo.IsHoming")]
  92. public bool BoatRAxisIsHoming { get; set; }
  93. [Subscription("PM1.BoatRotationServo.IsInitializing")]
  94. public bool BoatRAxisIsInitializing { get; set; }
  95. [Subscription("PM1.AlarmSignaBoatRAxisWarning.Value")]
  96. public bool BoatRAxisIsWarning { get; set; }
  97. [Subscription("PM1.AlarmSignaBoatRAxisAlarm.Value")]
  98. public bool BoatRAxisIsAlarm { get; set; }
  99. [Subscription("PM1.BoatRotationServo.IsServoOn")]
  100. public bool BoatRAxisIsServoOn { get; set; }
  101. [Subscription("PM1.BoatRotationServo.ErrorCode")]
  102. public string BoatRAxisErrorCode { get; set; }
  103. [Subscription("PM1.BoatRotationServo.Status")]
  104. public string BoatRAxisStatus { get; set; }
  105. [Subscription("PM1.BoatRotationServo.Direction")]
  106. public string BoatRAxisDirection { get; set; }
  107. [Subscription("PM1.BoatRotationServo.IsActionEnable")]
  108. public bool BoatRAxisIsActionEnable { get; set; }
  109. [Subscription("PM1.BoatRotationServo.IsMotorRun")]
  110. public bool BoatRAxisIsMotorRun { get; set; }
  111. public double RAxisLoadPosition { get; set; }
  112. public double RAxisPosition180 { get; set; }
  113. public double RAxisPosition90 { get; set; }
  114. public double RAxisPosition45 { get; set; }
  115. public double RAxisHomePosition { get; set; }
  116. public double RAxisPositiveLimit { get; set; }
  117. public double RAxisNegativeLimit { get; set; }
  118. public double RAxisMoveSpeed { get; set; }
  119. public double RAxisJogSpeed { get; set; }
  120. public double RAxisAccTime { get; set; }
  121. public double RAxisDecTime { get; set; }
  122. public double BoatRAxisLimitSpeed { get; set; }
  123. public double BoatZAxisLimitSpeed { get; set; }
  124. #endregion
  125. #region Shutter Data
  126. [Subscription("PM1.Shutter.OpenCloseStatus")]
  127. public string AutoDoorOpenCloseStatus { get; set; }
  128. #endregion
  129. [Subscription("Boat.BoatTestCycledCount")]
  130. public int BoatTestCycledCount { get; set; }
  131. private int _boatCycleCountSetPoint;
  132. public string BoatCycleDisplay => $" {BoatTestCycledCount} / {_boatCycleCountSetPoint}";
  133. [Subscription("Boat.ShutterCycledCount")]
  134. public int ShutterCycledCount { get; set; }
  135. private int _ShutterCycleCountSetPoint;
  136. public string ShutterCycleDisplay => $" {ShutterCycledCount} / {_ShutterCycleCountSetPoint}";
  137. private List<string> _ZPositions;
  138. public List<string> ZPositions
  139. {
  140. get { return _ZPositions; }
  141. set { _ZPositions = value; NotifyOfPropertyChange("ZPositions"); }
  142. }
  143. private List<string> _RPositions;
  144. public List<string> RPositions
  145. {
  146. get { return _RPositions; }
  147. set { _RPositions = value; NotifyOfPropertyChange("RPositions"); }
  148. }
  149. public string ZAxisTestStartPosition { get; set; }
  150. public string ZAxisTestEndPosition { get; set; }
  151. public string RAxisTestDirection { get; set; }
  152. //public bool IsPermission { get => this.Permission >= 3 && ClientApp.Instance.UserContext.RoleName == "Service"; }
  153. public bool IsPermission { get => this.Permission >= 3; }
  154. public BoatRobotViewModel()
  155. {
  156. _ZPositions = new List<string>()
  157. {
  158. "Position1",
  159. "Position2",
  160. "Position3",
  161. };
  162. RPositions = new List<string>()
  163. {
  164. "CW",
  165. "CCW",
  166. };
  167. }
  168. public void BoatModify()
  169. {
  170. var windowManager = IoC.Get<IWindowManager>();
  171. BoatModifyViewModel boatModifyViewModel = new BoatModifyViewModel(ModuleName.PM1.ToString());
  172. (windowManager as WindowManager)?.ShowDialogWithTitle(boatModifyViewModel, null, "Boat Wafer");
  173. }
  174. private BoatRobotView _view;
  175. protected override void InvokeAfterUpdateProperty(Dictionary<string, object> data)
  176. {
  177. InitData();
  178. if (_view != null)
  179. {
  180. var rsetValueBool = double.TryParse(_view?.tbMoveSpeed.Text, out double setZValue);
  181. if (!rsetValueBool)
  182. _view.tbMoveSpeed.Text = "0";
  183. var zsetValueBool = double.TryParse(_view?.tbSetSpeed.Text, out double setRValue);
  184. if (!rsetValueBool)
  185. _view.tbSetSpeed.Text = "0";
  186. if (!string.IsNullOrEmpty(_view?.tbMoveSpeed.Text) && rsetValueBool && setZValue > BoatZAxisLimitSpeed)
  187. {
  188. _view.tbMoveSpeed.Text = "0";
  189. DialogBox.ShowWarning($"Max Move Speed is {BoatZAxisLimitSpeed}");
  190. }
  191. if (!string.IsNullOrEmpty(_view?.tbSetSpeed.Text) && zsetValueBool && setRValue > BoatRAxisLimitSpeed)
  192. {
  193. _view.tbSetSpeed.Text = "0";
  194. DialogBox.ShowWarning($"Max Roat Speed is {BoatRAxisLimitSpeed}");
  195. }
  196. }
  197. }
  198. protected override void OnViewLoaded(object view)
  199. {
  200. base.OnViewLoaded(view);
  201. _view = view as BoatRobotView;
  202. BoatZAxisLimitSpeed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.BoatZAxisLimitSpeed");
  203. BoatRAxisLimitSpeed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.BoatRAxisLimitSpeed");
  204. }
  205. private void InitData()
  206. {
  207. ZAxisPosition1 = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position1");
  208. ZAxisPosition2 = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position2");
  209. ZAxisHomePosition = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position6");
  210. ZAxisProcessPosition = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position7");
  211. ZAxisPositiveLimit = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position8");
  212. ZAxisNegativeLimit = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Position9");
  213. ZAxisMoveSpeed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.MoveSpeed");
  214. ZAxisAcc = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Acc");
  215. ZAxisDec = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatElevatorServo.Dec");
  216. _boatCycleCountSetPoint = (int)QueryDataClient.Instance.Service.GetConfig($"Boat.CycleCount");
  217. _ShutterCycleCountSetPoint = (int)QueryDataClient.Instance.Service.GetConfig($"Boat.AutoShutter.CycleCount");
  218. RAxisPosition45 = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.Position1");
  219. RAxisPosition90 = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.Position2");
  220. RAxisPosition180 = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.Position3");
  221. RAxisLoadPosition = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.Position4");
  222. RAxisMoveSpeed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.MoveSpeed");
  223. }
  224. public void BoatZSaveValue(object obj, object tb)
  225. {
  226. switch (obj)
  227. {
  228. case "Position1":
  229. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  230. break;
  231. case "Position2":
  232. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  233. break;
  234. case "Position3":
  235. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  236. break;
  237. case "Position4":
  238. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  239. break;
  240. case "Position5":
  241. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  242. break;
  243. case "Position6":
  244. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  245. break;
  246. case "Position7":
  247. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  248. break;
  249. case "Position8":
  250. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  251. break;
  252. case "Position9":
  253. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  254. break;
  255. case "MoveSpeed":
  256. case "Acc":
  257. case "Dec":
  258. var setValue = double.Parse((tb as TextBox)?.Text);
  259. if (setValue > BoatZAxisLimitSpeed)
  260. {
  261. DialogBox.ShowWarning($"Max MoveSpeed is {BoatZAxisLimitSpeed}");
  262. break;
  263. }
  264. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatElevatorServo.{obj}", (tb as TextBox)?.Text);
  265. break;
  266. }
  267. }
  268. public void BoatRSaveValue(object obj, object tb)
  269. {
  270. switch (obj)
  271. {
  272. case "Position1":
  273. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatRotationServo.{obj}", (tb as TextBox)?.Text);
  274. break;
  275. case "Position2":
  276. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatRotationServo.{obj}", (tb as TextBox)?.Text);
  277. break;
  278. case "Position3":
  279. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatRotationServo.{obj}", (tb as TextBox)?.Text);
  280. break;
  281. case "Position4":
  282. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatRotationServo.{obj}", (tb as TextBox)?.Text);
  283. break;
  284. case "MoveSpeed":
  285. var textValue = string.IsNullOrEmpty((tb as TextBox)?.Text) ? "0" : (tb as TextBox)?.Text;
  286. var setValue = double.Parse(textValue);
  287. if (setValue > BoatRAxisLimitSpeed)
  288. {
  289. DialogBox.ShowWarning($"Max Roat Speed is {BoatRAxisLimitSpeed}");
  290. return;
  291. }
  292. InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"Boat.BoatRotationServo.{obj}", (tb as TextBox)?.Text);
  293. break;
  294. }
  295. }
  296. public void MoveTo(object targetPosition)
  297. {
  298. switch (targetPosition)
  299. {
  300. case "Position1":
  301. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  302. break;
  303. case "Position2":
  304. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  305. break;
  306. case "Position3":
  307. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  308. break;
  309. case "Position4":
  310. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  311. break;
  312. case "Position5":
  313. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  314. break;
  315. case "Position6":
  316. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  317. break;
  318. case "Position7":
  319. InvokeClient.Instance.Service.DoOperation($"PM1.BoatElevatorServo.ServoMoveTo", targetPosition);
  320. break;
  321. }
  322. }
  323. public void RAxisMoveTo(object targetPosition)
  324. {
  325. switch (targetPosition)
  326. {
  327. case "Position1":
  328. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition);
  329. break;
  330. case "Position2":
  331. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition);
  332. break;
  333. case "Position3":
  334. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition);
  335. break;
  336. case "Position4":
  337. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition);
  338. break;
  339. case "CW":
  340. var speed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.MoveSpeed");
  341. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition, speed);
  342. break;
  343. case "CCW":
  344. speed = (double)QueryDataClient.Instance.Service.GetConfig($"Boat.BoatRotationServo.MoveSpeed");
  345. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition, speed);
  346. break;
  347. default:
  348. InvokeClient.Instance.Service.DoOperation($"PM1.BoatRotationServo.ServoMoveTo", targetPosition);
  349. break;
  350. }
  351. }
  352. public void BoatZServoTest()
  353. {
  354. if (string.IsNullOrEmpty(ZAxisTestStartPosition))
  355. {
  356. return;
  357. }
  358. if (zPositionTranslate.Keys.Contains(ZAxisTestStartPosition) && zPositionTranslate.Keys.Contains(ZAxisTestStartPosition))
  359. {
  360. InvokeClient.Instance.Service.DoOperation($"Boat.ZAxisMovingTest", zPositionTranslate[ZAxisTestStartPosition], zPositionTranslate[ZAxisTestEndPosition]);
  361. }
  362. else
  363. {
  364. InvokeClient.Instance.Service.DoOperation($"Boat.ZAxisMovingTest", ZAxisTestStartPosition, ZAxisTestEndPosition);
  365. }
  366. }
  367. public void BoatRotationServoTest(object targetPosition)
  368. {
  369. InvokeClient.Instance.Service.DoOperation($"Boat.RAxisMovingTest", targetPosition);
  370. }
  371. public void BoatTestStart()
  372. {
  373. if (zPositionTranslate.Keys.Contains(ZAxisTestStartPosition) && zPositionTranslate.Keys.Contains(ZAxisTestStartPosition))
  374. {
  375. InvokeClient.Instance.Service.DoOperation($"Boat.MovingTest", zPositionTranslate[ZAxisTestStartPosition], zPositionTranslate[ZAxisTestEndPosition], RAxisTestDirection);
  376. }
  377. else
  378. {
  379. InvokeClient.Instance.Service.DoOperation($"Boat.MovingTest", ZAxisTestStartPosition, ZAxisTestEndPosition, RAxisTestDirection);
  380. }
  381. }
  382. public void BoatTestStop()
  383. {
  384. InvokeClient.Instance.Service.DoOperation($"Boat.Abort");
  385. }
  386. public void ShutterTestStart()
  387. {
  388. InvokeClient.Instance.Service.DoOperation($"Boat.ShutterCycleTest");
  389. }
  390. public void ShutterTestStop()
  391. {
  392. InvokeClient.Instance.Service.DoOperation($"Boat.Abort");
  393. }
  394. public void BoatRotationServoStopTest()
  395. {
  396. InvokeClient.Instance.Service.DoOperation($"Boat.Abort");
  397. }
  398. public void Home(object target)
  399. {
  400. InvokeClient.Instance.Service.DoOperation($"{target}.ServoHome");
  401. }
  402. public void SetServoOn(object target, object isOn)
  403. {
  404. InvokeClient.Instance.Service.DoOperation($"{target}", $"{isOn}");
  405. }
  406. public void Continue(object target)
  407. {
  408. InvokeClient.Instance.Service.DoOperation($"{target}.Continue");
  409. }
  410. public void Stop(object target)
  411. {
  412. InvokeClient.Instance.Service.DoOperation($"{target}.ServoStop");
  413. }
  414. public void Reset(object target)
  415. {
  416. InvokeClient.Instance.Service.DoOperation($"{target}.ServoResetAlarm");
  417. }
  418. public void SetOpen(object target, bool open)
  419. {
  420. // IsAutoDoorEnableManualOperation
  421. InvokeClient.Instance.Service.DoOperation($"{target}", open);
  422. }
  423. }
  424. }