optimize_get_rune_list.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <?php
  2. /**
  3. * File for the rune optimization action.
  4. *
  5. * Implements an action function to be called from the {@see Controller}.
  6. *
  7. * @author Iñigo Valentin <i@inigovalentin.com>
  8. * @license https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License V3
  9. * @package SWDB
  10. */
  11. /**
  12. * Selects the runes for optimization.
  13. *
  14. * Reads the POST parameters looking for the following KEYS:
  15. * player: Player ID.
  16. * mode: Game mode ({@see GAME_MODE_ID}).
  17. * unit: Unit ID.
  18. * source: Source of the runes to select (assigned, unassigned, ...).
  19. * tuning: 1: All +12; 2: Even +15, odd + 12; 3: All +15.
  20. * set[]: Selected rune sets ({@see RUNE_SET_ID}).
  21. *
  22. * Then it selects all the runes matching the cryteria.
  23. *
  24. * @return int|string a JSON with the runes on success, negative integers on error. 0 if no errors
  25. * ocurred, but no results were found.
  26. * @category Action
  27. */
  28. function action(){
  29. // Increase max execution time.
  30. set_time_limit(60);
  31. $candidates = [
  32. 1 => [],
  33. 2 => [],
  34. 3 => [],
  35. 4 => [],
  36. 5 => [],
  37. 6 => []
  38. ];
  39. $response = null;
  40. $player = filter_input(INPUT_POST, 'player');
  41. if ($player == null){
  42. return -1;
  43. }
  44. $game_mode = GAME_MODE_ID::NORMAL;
  45. if (filter_input(INPUT_POST, 'mode') == GAME_MODE_ID::RTA){
  46. $game_mode = GAME_MODE_ID::RTA;
  47. }
  48. $unit_id = filter_input(INPUT_POST, 'unit');
  49. if ($unit_id == null){
  50. return -2;
  51. }
  52. // Sets
  53. $sets = [];
  54. foreach ($_POST["set"] as $x){
  55. array_push($sets, intval($x));
  56. }
  57. if (sizeof($sets) < 2 || sizeof($sets) > 3){
  58. return -3;
  59. }
  60. $focus = [];
  61. if (isset($_POST["focus_0"]) && intval($_POST["focus_0"]) > 0){
  62. array_push($focus, intval($_POST["focus_0"]));
  63. }
  64. if (isset($_POST["focus_1"]) && intval($_POST["focus_1"]) > 0){
  65. array_push($focus, intval($_POST["focus_1"]));
  66. }
  67. if (isset($_POST["focus_2"]) && intval($_POST["focus_2"]) > 0){
  68. array_push($focus, intval($_POST["focus_2"]));
  69. }
  70. // Remove doubles and sort. The order will be HP, ATK, DEF, SPD, CRR, CRD, RES, ACC
  71. $focus = array_unique($focus, SORT_NUMERIC);
  72. // Main stats in even slots.
  73. $stats = [];
  74. foreach ($_POST["stat"] as $x){
  75. array_push($stats, intval($x));
  76. }
  77. $source = filter_input(INPUT_POST, 'source');
  78. if ($source == null){
  79. return -4;
  80. }
  81. $tuning = filter_input(INPUT_POST, 'tuning');
  82. if ($tuning == null){
  83. return -6;
  84. }
  85. // Instantiate the unit
  86. $unit = new Unit($unit_id);
  87. // Get build query:
  88. $base_s = "
  89. SELECT
  90. id,
  91. type,
  92. slot,
  93. level,
  94. stars,
  95. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::MAIN . " ) AS main_stat,
  96. (SELECT value FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::MAIN . " ) AS main_stat_value,
  97. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::INNATE . " ) AS innate_stat,
  98. (SELECT value FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::INNATE . " ) AS innate_stat_value,
  99. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_1 . " ) AS substat_1,
  100. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_1 . " ) AS substat_1_value,
  101. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_2 . " ) AS substat_2,
  102. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_2 . " ) AS substat_2_value,
  103. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_3 . " ) AS substat_3,
  104. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_3 . " ) AS substat_3_value,
  105. (SELECT stat FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_4 . " ) AS substat_4,
  106. (SELECT value + grind FROM rune_stat WHERE rune = rune.id AND slot = " . RUNE_STAT_SLOT_ID::SUBSTAT_4 . " ) AS substat_4_value
  107. FROM rune
  108. WHERE
  109. player = :player AND
  110. type IN (
  111. ";
  112. foreach ($sets as $set){
  113. $base_s .= ($set . ",");
  114. }
  115. $base_s .= "-1) AND ";
  116. switch ($source){
  117. case 0: // Storage only (or itself)
  118. $base_s .= "
  119. (
  120. rune.id IN (SELECT DISTINCT rune FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  121. OR
  122. rune.id NOT IN (SELECT DISTINCT rune FROM unit_rune WHERE rta = " . $game_mode . ")
  123. )";
  124. break;
  125. case 1: // Units in no teams (or itself)
  126. $base_s .= "
  127. (
  128. rune.id IN (SELECT DISTINCT rune FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  129. OR rune.id NOT IN (SELECT DISTINCT rune FROM unit_rune WHERE rta = " . $game_mode . ")
  130. OR rune.id NOT IN (SELECT DISTINCT rune FROM unit_rune WHERE rta = " . $game_mode . " AND unit NOT IN (SELECT DISTINCT unit FROM team_unit))
  131. )
  132. ";
  133. break;
  134. case 2: // Units in teams with 0 score (or itself)
  135. $base_s .= "
  136. (
  137. rune.id IN (SELECT DISTINCT rune FROM unit_rune WHERE unit = :unit_id AND rta = " . $game_mode . ")
  138. OR rune.id NOT IN (SELECT DISTINCT rune FROM unit_rune WHERE rta = " . $game_mode . ")
  139. OR rune.id NOT IN (
  140. SELECT DISTINCT rune
  141. FROM unit_rune
  142. WHERE
  143. rta = " . $game_mode . "
  144. AND unit NOT IN (
  145. SELECT DISTINCT unit
  146. FROM
  147. team,
  148. team_unit
  149. WHERE
  150. team.id = team_unit.team
  151. AND team.score > 0
  152. )
  153. )
  154. )
  155. ";
  156. break;
  157. case 3: // Units with lower overall score (or itself)
  158. // TODO
  159. break;
  160. case 4: // All runes - dont filter
  161. $base_s .= " 1 = 1 ";
  162. break;
  163. default: // Invalid options - return nothing
  164. $base_s .= " 1 = 0 ";
  165. }
  166. $s_order = " ORDER BY stars DESC, original_quality DESC, max_efficiency DESC, efficiency DESC, level DESC";
  167. //$s_in = " main_stat IN (:stat_0, :stat_1, :stat_2) ";
  168. $s_main = [
  169. " main_stat = :stat_0 ",
  170. " main_stat = :stat_1 ",
  171. " main_stat = :stat_2 ",
  172. ];
  173. // Process focuses
  174. $focus_stats = [];
  175. foreach ($focus as $f){
  176. switch ($f){
  177. case STAT_ID::HP:
  178. array_push($focus_stats, RUNE_STAT_ID::HP);
  179. array_push($focus_stats, RUNE_STAT_ID::HP_P);
  180. break;
  181. case STAT_ID::ATK:
  182. array_push($focus_stats, RUNE_STAT_ID::ATK);
  183. array_push($focus_stats, RUNE_STAT_ID::ATK_P);
  184. break;
  185. case STAT_ID::DEF:
  186. array_push($focus_stats, RUNE_STAT_ID::DEF);
  187. array_push($focus_stats, RUNE_STAT_ID::DEF_P);
  188. break;
  189. case STAT_ID::SPD:
  190. array_push($focus_stats, RUNE_STAT_ID::SPD);
  191. break;
  192. case STAT_ID::CRR:
  193. array_push($focus_stats, RUNE_STAT_ID::CRR);
  194. break;
  195. case STAT_ID::CRD:
  196. array_push($focus_stats, RUNE_STAT_ID::CRD);
  197. break;
  198. case STAT_ID::ACC:
  199. array_push($focus_stats, RUNE_STAT_ID::ACC);
  200. break;
  201. case STAT_ID::RES:
  202. array_push($focus_stats, RUNE_STAT_ID::RES);
  203. break;
  204. }
  205. }
  206. $focus_cond = ["", "", "", "", "", "", ""];
  207. if (sizeof($focus) > 0){
  208. // Slot 1, no ATK flat, no DEF flat, no DEF %
  209. $focus_slot = $focus_stats;
  210. /*if (array_search(RUNE_STAT_ID::ATK, $focus_slot) !== false){
  211. $focus_slot = array_diff($focus_slot, [RUNE_STAT_ID::ATK])//array_splice($focus_slot, array_search(RUNE_STAT_ID::ATK, $focus_slot), 1);
  212. }
  213. if (array_search(RUNE_STAT_ID::DEF, $focus_slot) !== false){
  214. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::DEF, $focus_slot), 1);
  215. }
  216. if (array_search(RUNE_STAT_ID::DEF_P, $focus_slot) !== false){
  217. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::DEF_P, $focus_slot), 1);
  218. }*/
  219. $focus_slot = array_diff($focus_slot, [RUNE_STAT_ID::ATK, RUNE_STAT_ID::DEF, RUNE_STAT_ID::DEF_P]);
  220. if (sizeof($focus_slot) > 0){
  221. $focus_cond[1] .= "
  222. -- FOCUS 1
  223. AND (
  224. rune.id IN (
  225. SELECT DISTINCT rune FROM rune_stat WHERE slot != :slot_main AND stat IN
  226. (
  227. ";
  228. foreach ($focus_slot as $stat){
  229. $focus_cond[1] .= $stat . ", ";
  230. }
  231. $focus_cond[1] = rtrim($focus_cond[1], ", ");
  232. $focus_cond[1] .= "
  233. )
  234. )
  235. ) -- END FOCUS 1
  236. ";
  237. }
  238. // Slot 3, no ATK flat, no ATK %, no DEF flat.
  239. $focus_slot = $focus_stats;
  240. /*if (array_search(RUNE_STAT_ID::ATK, $focus_slot) !== false){
  241. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::ATK, $focus_slot), 1);
  242. }
  243. if (array_search(RUNE_STAT_ID::ATK_P, $focus_slot) !== false){
  244. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::ATK_P, $focus_slot), 1);
  245. }
  246. if (array_search(RUNE_STAT_ID::DEF, $focus_slot) !== false){
  247. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::DEF, $focus_slot), 1);
  248. }*/
  249. $focus_slot = array_diff($focus_slot, [RUNE_STAT_ID::ATK, RUNE_STAT_ID::ATK_P, RUNE_STAT_ID::DEF]);
  250. if (sizeof($focus_slot) > 0){
  251. $focus_cond[3] .= "
  252. -- FOCUS 3
  253. AND (
  254. rune.id IN (
  255. SELECT DISTINCT rune FROM rune_stat WHERE slot != :slot_main AND stat IN
  256. (
  257. ";
  258. foreach ($focus_slot as $stat){
  259. $focus_cond[3] .= $stat . ", ";
  260. }
  261. $focus_cond[3] = rtrim($focus_cond[3], ", ");
  262. $focus_cond[3] .= "
  263. )
  264. )
  265. ) -- END FOCUS 3
  266. ";
  267. }
  268. // Slot 5, no HP flat.
  269. $focus_slot = $focus_stats;
  270. /*if (array_search(RUNE_STAT_ID::HP, $focus_slot) !== false){
  271. $focus_slot = array_splice($focus_slot, array_search(RUNE_STAT_ID::HP, $focus_slot), 1);
  272. }*/
  273. $focus_slot = array_diff($focus_slot, [RUNE_STAT_ID::HP]);
  274. if (sizeof($focus_slot) > 0){
  275. $focus_cond[5] .= "
  276. -- FOCUS 5
  277. AND (
  278. rune.id IN (
  279. SELECT DISTINCT rune FROM rune_stat WHERE slot != :slot_main AND stat IN
  280. (
  281. ";
  282. foreach ($focus_slot as $stat){
  283. $focus_cond[5] .= $stat . ", ";
  284. }
  285. $focus_cond[5] = rtrim($focus_cond[5], ", ");
  286. $focus_cond[5] .= "
  287. )
  288. )
  289. ) -- END FOCUS 5
  290. ";
  291. }
  292. // TODO: Focus for even slots.
  293. // Slot 2, all stat, but include main
  294. // Slot 5, no HP flat.
  295. $focus_slot = $focus_stats;
  296. if (sizeof($focus_slot) > 0){
  297. $focus_cond[2] .= "
  298. -- FOCUS EVEN
  299. AND (
  300. rune.id IN (
  301. SELECT DISTINCT rune FROM rune_stat WHERE stat IN
  302. (
  303. ";
  304. foreach ($focus_slot as $stat){
  305. $focus_cond[2] .= $stat . ", ";
  306. }
  307. $focus_cond[2] = rtrim($focus_cond[2], ", ");
  308. $focus_cond[2] .= "
  309. )
  310. )
  311. ) -- END FOCUS EVEN
  312. ";
  313. }
  314. }
  315. //TODO DEBUG
  316. $focus_cond[2] = "";
  317. $s = ["", "", "", "", "", "", ""];
  318. $s[1] = $base_s . " AND slot = 1 " . $focus_cond[1] . $s_order . " LIMIT :limit_odd;";
  319. $s[3] = $base_s . " AND slot = 3 " . $focus_cond[3] . $s_order . " LIMIT :limit_odd;";
  320. $s[5] = $base_s . " AND slot = 5 " . $focus_cond[5] . $s_order . " LIMIT :limit_odd;";
  321. $s[2] = $base_s . " AND slot = 2 AND " . $s_main[0] . $focus_cond[2] . $s_order . " LIMIT :limit_even;";
  322. $s[4] = $base_s . " AND slot = 4 AND " . $s_main[1] . $focus_cond[2] . $s_order . " LIMIT :limit_even;";
  323. $s[6] = $base_s . " AND slot = 6 AND " . $s_main[2] . $focus_cond[2] . $s_order . " LIMIT :limit_even;";
  324. $total_candidates = 0;
  325. for ($i = 1; $i <= 6; $i ++){
  326. //error_log($s[$i]);
  327. $statement = get_context()->get_db()->prepare($s[$i]);
  328. $statement->bindValue(':player', $player, SQLITE3_TEXT);
  329. $statement->bindValue(':unit_id', $unit_id, SQLITE3_TEXT);
  330. $statement->bindValue(':stat_0', $stats[0], SQLITE3_TEXT);
  331. $statement->bindValue(':stat_1', $stats[1], SQLITE3_TEXT);
  332. $statement->bindValue(':stat_2', $stats[2], SQLITE3_TEXT);
  333. $statement->bindValue(':slot_main', RUNE_STAT_SLOT_ID::MAIN, SQLITE3_INTEGER);
  334. $statement->bindValue(':limit_even', 150, SQLITE3_INTEGER);
  335. $statement->bindValue(':limit_odd', 100, SQLITE3_INTEGER);
  336. //error_log($statement->getSQL(true));
  337. $q = $statement->execute();
  338. while ($r = $q->fetchArray(SQLITE3_ASSOC)){
  339. $rune = create_rune_array($unit, $r, $tuning);
  340. //array_push($candidates[$i], new Rune($r["id"]));
  341. array_push($candidates[$i], $rune);
  342. $total_candidates ++;
  343. }
  344. }
  345. //$max_combinations = sizeof($candidates[1]) * sizeof($candidates[2]) * sizeof($candidates[3]) * sizeof($candidates[4]) * sizeof($candidates[5]) * sizeof($candidates[6]);
  346. // Build response
  347. $response = json_encode($candidates);
  348. if ($response == null){
  349. return 0;
  350. }
  351. else{
  352. return $response;
  353. }
  354. }
  355. /**
  356. * Creates an array with the stats provided by a rune on a unit.
  357. *
  358. * @param Unit $unit Target unit.
  359. * @param int $r Rune main stat ID.
  360. * @param int $stars Rune stars.
  361. * @return int Value of the main stat at the selected level.
  362. */
  363. function create_rune_array($unit, $r, $tuning){
  364. $rune = [
  365. "ID" => $r["id"],
  366. "TYPE" => $r["type"],
  367. "ATK" => 0,
  368. "DEF" => 0,
  369. "HP" => 0,
  370. "SPD" => 0,
  371. "CRR" => 0,
  372. "CRD" => 0,
  373. "ACC" => 0,
  374. "RES" => 0
  375. ];
  376. // Calculate main stat value based on requested level.
  377. $level = $r["level"];
  378. $main_value = $r["main_stat_value"];
  379. switch ($tuning){
  380. case 1: // All +12
  381. if ($level < 12){
  382. $main_value = get_main_stat_at_level(12, $r["main_stat"], $r["stars"]);
  383. }
  384. break;
  385. case 2: // Even +15, Odd + 12
  386. if ($level < 15 && $r["slot"] % 2 == 0){
  387. $main_value = get_main_stat_at_level(15, $r["main_stat"], $r["stars"]);
  388. }
  389. elseif ($level < 12 && $r["slot"] % 2 != 0){
  390. $main_value = get_main_stat_at_level(12, $r["main_stat"], $r["stars"]);
  391. }
  392. break;
  393. case 3: // All +15
  394. if ($level < 15){
  395. $main_value = get_main_stat_at_level(15, $r["main_stat"], $r["stars"]);
  396. }
  397. break;
  398. }
  399. // Array to loop.
  400. $stats = [
  401. [
  402. "STAT" => $r["main_stat"],
  403. "VALUE" => $main_value
  404. ],
  405. [
  406. "STAT" => $r["innate_stat"],
  407. "VALUE" => $r["innate_stat_value"]
  408. ],
  409. [
  410. "STAT" => $r["substat_1"],
  411. "VALUE" => $r["substat_1_value"]
  412. ],
  413. [
  414. "STAT" => $r["substat_2"],
  415. "VALUE" => $r["substat_2_value"]
  416. ],
  417. [
  418. "STAT" => $r["substat_3"],
  419. "VALUE" => $r["substat_3_value"]
  420. ],
  421. [
  422. "STAT" => $r["substat_4"],
  423. "VALUE" => $r["substat_4_value"]
  424. ]
  425. ];
  426. foreach ($stats as $stat){
  427. switch ($stat["STAT"]){
  428. case RUNE_STAT_ID::ATK:
  429. $rune["ATK"] += $stat["VALUE"];
  430. break;
  431. case RUNE_STAT_ID::ATK_P:
  432. $rune["ATK"] += ($unit->get_base_stats()["atk"] * $stat["VALUE"] / 100);
  433. break;
  434. case RUNE_STAT_ID::DEF:
  435. $rune["DEF"] += $stat["VALUE"];
  436. break;
  437. case RUNE_STAT_ID::DEF_P:
  438. $rune["DEF"] += ($unit->get_base_stats()["def"] * $stat["VALUE"] / 100);
  439. break;
  440. case RUNE_STAT_ID::HP:
  441. $rune["HP"] += $stat["VALUE"];
  442. break;
  443. case RUNE_STAT_ID::HP_P:
  444. $rune["HP"] += ($unit->get_base_stats()["hp"] * $stat["VALUE"] / 100);
  445. break;
  446. case RUNE_STAT_ID::SPD:
  447. $rune["SPD"] += $stat["VALUE"];
  448. break;
  449. case RUNE_STAT_ID::CRR:
  450. $rune["CRR"] += $stat["VALUE"];
  451. break;
  452. case RUNE_STAT_ID::CRD:
  453. $rune["CRD"] += $stat["VALUE"];
  454. break;
  455. case RUNE_STAT_ID::ACC:
  456. $rune["ACC"] += $stat["VALUE"];
  457. break;
  458. case RUNE_STAT_ID::RES:
  459. $rune["RES"] += $stat["VALUE"];
  460. break;
  461. }
  462. }
  463. return $rune;
  464. }
  465. /**
  466. * Gets the value of the main stat at an arbitrary level.
  467. *
  468. * @param int $level Desired level.
  469. * @param int $stat Rune main stat ID.
  470. * @param int $stars Rune stars.
  471. * @return int Value of the main stat at the selected level.
  472. */
  473. function get_main_stat_at_level($level, $stat, $stars){
  474. $level = intval($level);
  475. if ($level < 0 || $level > 15){
  476. return 0;
  477. }
  478. switch ($stat){
  479. case RUNE_STAT_ID::HP:
  480. return RUNE_STAT_VALUES::HP[$stars][$level];
  481. case RUNE_STAT_ID::HP_P:
  482. return RUNE_STAT_VALUES::HP_P[$stars][$level];
  483. case RUNE_STAT_ID::ATK:
  484. return RUNE_STAT_VALUES::ATK[$stars][$level];
  485. case RUNE_STAT_ID::ATK_P:
  486. return RUNE_STAT_VALUES::ATK_P[$stars][$level];
  487. case RUNE_STAT_ID::DEF:
  488. return RUNE_STAT_VALUES::DEF[$stars][$level];
  489. case RUNE_STAT_ID::DEF_P:
  490. return RUNE_STAT_VALUES::DEF_P[$stars][$level];
  491. case RUNE_STAT_ID::SPD:
  492. return RUNE_STAT_VALUES::SPD[$stars][$level];
  493. case RUNE_STAT_ID::CRR:
  494. return RUNE_STAT_VALUES::CRR[$stars][$level];
  495. case RUNE_STAT_ID::CRD:
  496. return RUNE_STAT_VALUES::CRD[$stars][$level];
  497. case RUNE_STAT_ID::RES:
  498. return RUNE_STAT_VALUES::RES[$stars][$level];
  499. case RUNE_STAT_ID::ACC:
  500. return RUNE_STAT_VALUES::ACC[$stars][$level];
  501. default:
  502. return 0;
  503. }
  504. }