evalform.class.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Script
  5. * @package chamilo.gradebook
  6. */
  7. /**
  8. * Init
  9. */
  10. require_once dirname(__FILE__).'/../../../inc/global.inc.php';
  11. require_once dirname(__FILE__).'/../be.inc.php';
  12. require_once dirname(__FILE__).'/../gradebook_functions.inc.php';
  13. /**
  14. * Extends formvalidator with add&edit forms for evaluations
  15. * @author Stijn Konings
  16. * @package chamilo.gradebook
  17. */
  18. $htmlHeadXtra[] = '<script>
  19. function setFocus(){
  20. $("#evaluation_title").focus();
  21. }
  22. $(document).ready(function () {
  23. setFocus();
  24. });
  25. </script>';
  26. class EvalForm extends FormValidator
  27. {
  28. const TYPE_ADD= 1;
  29. const TYPE_EDIT= 2;
  30. const TYPE_MOVE= 3;
  31. const TYPE_RESULT_ADD= 4;
  32. const TYPE_RESULT_EDIT= 5;
  33. const TYPE_ALL_RESULTS_EDIT= 6;
  34. const TYPE_ADD_USERS_TO_EVAL= 7;
  35. private $evaluation_object;
  36. private $result_object;
  37. private $extra;
  38. /**
  39. * Builds a form containing form items based on a given parameter
  40. * @param int form_type 1=add, 2=edit,3=move,4=result_add
  41. * @param obj cat_obj the category object
  42. * @param obj res_obj the result object
  43. * @param string form name
  44. * @param method
  45. * @param action
  46. */
  47. public function __construct($form_type, $evaluation_object, $result_object, $form_name, $method= 'post', $action= null, $extra1 = null, $extra2 = null) {
  48. parent::__construct($form_name, $method, $action);
  49. if (isset ($evaluation_object)) {
  50. $this->evaluation_object= $evaluation_object;
  51. }
  52. if (isset ($result_object)) {
  53. $this->result_object= $result_object;
  54. }
  55. if (isset ($extra1)) {
  56. $this->extra = $extra1;
  57. }
  58. switch ($form_type) {
  59. case self :: TYPE_EDIT:
  60. $this->build_editing_form();
  61. break;
  62. case self :: TYPE_ADD:
  63. $this->build_add_form();
  64. break;
  65. case self :: TYPE_MOVE:
  66. $this->build_editing_form();
  67. break;
  68. case self :: TYPE_RESULT_ADD:
  69. $this->build_result_add_form();
  70. break;
  71. case self :: TYPE_RESULT_EDIT:
  72. $this->build_result_edit_form();
  73. break;
  74. case self :: TYPE_ALL_RESULTS_EDIT:
  75. $this->build_all_results_edit_form();
  76. break;
  77. case self :: TYPE_ADD_USERS_TO_EVAL:
  78. $this->build_add_user_to_eval();
  79. break;
  80. }
  81. $this->setDefaults();
  82. }
  83. /**
  84. * This form will build a form to add users to an evaluation
  85. */
  86. protected function build_add_user_to_eval() {
  87. $this->addElement('header', get_lang('ChooseUser'));
  88. $select= $this->addElement('select', 'firstLetterUser', get_lang('FirstLetter'), null, array(
  89. 'onchange'=> 'document.add_users_to_evaluation.submit()'
  90. ));
  91. $select->addOption('','');
  92. for ($i = 65; $i <= 90; $i ++) {
  93. $letter = chr($i);
  94. if (isset($this->extra) && $this->extra == $letter) {
  95. $select->addOption($letter,$letter,'selected');
  96. } else {
  97. $select->addOption($letter,$letter);
  98. }
  99. }
  100. $select= $this->addElement('select', 'add_users', null, null, array (
  101. 'multiple' => 'multiple',
  102. 'size' => '15',
  103. 'style' => 'width:250px'
  104. ));
  105. foreach ($this->evaluation_object->get_not_subscribed_students() as $user) {
  106. if ( (!isset($this->extra)) || empty($this->extra) || api_strtoupper(api_substr($user[1],0,1)) == $this->extra ) {
  107. $select->addoption($user[1] . ' ' . $user[2] . ' (' . $user[3] . ')', $user[0]);
  108. }
  109. }
  110. $this->addElement('submit', 'submit_button', get_lang('AddUserToEval'));
  111. }
  112. /**
  113. * This function builds a form to edit all results in an evaluation
  114. */
  115. protected function build_all_results_edit_form() {
  116. //extra field for check on maxvalue
  117. $this->addElement('hidden', 'maxvalue', $this->evaluation_object->get_max());
  118. $this->addElement('hidden', 'minvalue', 0);
  119. $this->addElement('header', get_lang('EditResult'));
  120. $renderer =& $this->defaultRenderer();
  121. // set new form template
  122. $form_template = '<form{attributes}>
  123. <table class="data_table" border="0" cellpadding="5" cellspacing="5">{content}
  124. </table>
  125. </form>';
  126. $renderer->setFormTemplate($form_template);
  127. if (api_is_western_name_order()){
  128. $renderer->setHeaderTemplate(
  129. '<tr>
  130. <th>'.get_lang('OfficialCode').'</th>
  131. <th>'.get_lang('UserName').'</th>
  132. <th>'.get_lang('FirstName').'</th>
  133. <th>'.get_lang('LastName').'</th>
  134. <th>'.get_lang('Qualify').'</th>
  135. </tr>'
  136. );
  137. } else {
  138. $renderer->setHeaderTemplate(
  139. '<tr>
  140. <th>'.get_lang('OfficialCode').'</th>
  141. <th>'.get_lang('UserName').'</th>
  142. <th>'.get_lang('LastName').'</th>
  143. <th>'.get_lang('FirstName').'</th>
  144. <th>'.get_lang('Qualify').'</th>
  145. </tr>'
  146. );
  147. }
  148. $template_submit = '<tr>
  149. <td colspan="4" ></td>
  150. <td >
  151. {element}
  152. <!-- BEGIN error --><br /><span style="color: #ff0000;font-size:10px">{error}</span><!-- END error -->
  153. </td>
  154. </tr>';
  155. $results_and_users = array();
  156. foreach ($this->result_object as $result) {
  157. $user = api_get_user_info($result->get_user_id());
  158. $results_and_users[] = array ('result' => $result, 'user' => $user);
  159. }
  160. usort($results_and_users, array ('EvalForm', 'sort_by_user'));
  161. $defaults = array();
  162. foreach ($results_and_users as $result_and_user) {
  163. $user = $result_and_user['user'];
  164. $result = $result_and_user['result'];
  165. $renderer = &$this->defaultRenderer();
  166. $this->add_textfield('score[' . $result->get_id() . ']',
  167. $this->build_stud_label($user['user_id'], $user['username'], $user['lastname'], $user['firstname']),
  168. false,
  169. array ('class' => "span2",
  170. 'maxlength' => 5));
  171. $this->addRule('score[' . $result->get_id() . ']', get_lang('OnlyNumbers'), 'numeric');
  172. $this->addRule(array (
  173. 'score[' . $result->get_id() . ']', 'maxvalue'), get_lang('OverMax'), 'compare', '<=');
  174. $this->addRule(array (
  175. 'score[' . $result->get_id() . ']', 'minvalue'), get_lang('UnderMin'), 'compare', '>=');
  176. $defaults['score[' . $result->get_id() . ']'] = $result->get_score();
  177. if (api_is_western_name_order() ) {
  178. $user_info = '<td align="left" >'.$user['firstname'].'</td>';
  179. $user_info .= '<td align="left" >'.$user['lastname'].'</td>';
  180. } else {
  181. $user_info = '<td align="left" >'.$user['lastname'].'</td>';
  182. $user_info .= '<td align="left" >'.$user['firstname'].'</td>';
  183. }
  184. $template = '<tr>
  185. <td align="left" >'.$user['official_code'].'</td>
  186. <td align="left" >'.$user['username'].'</td>
  187. '.$user_info.'
  188. <td align="left">{element} / '.$this->evaluation_object->get_max().'
  189. <!-- BEGIN error --><br /><span style="color: #ff0000;font-size:10px">{error}</span><!-- END error -->
  190. </td>
  191. </tr>';
  192. $renderer->setElementTemplate($template,'score[' . $result->get_id() . ']');
  193. }
  194. $this->setDefaults($defaults);
  195. $this->addElement('style_submit_button', 'submit',get_lang('EditResult'),'class="save"');
  196. $renderer->setElementTemplate($template_submit,'submit');
  197. }
  198. /**
  199. * This function builds a form to move an item to another category
  200. *
  201. */
  202. protected function build_move_form() {
  203. $renderer = & $this->defaultRenderer();
  204. $renderer->setElementTemplate('<span>{element}</span> ');
  205. $this->addElement('static', null, null, '"'.$this->evaluation_object->get_name().'" ');
  206. $this->addElement('static', null, null, get_lang('MoveTo').' : ');
  207. $select= $this->addElement('select', 'move_cat', null, null);
  208. foreach ($this->evaluation_object->get_target_categories() as $cat) {
  209. for ($i= 0; $i < $cat[2]; $i++) {
  210. $line .= '&mdash;';
  211. }
  212. $select->addoption($line . ' ' . $cat[1], $cat[0]);
  213. $line= '';
  214. }
  215. $this->addElement('style_submit_button' , 'submit', get_lang('Ok'),'class="save"');
  216. }
  217. /**
  218. * Builds a result form containing inputs for all students with a given course_code
  219. */
  220. protected function build_result_add_form() {
  221. $renderer =& $this->defaultRenderer();
  222. $renderer->setFormTemplate(
  223. '<form{attributes}>
  224. <table class="data_table">
  225. {content}
  226. </table>
  227. </form>'
  228. );
  229. $courseInfo = api_get_course_info($this->evaluation_object->get_course_code());
  230. $tblusers = get_users_in_course($courseInfo['real_id']);
  231. $nr_users = 0;
  232. //extra field for check on maxvalue
  233. $this->addElement('hidden', 'maxvalue', $this->evaluation_object->get_max());
  234. $this->addElement('hidden', 'minvalue', 0);
  235. $this->addElement('header', get_lang('AddResult'));
  236. if (api_is_western_name_order()){
  237. $renderer->setHeaderTemplate(
  238. '<tr>
  239. <th>'.get_lang('OfficialCode').'</th>
  240. <th>'.get_lang('UserName').'</th>
  241. <th>'.get_lang('FirstName').'</th>
  242. <th>'.get_lang('LastName').'</th>
  243. <th>'.get_lang('Qualify').'</th>
  244. </tr>'
  245. );
  246. } else {
  247. $renderer->setHeaderTemplate(
  248. '<tr>
  249. <th>'.get_lang('OfficialCode').'</th>
  250. <th>'.get_lang('UserName').'</th>
  251. <th>'.get_lang('LastName').'</th>
  252. <th>'.get_lang('FirstName').'</th>
  253. <th>'.get_lang('Qualify').'</th>
  254. </tr>'
  255. );
  256. }
  257. foreach ($tblusers as $user) {
  258. $element_name = 'score['.$user[0].']';
  259. //user_id, user.username, lastname, firstname
  260. $this->add_textfield($element_name,
  261. $this->build_stud_label($user[0], $user[1], $user[2], $user[3]),
  262. false,
  263. array ('class' => 'span1','maxlength' => 5));
  264. $this->addRule($element_name, get_lang('OnlyNumbers'), 'numeric');
  265. $this->addRule(array($element_name,'maxvalue'), get_lang('OverMax'), 'compare', '<=');
  266. $this->addRule(array($element_name,'minvalue'), get_lang('UnderMin'), 'compare', '>=');
  267. if (api_is_western_name_order() ) {
  268. $user_info = '<td align="left" >'.$user[3].'</td>';
  269. $user_info .= '<td align="left" >'.$user[2].'</td>';
  270. } else {
  271. $user_info = '<td align="left" >'.$user[2].'</td>';
  272. $user_info .= '<td align="left" >'.$user[3].'</td>';
  273. }
  274. $nr_users++;
  275. $template = '<tr>
  276. <td align="left" >'.$user[4].'</td>
  277. <td align="left" >'.$user[1].'</td>
  278. '.$user_info.'
  279. <td align="left">{element} / '.$this->evaluation_object->get_max().'
  280. <!-- BEGIN error --><br /><span style="color: #ff0000;font-size:10px">{error}</span><!-- END error -->
  281. </td>
  282. </tr>';
  283. $renderer->setElementTemplate($template, $element_name);
  284. }
  285. $this->addElement('hidden', 'nr_users', $nr_users);
  286. $this->addElement('hidden', 'evaluation_id', $this->result_object->get_evaluation_id());
  287. $this->addElement('style_submit_button', 'submit', get_lang('AddResult'),'class="save"');
  288. $template_submit = '<tr>
  289. <td colspan="4" ></td>
  290. <td >
  291. {element}
  292. <!-- BEGIN error --><br /><span style="color: #ff0000;font-size:10px">{error}</span><!-- END error -->
  293. </td>
  294. </tr>';
  295. $renderer->setElementTemplate($template_submit, 'submit');
  296. }
  297. /**
  298. * Builds a form to edit a result
  299. */
  300. protected function build_result_edit_form() {
  301. $this->setDefaults(array (
  302. 'score' => $this->result_object->get_score(),
  303. 'maximum' => $this->evaluation_object->get_max()
  304. ));
  305. $userinfo= api_get_user_info($this->result_object->get_user_id());
  306. $renderer =& $this->defaultRenderer();
  307. $renderer->setElementTemplate('<span>{element}</span> ');
  308. $this->addElement('label', get_lang('User'), $userinfo['complete_name']);
  309. $this->add_textfield('score', array(get_lang('Score'), null, '/ '.$this->evaluation_object->get_max()), false, array (
  310. 'size' => '4',
  311. 'class' => 'span1',
  312. 'maxlength' => '5'
  313. ));
  314. /* $this->add_textfield('maximum', null, false, array (
  315. 'size' => '4',
  316. 'maxlength' => '5',
  317. 'disabled' => 'disabled'
  318. ));*/
  319. $this->addElement('style_submit_button', 'submit', get_lang('Edit'),'class="save"');
  320. $this->addElement('hidden', 'minvalue', 0);
  321. $this->addElement('hidden', 'hid_user_id', $this->result_object->get_user_id());
  322. $this->addElement('hidden', 'maxvalue', $this->evaluation_object->get_max());
  323. $this->addRule('score', get_lang('OnlyNumbers'), 'numeric',null,'client');
  324. $this->addRule(array (
  325. 'score',
  326. 'maxvalue'
  327. ), get_lang('OverMax'), 'compare', '<=','client');
  328. $this->addRule(array (
  329. 'score',
  330. 'minvalue'
  331. ), get_lang('UnderMin'), 'compare', '>=','client');
  332. }
  333. /**
  334. * Builds a form to add an evaluation
  335. */
  336. protected function build_add_form() {
  337. $this->setDefaults(array ( 'hid_user_id' => $this->evaluation_object->get_user_id(),
  338. 'hid_category_id' => $this->evaluation_object->get_category_id(),
  339. 'hid_course_code' => $this->evaluation_object->get_course_code(), 'created_at' => api_get_utc_datetime()));
  340. $this->build_basic_form(0);
  341. if ($this->evaluation_object->get_course_code() == null) {
  342. $this->addElement('checkbox', 'adduser', null, get_lang('AddUserToEval'));
  343. } else {
  344. $this->addElement('checkbox', 'addresult', null, get_lang('AddResult'));
  345. }
  346. $this->addElement('style_submit_button', 'submit', get_lang('AddAssessment'),'class="add"');
  347. }
  348. /**
  349. * Builds a form to edit an evaluation
  350. */
  351. protected function build_editing_form() {
  352. $parent_cat = Category :: load($this->evaluation_object->get_category_id());
  353. if ($parent_cat[0]->get_parent_id() == 0) {
  354. $weight_mask = $this->evaluation_object->get_weight();
  355. } else {
  356. $cat = Category :: load($parent_cat[0]->get_parent_id());
  357. $global_weight = $cat[0]->get_weight();
  358. $weight_mask = $global_weight*$this->evaluation_object->get_weight()/$parent_cat[0]->get_weight() ;
  359. }
  360. $weight_mask = $this->evaluation_object->get_weight();
  361. $this->setDefaults(array ( 'hid_id' => $this->evaluation_object->get_id(),
  362. 'name' => $this->evaluation_object->get_name(),
  363. 'description' => $this->evaluation_object->get_description(),
  364. 'hid_user_id' => $this->evaluation_object->get_user_id(),
  365. 'hid_course_code' => $this->evaluation_object->get_course_code(),
  366. 'hid_category_id' => $this->evaluation_object->get_category_id(),
  367. 'created_at' => api_get_utc_datetime($this->evaluation_object->get_date()),
  368. 'weight' => $weight,
  369. 'weight_mask' => $weight_mask,
  370. 'max' => $this->evaluation_object->get_max(),
  371. 'visible' => $this->evaluation_object->is_visible()));
  372. $id_current=isset($this->id)?$this->id :null;
  373. $this->addElement('hidden', 'hid_id', $id_current);
  374. $this->build_basic_form(1);
  375. $this->addElement('style_submit_button', 'submit', get_lang('ModifyEvaluation'),'class="save"');
  376. }
  377. /**
  378. * Builds a basic form that is used in add and edit
  379. */
  380. private function build_basic_form($edit= 0) {
  381. $form_title = get_lang('NewEvaluation');
  382. if ($_GET['editeval']==1) {
  383. $form_title = get_lang('EditEvaluation');
  384. }
  385. $this->addElement('header', $form_title);
  386. $this->addElement('hidden', 'zero', 0);
  387. $this->addElement('hidden', 'hid_user_id');
  388. $this->addElement('hidden', 'hid_course_code');
  389. $this->add_textfield('name', get_lang('EvaluationName'), true, array (
  390. 'class' => 'span3',
  391. 'maxlength' => '50',
  392. 'id' => 'evaluation_title'
  393. ));
  394. $cat_id = $this->evaluation_object->get_category_id();
  395. $session_id = api_get_session_id();
  396. $course_code = api_get_course_id();
  397. $all_categories = Category :: load(null, null, $course_code, null, null, $session_id, false);
  398. if (count($all_categories) == 1) {
  399. $this->addElement('hidden', 'hid_category_id', $cat_id);
  400. } else {
  401. $select_gradebook = $this->addElement('select', 'hid_category_id', get_lang('SelectGradebook'), array(), array('id' => 'hid_category_id'));
  402. $this->addRule('hid_category_id', get_lang('ThisFieldIsRequired'), 'nonzero');
  403. $default_weight = 0;
  404. if (!empty($all_categories)) {
  405. foreach ($all_categories as $my_cat) {
  406. if ($my_cat->get_course_code() == api_get_course_id()) {
  407. $grade_model_id = $my_cat->get_grade_model_id();
  408. if (empty($grade_model_id)) {
  409. if ($my_cat->get_parent_id() == 0) {
  410. $default_weight = $my_cat->get_weight();
  411. $select_gradebook->addoption(get_lang('Default'), $my_cat->get_id());
  412. $cats_added[] = $my_cat->get_id();
  413. } else {
  414. $select_gradebook->addoption($my_cat->get_name(), $my_cat->get_id());
  415. $cats_added[] = $my_cat->get_id();
  416. }
  417. } else {
  418. $select_gradebook->addoption(get_lang('Select'), 0);
  419. }
  420. if ($this->evaluation_object->get_category_id() == $my_cat->get_id()) {
  421. $default_weight = $my_cat->get_weight();
  422. }
  423. }
  424. }
  425. }
  426. }
  427. $this->add_textfield('weight_mask', array(get_lang('Weight'), null, ' [0 .. '.$all_categories[0]->get_weight().'] '), true, array (
  428. 'size' => '4',
  429. 'maxlength' => '5',
  430. 'class' => 'span1'
  431. ));
  432. /*$this->add_textfield('weight', array(null, null, '/ <span id="max_weight">'.$default_weight.'</span>'), true, array (
  433. 'size' => '4',
  434. 'maxlength' => '5',
  435. 'class' => 'span1'
  436. ));*/
  437. if ($edit) {
  438. if (!$this->evaluation_object->has_results()) {
  439. $this->add_textfield('max', get_lang('QualificationNumeric'), true, array (
  440. 'class' => 'span1',
  441. 'maxlength' => '5'
  442. ));
  443. } else {
  444. $this->add_textfield('max', array(get_lang('QualificationNumeric'), get_lang('CannotChangeTheMaxNote')), false, array (
  445. 'class' => 'span1',
  446. 'maxlength' => '5',
  447. 'disabled' => 'disabled'
  448. ));
  449. }
  450. } else {
  451. $this->add_textfield('max', get_lang('QualificationNumeric'), true, array (
  452. 'class' => 'span1',
  453. 'maxlength' => '5'
  454. ));
  455. $default_max = api_get_setting('gradebook_default_weight');
  456. $defaults['max'] = isset($default_max) ? $default_max : 100;
  457. $this->setDefaults($defaults);
  458. }
  459. $this->addElement('textarea', 'description', get_lang('Description'), array (
  460. 'rows' => '3',
  461. 'class' => 'span3',
  462. ));
  463. $this->addRule('hid_category_id', get_lang('ThisFieldIsRequired'), 'required');
  464. $this->addElement('checkbox', 'visible', null, get_lang('Visible'));
  465. $this->addRule('weight_mask', get_lang('OnlyNumbers'), 'numeric');
  466. $this->addRule(array('weight_mask', 'zero'), get_lang('NegativeValue'), 'compare', '>=');
  467. $this->addRule('max', get_lang('OnlyNumbers'), 'numeric');
  468. $this->addRule(array('max', 'zero'), get_lang('NegativeValue'), 'compare', '>=');
  469. $setting = api_get_setting('tool_visible_by_default_at_creation');
  470. $visibility_default = 1;
  471. if (isset($setting['gradebook']) && $setting['gradebook'] == 'false') {
  472. $visibility_default = 0;
  473. }
  474. $this->setDefaults(array('visible' => $visibility_default));
  475. }
  476. function display() {
  477. parent :: display();
  478. }
  479. function setDefaults($defaults= array(), $filter = null) {
  480. parent :: setDefaults($defaults, $filter);
  481. }
  482. private function build_stud_label ($id, $username,$lastname, $firstname) {
  483. $opendocurl_start = '';
  484. $opendocurl_end = '';
  485. // evaluation's origin is a link
  486. if ($this->evaluation_object->get_category_id() < 0) {
  487. $link = LinkFactory :: get_evaluation_link ($this->evaluation_object->get_id());
  488. $doc_url = $link->get_view_url($id);
  489. if ($doc_url != null) {
  490. $opendocurl_start .= '<a href="'. $doc_url . '" target="_blank">';
  491. $opendocurl_end = '</a>';
  492. }
  493. }
  494. return $opendocurl_start . api_get_person_name($firstname, $lastname) .' ('.$username.')'. $opendocurl_end;
  495. }
  496. function sort_by_user ($item1, $item2) {
  497. $user1 = $item1['user'];
  498. $user2 = $item2['user'];
  499. if (api_sort_by_first_name()) {
  500. $result = api_strcmp($user1['firstname'], $user2['firstname']);
  501. if ($result == 0) {
  502. return api_strcmp($user1['lastname'], $user2['lastname']);
  503. }
  504. } else {
  505. $result = api_strcmp($user1['lastname'], $user2['lastname']);
  506. if ($result == 0) {
  507. return api_strcmp($user1['firstname'], $user2['firstname']);
  508. }
  509. }
  510. return $result;
  511. }
  512. }