ManualTransfer.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. using System;
  2. using System.Collections.Generic;
  3. using Aitex.Core.RT.Event;
  4. using Aitex.Core.RT.Routine;
  5. using Aitex.Sorter.Common;
  6. using MECF.Framework.Common.Equipment;
  7. using MECF.Framework.Common.Schedulers;
  8. using MECF.Framework.Common.SubstrateTrackings;
  9. using MECF.Framework.RT.ModuleLibrary.SystemModules;
  10. using EfemDualSchedulerLib.Schedulers;
  11. namespace EfemDualSchedulerLib
  12. {
  13. internal interface IManualTransferRoutine : IRoutine
  14. {
  15. }
  16. public class MoveItemEx : MoveItem
  17. {
  18. public int CoolingTime { get; set; }
  19. public MoveItemEx(ModuleName sourceModule, int sourceSlot, ModuleName destinationModule, int destinationSlot, int coolingTime)
  20. : base(sourceModule, sourceSlot, destinationModule, destinationSlot, Hand.Blade1)
  21. {
  22. CoolingTime = coolingTime;
  23. }
  24. }
  25. public class ManualTransfer : SchedulerModuleFactory, IRoutine
  26. {
  27. private Queue<IRoutine> _moveTaskQueue = new Queue<IRoutine>();
  28. private IRoutine _activeTask;
  29. public ManualTransfer(EquipmentManager equipment)
  30. {
  31. }
  32. public Result Start(object[] objs)
  33. {
  34. _moveTaskQueue.Clear();
  35. ModuleName source = (ModuleName)objs[0];
  36. int ss = (int)objs[1];
  37. ModuleName target = (ModuleName)objs[2];
  38. int ds = (int)objs[3];
  39. //bool autoAlign = (bool)objs[4];
  40. //int alignAngle = (int)objs[5];
  41. bool autoAlign = false;
  42. //bool autoCooling = false;//(bool)objs[6];
  43. //int coolingTime = (int)objs[7];
  44. if (!WaferManager.Instance.CheckHasWafer(source, ss))
  45. {
  46. EV.PostWarningLog("System", "source no wafer");
  47. return Result.FAIL;
  48. }
  49. if (!WaferManager.Instance.CheckNoWafer(target, ds))
  50. {
  51. EV.PostWarningLog("System", "destination has wafer");
  52. return Result.FAIL;
  53. }
  54. if (CheckNeedEfemRobot(source, target) && !_efem.Blade1Enable && !_efem.Blade2Enable)
  55. {
  56. EV.PostWarningLog("System", "EFEM robot both disabled");
  57. return Result.FAIL;
  58. }
  59. if (CheckNeedEfemRobot(source, target)
  60. &&(!ModuleHelper.IsEfemRobot(source)&& !ModuleHelper.IsEfemRobot(target))
  61. && WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0)
  62. && WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1))
  63. {
  64. EV.PostWarningLog("System", "EFEM robot has wafer");
  65. return Result.FAIL;
  66. }
  67. if (CheckNeedTMRobot(source, target) && !_tmRobot.Blade1Enable && !_tmRobot.Blade2Enable)
  68. {
  69. EV.PostWarningLog("System", "TM robot both disabled");
  70. return Result.FAIL;
  71. }
  72. if (CheckNeedTMRobot(source, target)
  73. && (!ModuleHelper.IsTMRobot(source) && !ModuleHelper.IsTMRobot(target))
  74. && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0)
  75. && WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1))
  76. {
  77. EV.PostWarningLog("System", "TM robot has wafer");
  78. return Result.FAIL;
  79. }
  80. if (CheckNeedEfemRobot(source, target) && CheckNeedTMRobot(source, target))
  81. {
  82. var emptyLoadLockSlot = GetEmptyLoadLockSlot();
  83. if (emptyLoadLockSlot == null)
  84. {
  85. EV.PostWarningLog("System", "Can not transfer, LoadLock has full wafer");
  86. return Result.FAIL;
  87. }
  88. if (ModuleHelper.IsPm(source) || ModuleHelper.IsTMRobot(source))
  89. {
  90. _moveTaskQueue.Enqueue(new TMRobotMover(new MoveItemEx(source, ss, emptyLoadLockSlot.Item1, emptyLoadLockSlot.Item2, 0)));
  91. _moveTaskQueue.Enqueue(new EfemRobotMover(new MoveItemEx(emptyLoadLockSlot.Item1, emptyLoadLockSlot.Item2, target, ds, 0)));
  92. }
  93. else
  94. {
  95. _moveTaskQueue.Enqueue(new EfemRobotMover(new MoveItemEx(source, ss, emptyLoadLockSlot.Item1, emptyLoadLockSlot.Item2, 0)));
  96. _moveTaskQueue.Enqueue(new TMRobotMover(new MoveItemEx(emptyLoadLockSlot.Item1, emptyLoadLockSlot.Item2, target, ds, 0)));
  97. }
  98. }
  99. else if (CheckNeedEfemRobot(source, target))
  100. {
  101. if (autoAlign)
  102. {
  103. _moveTaskQueue.Enqueue(new EfemRobotMover(new MoveItemEx(source, ss, ModuleName.Aligner, 0, 0)));
  104. _moveTaskQueue.Enqueue(new EfemRobotMover(new MoveItemEx(ModuleName.Aligner, 0, target, ds, 0)));
  105. }
  106. else
  107. {
  108. _moveTaskQueue.Enqueue(new EfemRobotMover(new MoveItemEx(source, ss, target, ds, 0)));
  109. }
  110. }
  111. else if (CheckNeedTMRobot(source, target))
  112. {
  113. _moveTaskQueue.Enqueue(new TMRobotMover(new MoveItemEx(source, ss, target, ds, 0)));
  114. }
  115. _activeTask = _moveTaskQueue.Dequeue();
  116. return _activeTask.Start();
  117. }
  118. public Result Monitor()
  119. {
  120. System.Diagnostics.Debug.Assert(_activeTask != null, "mover should not be null, call start first");
  121. Result ret = _activeTask.Monitor();
  122. if (ret == Result.FAIL)
  123. return ret;
  124. if (ret == Result.DONE)
  125. {
  126. if (_moveTaskQueue.Count > 0)
  127. {
  128. _activeTask = _moveTaskQueue.Dequeue();
  129. return _activeTask.Start();
  130. }
  131. return Result.DONE;
  132. }
  133. return Result.RUN;
  134. }
  135. public void Clear()
  136. {
  137. _moveTaskQueue.Clear();
  138. _activeTask = null;
  139. }
  140. public void Abort()
  141. {
  142. }
  143. public bool CheckNeedEfemRobot(ModuleName source, ModuleName target)
  144. {
  145. if (ModuleHelper.IsLoadPort(source) || ModuleHelper.IsLoadPort(target))
  146. {
  147. return true;
  148. }
  149. if (ModuleHelper.IsEfemRobot(source) || ModuleHelper.IsEfemRobot(target))
  150. {
  151. return true;
  152. }
  153. if (ModuleHelper.IsAligner(source) || ModuleHelper.IsAligner(target))
  154. {
  155. return true;
  156. }
  157. if (ModuleHelper.IsLoadLock(source) || ModuleHelper.IsLoadLock(target))
  158. {
  159. if (!CheckNeedTMRobot(source, target))
  160. return true;
  161. }
  162. return false;
  163. }
  164. public bool CheckNeedTMRobot(ModuleName source, ModuleName target)
  165. {
  166. if (ModuleHelper.IsPm(source) || ModuleHelper.IsPm(target))
  167. {
  168. return true;
  169. }
  170. if (ModuleHelper.IsTMRobot(source) || ModuleHelper.IsTMRobot(target))
  171. {
  172. return true;
  173. }
  174. return false;
  175. }
  176. public Tuple<ModuleName, int> GetEmptyLoadLockSlot()
  177. {
  178. var lla = WaferManager.Instance.GetWafers(ModuleName.LLA);
  179. for (int i = 0; i < lla.Length; i++)
  180. {
  181. if (lla[i].IsEmpty)
  182. {
  183. return new Tuple<ModuleName, int>(ModuleName.LLA, i);
  184. }
  185. }
  186. var llb = WaferManager.Instance.GetWafers(ModuleName.LLB);
  187. for (int i = 0; i < llb.Length; i++)
  188. {
  189. if (llb[i].IsEmpty)
  190. {
  191. return new Tuple<ModuleName, int>(ModuleName.LLB, i);
  192. }
  193. }
  194. return null;
  195. }
  196. }
  197. public class EfemRobotMover : SchedulerModuleFactory, IRoutine
  198. {
  199. private MoveItem _moveTask;
  200. private SchedulerModule _source;
  201. private SchedulerModule _destination;
  202. public EfemRobotMover(MoveItem moveTask)
  203. {
  204. _moveTask = moveTask;
  205. }
  206. public Result Start()
  207. {
  208. _source = GetModule(_moveTask.SourceModule.ToString());
  209. _destination = GetModule(_moveTask.DestinationModule.ToString());
  210. System.Diagnostics.Debug.Assert(_source != null, $"{_moveTask.SourceModule} not valid");
  211. System.Diagnostics.Debug.Assert(_destination != null, $"{_moveTask.DestinationModule} not valid");
  212. if (!_source.HasWafer(_moveTask.SourceSlot))
  213. {
  214. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} slot {_moveTask.SourceSlot + 1} has not wafer");
  215. return Result.FAIL;
  216. }
  217. if (!_destination.NoWafer(_moveTask.DestinationSlot))
  218. {
  219. EV.PostWarningLog("System", $"Failed transfer, destination {_moveTask.DestinationModule} slot {_moveTask.DestinationSlot + 1} has wafer");
  220. return Result.FAIL;
  221. }
  222. if (!_source.IsOnline)
  223. {
  224. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} should be put online");
  225. return Result.FAIL;
  226. }
  227. if (!_source.IsAvailable)
  228. {
  229. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} in busy status");
  230. return Result.FAIL;
  231. }
  232. if (!_destination.IsOnline)
  233. {
  234. EV.PostWarningLog("System", $"Failed transfer, Destination {_moveTask.DestinationModule} should be put online");
  235. return Result.FAIL;
  236. }
  237. if (!_destination.IsAvailable)
  238. {
  239. EV.PostWarningLog("System", $"Failed transfer, Destination {_moveTask.DestinationModule} in busy status");
  240. return Result.FAIL;
  241. }
  242. if (!_efem.IsAvailable)
  243. {
  244. EV.PostWarningLog("System", $"Failed transfer, EFEM Robot is busy");
  245. return Result.FAIL;
  246. }
  247. if (ModuleHelper.IsEfem(_source.Module)||ModuleHelper.IsEfemRobot(_source.Module))
  248. {
  249. _moveTask.RobotHand = (Hand)_moveTask.SourceSlot;
  250. }
  251. else if (ModuleHelper.IsEfem(_destination.Module) || ModuleHelper.IsEfemRobot(_destination.Module))
  252. {
  253. _moveTask.RobotHand = (Hand)_moveTask.DestinationSlot;
  254. }
  255. else
  256. {
  257. _moveTask.RobotHand = GetAvailableHand(ModuleName.EfemRobot);
  258. }
  259. return Result.RUN;
  260. }
  261. public Result Start(params object[] objs)
  262. {
  263. return this.Start();
  264. }
  265. public Result Monitor()
  266. {
  267. if (_source.NoWafer(_moveTask.SourceSlot) && _destination.HasWafer(_moveTask.DestinationSlot) &&
  268. _efem.IsAvailable)
  269. {
  270. if (_source.IsWaitTransfer(ModuleName.EfemRobot))
  271. _source.StopWaitTransfer(ModuleName.EfemRobot);
  272. if (_destination.IsWaitTransfer(ModuleName.EfemRobot))
  273. _destination.StopWaitTransfer(ModuleName.EfemRobot);
  274. return Result.DONE;
  275. }
  276. if (_source.IsError || _destination.IsError || _efem.IsError)
  277. return Result.FAIL;
  278. if (!_efem.IsAvailable)
  279. return Result.RUN;
  280. //pick
  281. if (_moveTask.SourceModule != ModuleName.EfemRobot)
  282. {
  283. if (_source.HasWafer(_moveTask.SourceSlot))
  284. {
  285. if (!_source.IsAvailable)
  286. return Result.RUN;
  287. if (!_source.IsReadyForPick(ModuleName.EfemRobot, GetAvailableHand(ModuleName.EfemRobot), _moveTask.SourceSlot))
  288. {
  289. if (!_source.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Pick, _moveTask.SourceSlot))
  290. return Result.FAIL;
  291. }
  292. if (!_source.IsAvailable)
  293. return Result.RUN;
  294. if (!_efem.HasWafer((int)_moveTask.RobotHand))
  295. {
  296. if (!_efem.Pick(_moveTask.SourceModule, _moveTask.SourceSlot, _moveTask.RobotHand))
  297. {
  298. return Result.FAIL;
  299. }
  300. _source.WaitTransfer(ModuleName.EfemRobot);
  301. }
  302. if (!_efem.IsAvailable)
  303. return Result.RUN;
  304. }
  305. else
  306. {
  307. if (!_efem.IsAvailable)
  308. return Result.RUN;
  309. if (_source.IsWaitTransfer(ModuleName.EfemRobot))
  310. _source.StopWaitTransfer(ModuleName.EfemRobot);
  311. }
  312. }
  313. //place
  314. if (_moveTask.DestinationModule != ModuleName.EfemRobot)
  315. {
  316. if (!_destination.IsAvailable)
  317. return Result.RUN;
  318. if (_destination.NoWafer(_moveTask.DestinationSlot))
  319. {
  320. if (!_destination.IsReadyForPlace(ModuleName.EfemRobot, GetAvailableHand(ModuleName.EfemRobot), _moveTask.DestinationSlot))
  321. {
  322. if (!_destination.PrepareTransfer(ModuleName.EfemRobot, EnumTransferType.Place,
  323. _moveTask.DestinationSlot))
  324. return Result.FAIL;
  325. }
  326. if (!_destination.IsAvailable)
  327. return Result.RUN;
  328. if (_efem.HasWafer((int)_moveTask.RobotHand))
  329. {
  330. if (!_efem.Place(_moveTask.DestinationModule, _moveTask.DestinationSlot, _moveTask.RobotHand))
  331. return Result.FAIL;
  332. _destination.WaitTransfer(ModuleName.EfemRobot);
  333. }
  334. if (!_efem.IsAvailable)
  335. return Result.RUN;
  336. }
  337. else
  338. {
  339. if (!_efem.IsAvailable)
  340. return Result.RUN;
  341. if (_destination.IsWaitTransfer(ModuleName.EfemRobot))
  342. _destination.StopWaitTransfer(ModuleName.EfemRobot);
  343. }
  344. }
  345. return Result.RUN;
  346. }
  347. public void Abort()
  348. {
  349. Clear();
  350. }
  351. public void Clear()
  352. {
  353. _efem.ResetTask();
  354. _source?.ResetTask();
  355. _destination?.ResetTask();
  356. }
  357. public Hand GetAvailableHand(ModuleName module)
  358. {
  359. var wafers = WaferManager.Instance.GetWafers(module);
  360. return _efem.Blade1Enable&&wafers[0].IsEmpty ? Hand.Blade1 : Hand.Blade2;
  361. }
  362. }
  363. public class TMRobotMover : SchedulerModuleFactory, IRoutine
  364. {
  365. private MoveItem _moveTask;
  366. private SchedulerModule _source;
  367. private SchedulerModule _destination;
  368. public TMRobotMover(MoveItem moveTask)
  369. {
  370. _moveTask = moveTask;
  371. }
  372. public Result Start()
  373. {
  374. _source = GetModule(_moveTask.SourceModule.ToString());
  375. _destination = GetModule(_moveTask.DestinationModule.ToString());
  376. System.Diagnostics.Debug.Assert(_source != null, $"{_moveTask.SourceModule} not valid");
  377. System.Diagnostics.Debug.Assert(_destination != null, $"{_moveTask.DestinationModule} not valid");
  378. if (!_source.HasWafer(_moveTask.SourceSlot))
  379. {
  380. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} slot {_moveTask.SourceSlot + 1} has not wafer");
  381. return Result.FAIL;
  382. }
  383. if (!_destination.NoWafer(_moveTask.DestinationSlot))
  384. {
  385. EV.PostWarningLog("System", $"Failed transfer, destination {_moveTask.DestinationModule} slot {_moveTask.DestinationSlot + 1} has wafer");
  386. return Result.FAIL;
  387. }
  388. if (!_source.IsOnline)
  389. {
  390. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} should be put online");
  391. return Result.FAIL;
  392. }
  393. if (!_source.IsAvailable)
  394. {
  395. EV.PostWarningLog("System", $"Failed transfer, source {_moveTask.SourceModule} in busy status");
  396. return Result.FAIL;
  397. }
  398. if (!_destination.IsOnline)
  399. {
  400. EV.PostWarningLog("System", $"Failed transfer, Destination {_moveTask.DestinationModule} should be put online");
  401. return Result.FAIL;
  402. }
  403. if (!_destination.IsAvailable)
  404. {
  405. EV.PostWarningLog("System", $"Failed transfer, Destination {_moveTask.DestinationModule} in busy status");
  406. return Result.FAIL;
  407. }
  408. if (!_tmRobot.IsAvailable)
  409. {
  410. EV.PostWarningLog("System", $"Failed transfer, TM Robot is busy");
  411. return Result.FAIL;
  412. }
  413. if (ModuleHelper.IsTM(_source.Module)||ModuleHelper.IsTMRobot(_source.Module))
  414. {
  415. _moveTask.RobotHand =(Hand) _moveTask.SourceSlot;
  416. }
  417. else if (ModuleHelper.IsTM(_destination.Module)||ModuleHelper.IsTMRobot(_destination.Module))
  418. {
  419. _moveTask.RobotHand = (Hand)_moveTask.DestinationSlot;
  420. }
  421. else
  422. {
  423. _moveTask.RobotHand = GetAvailableHand(ModuleName.TMRobot);
  424. }
  425. return Result.RUN;
  426. }
  427. public Result Start(params object[] objs)
  428. {
  429. return this.Start();
  430. }
  431. public Result Monitor()
  432. {
  433. if (_source.NoWafer(_moveTask.SourceSlot) && _destination.HasWafer(_moveTask.DestinationSlot) &&
  434. _tmRobot.IsAvailable)
  435. {
  436. if (_source.IsWaitTransfer(ModuleName.TMRobot))
  437. _source.StopWaitTransfer(ModuleName.TMRobot);
  438. if (_destination.IsWaitTransfer(ModuleName.TMRobot))
  439. _destination.StopWaitTransfer(ModuleName.TMRobot);
  440. if (ModuleHelper.IsPm(_moveTask.SourceModule) || ModuleHelper.IsPm(_moveTask.DestinationModule))
  441. {
  442. if (!_pm1.CheckSlitValveClose())
  443. _pm1.CloseSlitValve();
  444. if (!_pm2.CheckSlitValveClose())
  445. _pm2.CloseSlitValve();
  446. }
  447. return Result.DONE;
  448. }
  449. if (_source.IsError || _destination.IsError || _tmRobot.IsError)
  450. return Result.FAIL;
  451. if (!_tmRobot.IsAvailable)
  452. return Result.RUN;
  453. //pick
  454. if (_moveTask.SourceModule != ModuleName.TMRobot)
  455. {
  456. if (_source.HasWafer(_moveTask.SourceSlot))
  457. {
  458. if (!_source.IsAvailable)
  459. return Result.RUN;
  460. if (!_source.IsReadyForPick(ModuleName.TMRobot, GetAvailableHand(ModuleName.TMRobot), _moveTask.SourceSlot))
  461. {
  462. if (!_source.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, _moveTask.SourceSlot))
  463. return Result.FAIL;
  464. }
  465. if (!_source.IsAvailable)
  466. return Result.RUN;
  467. if (!_tmRobot.HasWafer((int)_moveTask.RobotHand))
  468. {
  469. if (!_tmRobot.Pick(_moveTask.SourceModule, _moveTask.SourceSlot, _moveTask.RobotHand, 0, 0, false))
  470. {
  471. return Result.FAIL;
  472. }
  473. _source.WaitTransfer(ModuleName.TMRobot);
  474. }
  475. if (!_tmRobot.IsAvailable)
  476. return Result.RUN;
  477. }
  478. else
  479. {
  480. if (!_tmRobot.IsAvailable)
  481. return Result.RUN;
  482. if (_source.IsWaitTransfer(ModuleName.TMRobot))
  483. _source.StopWaitTransfer(ModuleName.TMRobot);
  484. }
  485. }
  486. //place
  487. if (_moveTask.DestinationModule != ModuleName.TMRobot)
  488. {
  489. if (!_destination.IsAvailable)
  490. return Result.RUN;
  491. if (_destination.NoWafer(_moveTask.DestinationSlot))
  492. {
  493. if (!_destination.IsReadyForPlace(ModuleName.TMRobot, GetAvailableHand(ModuleName.TMRobot), _moveTask.DestinationSlot))
  494. {
  495. if (!_destination.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, _moveTask.DestinationSlot))
  496. return Result.FAIL;
  497. }
  498. if (!_destination.IsAvailable)
  499. return Result.RUN;
  500. if (_tmRobot.HasWafer((int)_moveTask.RobotHand))
  501. {
  502. if (!_tmRobot.Place(_moveTask.DestinationModule, _moveTask.DestinationSlot, _moveTask.RobotHand, 0, 0, false))
  503. return Result.FAIL;
  504. _destination.WaitTransfer(ModuleName.TMRobot);
  505. }
  506. if (!_tmRobot.IsAvailable)
  507. return Result.RUN;
  508. }
  509. else
  510. {
  511. if (!_tmRobot.IsAvailable)
  512. return Result.RUN;
  513. if (_destination.IsWaitTransfer(ModuleName.TMRobot))
  514. _destination.StopWaitTransfer(ModuleName.TMRobot);
  515. }
  516. }
  517. return Result.RUN;
  518. }
  519. public void Abort()
  520. {
  521. Clear();
  522. }
  523. public void Clear()
  524. {
  525. _tmRobot.ResetTask();
  526. _source?.ResetTask();
  527. _destination?.ResetTask();
  528. }
  529. public Hand GetAvailableHand(ModuleName module)
  530. {
  531. var wafers = WaferManager.Instance.GetWafers(module);
  532. return _tmRobot.Blade1Enable && wafers[0].IsEmpty ? Hand.Blade1 : Hand.Blade2;
  533. }
  534. }
  535. }