PageRenderTime 57ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmath/tests/v3dmath_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 526 lines | 472 code | 27 blank | 27 comment | 108 complexity | 72071fa6258f0e102d82154e94d45e9f MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file v3dmath_test.cpp
  3. * @author Adroit
  4. * @date 2007-03
  5. * @brief v3dmath test cases.
  6. *
  7. * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "linden_common.h"
  29. #include "llsd.h"
  30. #include "../test/lltut.h"
  31. #include "../m3math.h"
  32. #include "../v4math.h"
  33. #include "../v3dmath.h"
  34. #include "../v3dmath.h"
  35. #include "../llquaternion.h"
  36. namespace tut
  37. {
  38. struct v3dmath_data
  39. {
  40. };
  41. typedef test_group<v3dmath_data> v3dmath_test;
  42. typedef v3dmath_test::object v3dmath_object;
  43. tut::v3dmath_test v3dmath_testcase("v3dmath_h");
  44. template<> template<>
  45. void v3dmath_object::test<1>()
  46. {
  47. LLVector3d vec3D;
  48. ensure("1:LLVector3d:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ])));
  49. F64 x = 2.32f, y = 1.212f, z = -.12f;
  50. LLVector3d vec3Da(x,y,z);
  51. ensure("2:LLVector3d:Fail to initialize ", ((2.32f == vec3Da.mdV[VX]) && (1.212f == vec3Da.mdV[VY]) && (-.12f == vec3Da.mdV[VZ])));
  52. const F64 vec[3] = {1.2f ,3.2f, -4.2f};
  53. LLVector3d vec3Db(vec);
  54. ensure("3:LLVector3d:Fail to initialize ", ((1.2f == vec3Db.mdV[VX]) && (3.2f == vec3Db.mdV[VY]) && (-4.2f == vec3Db.mdV[VZ])));
  55. LLVector3 vec3((F32)x,(F32)y,(F32)z);
  56. LLVector3d vec3Dc(vec3);
  57. ensure_equals("4:LLVector3d Fail to initialize",vec3Da,vec3Dc);
  58. }
  59. template<> template<>
  60. void v3dmath_object::test<2>()
  61. {
  62. S32 a = -235;
  63. LLSD llsd(a);
  64. LLVector3d vec3d(llsd);
  65. LLSD sd = vec3d.getValue();
  66. LLVector3d vec3da(sd);
  67. ensure("1:getValue:Fail ", (vec3d == vec3da));
  68. }
  69. template<> template<>
  70. void v3dmath_object::test<3>()
  71. {
  72. F64 a = 232345521.411132;
  73. LLSD llsd(a);
  74. LLVector3d vec3d;
  75. vec3d.setValue(llsd);
  76. LLSD sd = vec3d.getValue();
  77. LLVector3d vec3da(sd);
  78. ensure("1:setValue:Fail to initialize ", (vec3d == vec3da));
  79. }
  80. template<> template<>
  81. void v3dmath_object::test<4>()
  82. {
  83. F64 a[3] = {222231.43222, 12345.2343, -434343.33222};
  84. LLSD llsd;
  85. llsd[0] = a[0];
  86. llsd[1] = a[1];
  87. llsd[2] = a[2];
  88. LLVector3d vec3D;
  89. vec3D = (LLVector3d)llsd;
  90. ensure("1:operator=:Fail to initialize ", ((llsd[0].asReal()== vec3D.mdV[VX]) && (llsd[1].asReal() == vec3D.mdV[VY]) && (llsd[2].asReal() == vec3D.mdV[VZ])));
  91. }
  92. template<> template<>
  93. void v3dmath_object::test<5>()
  94. {
  95. F64 x = 2.32f, y = 1.212f, z = -.12f;
  96. LLVector3d vec3D(x,y,z);
  97. vec3D.clearVec();
  98. ensure("1:clearVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ])));
  99. vec3D.setVec(x,y,z);
  100. ensure("2:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ])));
  101. vec3D.zeroVec();
  102. ensure("3:zeroVec:Fail to initialize ", ((0 == vec3D.mdV[VX]) && (0 == vec3D.mdV[VY]) && (0 == vec3D.mdV[VZ])));
  103. vec3D.clearVec();
  104. LLVector3 vec3((F32)x,(F32)y,(F32)z);
  105. vec3D.setVec(vec3);
  106. ensure("4:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ])));
  107. vec3D.clearVec();
  108. const F64 vec[3] = {x,y,z};
  109. vec3D.setVec(vec);
  110. ensure("5:setVec:Fail to initialize ", ((x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (z == vec3D.mdV[VZ])));
  111. LLVector3d vec3Da;
  112. vec3Da.setVec(vec3D);
  113. ensure_equals("6:setVec: Fail to initialize", vec3D, vec3Da);
  114. }
  115. template<> template<>
  116. void v3dmath_object::test<6>()
  117. {
  118. F64 x = -2.32, y = 1.212, z = -.12;
  119. LLVector3d vec3D(x,y,z);
  120. vec3D.abs();
  121. ensure("1:abs:Fail ", ((-x == vec3D.mdV[VX]) && (y == vec3D.mdV[VY]) && (-z == vec3D.mdV[VZ])));
  122. ensure("2:isNull():Fail ", (FALSE == vec3D.isNull()));
  123. vec3D.clearVec();
  124. x =.00000001, y = .000001001, z = .000001001;
  125. vec3D.setVec(x,y,z);
  126. ensure("3:isNull():Fail ", (TRUE == vec3D.isNull()));
  127. ensure("4:isExactlyZero():Fail ", (FALSE == vec3D.isExactlyZero()));
  128. x =.0000000, y = .00000000, z = .00000000;
  129. vec3D.setVec(x,y,z);
  130. ensure("5:isExactlyZero():Fail ", (TRUE == vec3D.isExactlyZero()));
  131. }
  132. template<> template<>
  133. void v3dmath_object::test<7>()
  134. {
  135. F64 x = -2.32, y = 1.212, z = -.12;
  136. LLVector3d vec3D(x,y,z);
  137. ensure("1:operator [] failed",( x == vec3D[0]));
  138. ensure("2:operator [] failed",( y == vec3D[1]));
  139. ensure("3:operator [] failed",( z == vec3D[2]));
  140. vec3D.clearVec();
  141. x = 23.23, y = -.2361, z = 3.25;
  142. vec3D.setVec(x,y,z);
  143. F64 &ref1 = vec3D[0];
  144. ensure("4:operator [] failed",( ref1 == vec3D[0]));
  145. F64 &ref2 = vec3D[1];
  146. ensure("5:operator [] failed",( ref2 == vec3D[1]));
  147. F64 &ref3 = vec3D[2];
  148. ensure("6:operator [] failed",( ref3 == vec3D[2]));
  149. }
  150. template<> template<>
  151. void v3dmath_object::test<8>()
  152. {
  153. F32 x = 1.f, y = 2.f, z = -1.f;
  154. LLVector4 vec4(x,y,z);
  155. LLVector3d vec3D;
  156. vec3D = vec4;
  157. ensure("1:operator=:Fail to initialize ", ((vec4.mV[VX] == vec3D.mdV[VX]) && (vec4.mV[VY] == vec3D.mdV[VY]) && (vec4.mV[VZ] == vec3D.mdV[VZ])));
  158. }
  159. template<> template<>
  160. void v3dmath_object::test<9>()
  161. {
  162. F64 x1 = 1.78787878, y1 = 232322.2121, z1 = -12121.121212;
  163. F64 x2 = 1.2, y2 = 2.5, z2 = 1.;
  164. LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db;
  165. vec3Db = vec3Da+ vec3D;
  166. ensure("1:operator+:Fail to initialize ", ((x1+x2 == vec3Db.mdV[VX]) && (y1+y2 == vec3Db.mdV[VY]) && (z1+z2 == vec3Db.mdV[VZ])));
  167. x1 = -2.45, y1 = 2.1, z1 = 3.0;
  168. vec3D.clearVec();
  169. vec3Da.clearVec();
  170. vec3D.setVec(x1,y1,z1);
  171. vec3Da += vec3D;
  172. ensure_equals("2:operator+=: Fail to initialize", vec3Da,vec3D);
  173. vec3Da += vec3D;
  174. ensure("3:operator+=:Fail to initialize ", ((2*x1 == vec3Da.mdV[VX]) && (2*y1 == vec3Da.mdV[VY]) && (2*z1 == vec3Da.mdV[VZ])));
  175. }
  176. template<> template<>
  177. void v3dmath_object::test<10>()
  178. {
  179. F64 x1 = 1., y1 = 2., z1 = -1.1;
  180. F64 x2 = 1.2, y2 = 2.5, z2 = 1.;
  181. LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2),vec3Db;
  182. vec3Db = vec3Da - vec3D;
  183. ensure("1:operator-:Fail to initialize ", ((x2-x1 == vec3Db.mdV[VX]) && (y2-y1 == vec3Db.mdV[VY]) && (z2-z1 == vec3Db.mdV[VZ])));
  184. x1 = -2.45, y1 = 2.1, z1 = 3.0;
  185. vec3D.clearVec();
  186. vec3Da.clearVec();
  187. vec3D.setVec(x1,y1,z1);
  188. vec3Da -=vec3D;
  189. ensure("2:operator-=:Fail to initialize ", ((2.45 == vec3Da.mdV[VX]) && (-2.1 == vec3Da.mdV[VY]) && (-3.0 == vec3Da.mdV[VZ])));
  190. vec3Da -= vec3D;
  191. ensure("3:operator-=:Fail to initialize ", ((-2*x1 == vec3Da.mdV[VX]) && (-2*y1 == vec3Da.mdV[VY]) && (-2*z1 == vec3Da.mdV[VZ])));
  192. }
  193. template<> template<>
  194. void v3dmath_object::test<11>()
  195. {
  196. F64 x1 = 1., y1 = 2., z1 = -1.1;
  197. F64 x2 = 1.2, y2 = 2.5, z2 = 1.;
  198. LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2);
  199. F64 res = vec3D * vec3Da;
  200. ensure_approximately_equals(
  201. "1:operator* failed",
  202. res,
  203. (x1*x2 + y1*y2 + z1*z2),
  204. 8);
  205. vec3Da.clearVec();
  206. F64 mulVal = 4.2;
  207. vec3Da = vec3D * mulVal;
  208. ensure_approximately_equals(
  209. "2a:operator* failed",
  210. vec3Da.mdV[VX],
  211. x1*mulVal,
  212. 8);
  213. ensure_approximately_equals(
  214. "2b:operator* failed",
  215. vec3Da.mdV[VY],
  216. y1*mulVal,
  217. 8);
  218. ensure_approximately_equals(
  219. "2c:operator* failed",
  220. vec3Da.mdV[VZ],
  221. z1*mulVal,
  222. 8);
  223. vec3Da.clearVec();
  224. vec3Da = mulVal * vec3D;
  225. ensure_approximately_equals(
  226. "3a:operator* failed",
  227. vec3Da.mdV[VX],
  228. x1*mulVal,
  229. 8);
  230. ensure_approximately_equals(
  231. "3b:operator* failed",
  232. vec3Da.mdV[VY],
  233. y1*mulVal,
  234. 8);
  235. ensure_approximately_equals(
  236. "3c:operator* failed",
  237. vec3Da.mdV[VZ],
  238. z1*mulVal,
  239. 8);
  240. vec3D *= mulVal;
  241. ensure_approximately_equals(
  242. "4a:operator*= failed",
  243. vec3D.mdV[VX],
  244. x1*mulVal,
  245. 8);
  246. ensure_approximately_equals(
  247. "4b:operator*= failed",
  248. vec3D.mdV[VY],
  249. y1*mulVal,
  250. 8);
  251. ensure_approximately_equals(
  252. "4c:operator*= failed",
  253. vec3D.mdV[VZ],
  254. z1*mulVal,
  255. 8);
  256. }
  257. template<> template<>
  258. void v3dmath_object::test<12>()
  259. {
  260. F64 x1 = 1., y1 = 2., z1 = -1.1;
  261. F64 x2 = 1.2, y2 = 2.5, z2 = 1.;
  262. F64 val1, val2, val3;
  263. LLVector3d vec3D(x1,y1,z1),vec3Da(x2,y2,z2), vec3Db;
  264. vec3Db = vec3D % vec3Da;
  265. val1 = y1*z2 - y2*z1;
  266. val2 = z1*x2 -z2*x1;
  267. val3 = x1*y2-x2*y1;
  268. ensure("1:operator% failed",(val1 == vec3Db.mdV[VX]) && (val2 == vec3Db.mdV[VY]) && (val3 == vec3Db.mdV[VZ]));
  269. vec3D %= vec3Da;
  270. ensure("2:operator%= failed",
  271. is_approx_equal(vec3D.mdV[VX],vec3Db.mdV[VX]) &&
  272. is_approx_equal(vec3D.mdV[VY],vec3Db.mdV[VY]) &&
  273. is_approx_equal(vec3D.mdV[VZ],vec3Db.mdV[VZ]) );
  274. }
  275. template<> template<>
  276. void v3dmath_object::test<13>()
  277. {
  278. F64 x1 = 1., y1 = 2., z1 = -1.1,div = 4.2;
  279. F64 t = 1.f / div;
  280. LLVector3d vec3D(x1,y1,z1), vec3Da;
  281. vec3Da = vec3D/div;
  282. ensure_approximately_equals(
  283. "1a:operator/ failed",
  284. vec3Da.mdV[VX],
  285. x1*t,
  286. 8);
  287. ensure_approximately_equals(
  288. "1b:operator/ failed",
  289. vec3Da.mdV[VY],
  290. y1*t,
  291. 8);
  292. ensure_approximately_equals(
  293. "1c:operator/ failed",
  294. vec3Da.mdV[VZ],
  295. z1*t,
  296. 8);
  297. x1 = 1.23, y1 = 4., z1 = -2.32;
  298. vec3D.clearVec();
  299. vec3Da.clearVec();
  300. vec3D.setVec(x1,y1,z1);
  301. vec3Da = vec3D/div;
  302. ensure_approximately_equals(
  303. "2a:operator/ failed",
  304. vec3Da.mdV[VX],
  305. x1*t,
  306. 8);
  307. ensure_approximately_equals(
  308. "2b:operator/ failed",
  309. vec3Da.mdV[VY],
  310. y1*t,
  311. 8);
  312. ensure_approximately_equals(
  313. "2c:operator/ failed",
  314. vec3Da.mdV[VZ],
  315. z1*t,
  316. 8);
  317. vec3D /= div;
  318. ensure_approximately_equals(
  319. "3a:operator/= failed",
  320. vec3D.mdV[VX],
  321. x1*t,
  322. 8);
  323. ensure_approximately_equals(
  324. "3b:operator/= failed",
  325. vec3D.mdV[VY],
  326. y1*t,
  327. 8);
  328. ensure_approximately_equals(
  329. "3c:operator/= failed",
  330. vec3D.mdV[VZ],
  331. z1*t,
  332. 8);
  333. }
  334. template<> template<>
  335. void v3dmath_object::test<14>()
  336. {
  337. F64 x1 = 1., y1 = 2., z1 = -1.1;
  338. LLVector3d vec3D(x1,y1,z1), vec3Da;
  339. ensure("1:operator!= failed",(TRUE == (vec3D !=vec3Da)));
  340. vec3Da = vec3D;
  341. ensure("2:operator== failed",(vec3D ==vec3Da));
  342. vec3D.clearVec();
  343. vec3Da.clearVec();
  344. x1 = .211, y1 = 21.111, z1 = 23.22;
  345. vec3D.setVec(x1,y1,z1);
  346. vec3Da.setVec(x1,y1,z1);
  347. ensure("3:operator== failed",(vec3D ==vec3Da));
  348. ensure("4:operator!= failed",(FALSE == (vec3D !=vec3Da)));
  349. }
  350. template<> template<>
  351. void v3dmath_object::test<15>()
  352. {
  353. F64 x1 = 1., y1 = 2., z1 = -1.1;
  354. LLVector3d vec3D(x1,y1,z1), vec3Da;
  355. std::ostringstream stream1, stream2;
  356. stream1 << vec3D;
  357. vec3Da.setVec(x1,y1,z1);
  358. stream2 << vec3Da;
  359. ensure("1:operator << failed",(stream1.str() == stream2.str()));
  360. }
  361. template<> template<>
  362. void v3dmath_object::test<16>()
  363. {
  364. F64 x1 = 1.23, y1 = 2.0, z1 = 4.;
  365. std::string buf("1.23 2. 4");
  366. LLVector3d vec3D, vec3Da(x1,y1,z1);
  367. LLVector3d::parseVector3d(buf, &vec3D);
  368. ensure_equals("1:parseVector3d: failed " , vec3D, vec3Da);
  369. }
  370. template<> template<>
  371. void v3dmath_object::test<17>()
  372. {
  373. F64 x1 = 1., y1 = 2., z1 = -1.1;
  374. LLVector3d vec3D(x1,y1,z1), vec3Da;
  375. vec3Da = -vec3D;
  376. ensure("1:operator- failed", (vec3D == - vec3Da));
  377. }
  378. template<> template<>
  379. void v3dmath_object::test<18>()
  380. {
  381. F64 x = 1., y = 2., z = -1.1;
  382. LLVector3d vec3D(x,y,z);
  383. F64 res = (x*x + y*y + z*z) - vec3D.magVecSquared();
  384. ensure("1:magVecSquared:Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO)));
  385. res = (F32) sqrt(x*x + y*y + z*z) - vec3D.magVec();
  386. ensure("2:magVec: Fail ", ((-F_APPROXIMATELY_ZERO <= res)&& (res <=F_APPROXIMATELY_ZERO)));
  387. }
  388. template<> template<>
  389. void v3dmath_object::test<19>()
  390. {
  391. F64 x = 1., y = 2., z = -1.1;
  392. LLVector3d vec3D(x,y,z);
  393. F64 mag = vec3D.normVec();
  394. mag = 1.f/ mag;
  395. ensure_approximately_equals(
  396. "1a:normVec: Fail ",
  397. vec3D.mdV[VX],
  398. x * mag,
  399. 8);
  400. ensure_approximately_equals(
  401. "1b:normVec: Fail ",
  402. vec3D.mdV[VY],
  403. y * mag,
  404. 8);
  405. ensure_approximately_equals(
  406. "1c:normVec: Fail ",
  407. vec3D.mdV[VZ],
  408. z * mag,
  409. 8);
  410. x = 0.000000001, y = 0.000000001, z = 0.000000001;
  411. vec3D.clearVec();
  412. vec3D.setVec(x,y,z);
  413. mag = vec3D.normVec();
  414. ensure_approximately_equals(
  415. "2a:normVec: Fail ",
  416. vec3D.mdV[VX],
  417. x * mag,
  418. 8);
  419. ensure_approximately_equals(
  420. "2b:normVec: Fail ",
  421. vec3D.mdV[VY],
  422. y * mag,
  423. 8);
  424. ensure_approximately_equals(
  425. "2c:normVec: Fail ",
  426. vec3D.mdV[VZ],
  427. z * mag,
  428. 8);
  429. }
  430. template<> template<>
  431. void v3dmath_object::test<20>()
  432. {
  433. F64 x1 = 1111.232222;
  434. F64 y1 = 2222222222.22;
  435. F64 z1 = 422222222222.0;
  436. std::string buf("1111.232222 2222222222.22 422222222222");
  437. LLVector3d vec3Da, vec3Db(x1,y1,z1);
  438. LLVector3d::parseVector3d(buf, &vec3Da);
  439. ensure_equals("1:parseVector3 failed", vec3Da, vec3Db);
  440. }
  441. template<> template<>
  442. void v3dmath_object::test<21>()
  443. {
  444. F64 x1 = 1., y1 = 2., z1 = -1.1;
  445. F64 x2 = 1.2, y2 = 2.5, z2 = 1.;
  446. F64 val = 2.3f,val1,val2,val3;
  447. val1 = x1 + (x2 - x1)* val;
  448. val2 = y1 + (y2 - y1)* val;
  449. val3 = z1 + (z2 - z1)* val;
  450. LLVector3d vec3Da(x1,y1,z1),vec3Db(x2,y2,z2);
  451. LLVector3d vec3d = lerp(vec3Da,vec3Db,val);
  452. ensure("1:lerp failed", ((val1 ==vec3d.mdV[VX])&& (val2 ==vec3d.mdV[VY]) && (val3 ==vec3d.mdV[VZ])));
  453. }
  454. template<> template<>
  455. void v3dmath_object::test<22>()
  456. {
  457. F64 x = 2.32, y = 1.212, z = -.12;
  458. F64 min = 0.0001, max = 3.0;
  459. LLVector3d vec3d(x,y,z);
  460. ensure("1:clamp:Fail ", (TRUE == (vec3d.clamp(min, max))));
  461. x = 0.000001f, z = 5.3f;
  462. vec3d.setVec(x,y,z);
  463. ensure("2:clamp:Fail ", (TRUE == (vec3d.clamp(min, max))));
  464. }
  465. template<> template<>
  466. void v3dmath_object::test<23>()
  467. {
  468. F64 x = 10., y = 20., z = -15.;
  469. F64 epsilon = .23425;
  470. LLVector3d vec3Da(x,y,z), vec3Db(x,y,z);
  471. ensure("1:are_parallel: Fail ", (TRUE == are_parallel(vec3Da,vec3Db,epsilon)));
  472. F64 x1 = -12., y1 = -20., z1 = -100.;
  473. vec3Db.clearVec();
  474. vec3Db.setVec(x1,y1,z1);
  475. ensure("2:are_parallel: Fail ", (FALSE == are_parallel(vec3Da,vec3Db,epsilon)));
  476. }
  477. template<> template<>
  478. void v3dmath_object::test<24>()
  479. {
  480. #if LL_WINDOWS && _MSC_VER < 1400
  481. skip("This fails on VS2003!");
  482. #else
  483. F64 x = 10., y = 20., z = -15.;
  484. F64 angle1, angle2;
  485. LLVector3d vec3Da(x,y,z), vec3Db(x,y,z);
  486. angle1 = angle_between(vec3Da, vec3Db);
  487. ensure("1:angle_between: Fail ", (0 == angle1));
  488. F64 x1 = -1., y1 = -20., z1 = -1.;
  489. vec3Da.clearVec();
  490. vec3Da.setVec(x1,y1,z1);
  491. angle2 = angle_between(vec3Da, vec3Db);
  492. vec3Db.normVec();
  493. vec3Da.normVec();
  494. F64 angle = vec3Db*vec3Da;
  495. angle = acos(angle);
  496. ensure("2:angle_between: Fail ", (angle == angle2));
  497. #endif
  498. }
  499. }