Commit | Line | Data |
---|---|---|
a4813c36 | 1 | <?php |
bfebaf64 MD |
2 | if (!defined('MOODLE_INTERNAL')) { |
3 | die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page | |
4 | } | |
5 | ||
23a7718b | 6 | require_once ($CFG->dirroot.'/course/moodleform_mod.php'); |
a4813c36 | 7 | require_once($CFG->dirroot.'/mod/scorm/locallib.php'); |
8 | ||
9 | class mod_scorm_mod_form extends moodleform_mod { | |
10 | ||
11 | function definition() { | |
6aff538a | 12 | global $CFG, $COURSE, $OUTPUT; |
30fc6e2d | 13 | $cfg_scorm = get_config('scorm'); |
a4813c36 | 14 | |
9528568b | 15 | $mform = $this->_form; |
16 | ||
9528568b | 17 | if (!$CFG->slasharguments) { |
6aff538a | 18 | $mform->addElement('static', '', '',$OUTPUT->notification(get_string('slashargs', 'scorm'), 'notifyproblem')); |
01e6c030 | 19 | } |
edf13ee8 | 20 | $zlib = ini_get('zlib.output_compression'); //check for zlib compression - if used, throw error because of IE bug. - SEE MDL-16185 |
21 | if (isset($zlib) && $zlib) { | |
6aff538a | 22 | $mform->addElement('static', '', '',$OUTPUT->notification(get_string('zlibwarning', 'scorm'), 'notifyproblem')); |
edf13ee8 | 23 | } |
a4813c36 | 24 | //------------------------------------------------------------------------------- |
25 | $mform->addElement('header', 'general', get_string('general', 'form')); | |
26 | ||
27 | // Name | |
28 | $mform->addElement('text', 'name', get_string('name')); | |
8eb1d25f | 29 | if (!empty($CFG->formatstringstriptags)) { |
30 | $mform->setType('name', PARAM_TEXT); | |
31 | } else { | |
b8ea3041 | 32 | $mform->setType('name', PARAM_CLEANHTML); |
8eb1d25f | 33 | } |
a4813c36 | 34 | $mform->addRule('name', null, 'required', null, 'client'); |
35 | ||
36 | // Summary | |
ac3668bf | 37 | $this->add_intro_editor(true); |
a4813c36 | 38 | |
9528568b | 39 | // Scorm types |
40 | $options = array(SCORM_TYPE_LOCAL => get_string('typelocal', 'scorm')); | |
41 | ||
30fc6e2d | 42 | if ($cfg_scorm->allowtypeexternal) { |
9528568b | 43 | $options[SCORM_TYPE_EXTERNAL] = get_string('typeexternal', 'scorm'); |
44 | } | |
45 | ||
30fc6e2d | 46 | if ($cfg_scorm->allowtypelocalsync) { |
9528568b | 47 | $options[SCORM_TYPE_LOCALSYNC] = get_string('typelocalsync', 'scorm'); |
48 | } | |
49 | ||
30fc6e2d | 50 | if (!empty($CFG->repositoryactivate) and $cfg_scorm->allowtypeimsrepository) { |
9528568b | 51 | $options[SCORM_TYPE_IMSREPOSITORY] = get_string('typeimsrepository', 'scorm'); |
52 | } | |
53 | ||
a4813c36 | 54 | // Reference |
9528568b | 55 | if (count($options) > 1) { |
e73d5557 | 56 | $mform->addElement('select', 'scormtype', get_string('scormtype', 'scorm'), $options); |
427bcd4d DM |
57 | $mform->addHelpButton('scormtype', 'scormtype', 'scorm'); |
58 | $mform->addElement('text', 'packageurl', get_string('packageurl', 'scorm'), array('size'=>60)); | |
9528568b | 59 | $mform->setType('packageurl', PARAM_RAW); |
427bcd4d | 60 | $mform->addHelpButton('packageurl', 'packageurl', 'scorm'); |
9528568b | 61 | $mform->disabledIf('packageurl', 'scormtype', 'eq', SCORM_TYPE_LOCAL); |
e73d5557 DM |
62 | } else { |
63 | $mform->addElement('hidden', 'scormtype', SCORM_TYPE_LOCAL); | |
9528568b | 64 | } |
65 | ||
66 | // New local package upload | |
560417ff | 67 | $maxbytes = get_max_upload_file_size($CFG->maxbytes, $COURSE->maxbytes); |
68 | $mform->setMaxFileSize($maxbytes); | |
d3d98a3a | 69 | $mform->addElement('filepicker', 'packagefile', get_string('package','scorm')); |
427bcd4d | 70 | $mform->addHelpButton('packagefile', 'package', 'scorm'); |
9528568b | 71 | $mform->disabledIf('packagefile', 'scormtype', 'noteq', SCORM_TYPE_LOCAL); |
a4813c36 | 72 | |
d54e2145 | 73 | //------------------------------------------------------------------------------- |
74 | // Time restrictions | |
75 | $mform->addElement('header', 'timerestricthdr', get_string('timerestrict', 'scorm')); | |
d54e2145 | 76 | |
413900b4 DM |
77 | $mform->addElement('date_time_selector', 'timeopen', get_string("scormopen", "scorm"),array('optional' => true)); |
78 | $mform->addElement('date_time_selector', 'timeclose', get_string("scormclose", "scorm"),array('optional' => true)); | |
a4813c36 | 79 | //------------------------------------------------------------------------------- |
80 | // Other Settings | |
3b631eda | 81 | $mform->addElement('header', 'advanced', get_string('othersettings', 'form')); |
a4813c36 | 82 | |
a4813c36 | 83 | // Grade Method |
30fc6e2d | 84 | $mform->addElement('select', 'grademethod', get_string('grademethod', 'scorm'), scorm_get_grade_method_array()); |
c329e370 | 85 | $mform->addHelpButton('grademethod', 'grademethod', 'scorm'); |
30fc6e2d | 86 | $mform->setDefault('grademethod', $cfg_scorm->grademethod); |
3268cf99 | 87 | |
a4813c36 | 88 | // Maximum Grade |
89 | for ($i=0; $i<=100; $i++) { | |
90 | $grades[$i] = "$i"; | |
91 | } | |
92 | $mform->addElement('select', 'maxgrade', get_string('maximumgrade'), $grades); | |
30fc6e2d | 93 | $mform->setDefault('maxgrade', $cfg_scorm->maxgrade); |
9528568b | 94 | $mform->disabledIf('maxgrade', 'grademethod','eq', GRADESCOES); |
a4813c36 | 95 | |
96 | // Attempts | |
97 | $mform->addElement('static', '', '' ,'<hr />'); | |
a4813c36 | 98 | |
99 | // Max Attempts | |
30fc6e2d | 100 | $mform->addElement('select', 'maxattempt', get_string('maximumattempts', 'scorm'), scorm_get_attempts_array()); |
c329e370 | 101 | $mform->addHelpButton('maxattempt', 'maximumattempts', 'scorm'); |
30fc6e2d | 102 | $mform->setDefault('maxattempt', $cfg_scorm->maxattempts); |
3268cf99 | 103 | |
87db13b5 PH |
104 | // What Grade |
105 | $mform->addElement('select', 'whatgrade', get_string('whatgrade', 'scorm'), scorm_get_what_grade_array()); | |
106 | $mform->disabledIf('whatgrade', 'maxattempt','eq',1); | |
c329e370 | 107 | $mform->addHelpButton('whatgrade', 'whatgrade', 'scorm'); |
87db13b5 PH |
108 | $mform->setDefault('whatgrade', $cfg_scorm->whatgrade); |
109 | $mform->setAdvanced('whatgrade'); | |
110 | ||
6381fa56 | 111 | // Display attempt status |
112 | $mform->addElement('selectyesno', 'displayattemptstatus', get_string('displayattemptstatus', 'scorm')); | |
c329e370 | 113 | $mform->addHelpButton('displayattemptstatus', 'displayattemptstatus', 'scorm'); |
30fc6e2d | 114 | $mform->setDefault('displayattemptstatus', $cfg_scorm->displayattemptstatus); |
3268cf99 | 115 | |
6381fa56 | 116 | // Force completed |
117 | $mform->addElement('selectyesno', 'forcecompleted', get_string('forcecompleted', 'scorm')); | |
c329e370 | 118 | $mform->addHelpButton('forcecompleted', 'forcecompleted', 'scorm'); |
30fc6e2d | 119 | $mform->setDefault('forcecompleted', $cfg_scorm->forcecompleted); |
6381fa56 | 120 | $mform->setAdvanced('forcecompleted'); |
121 | ||
122 | // Force new attempt | |
123 | $mform->addElement('selectyesno', 'forcenewattempt', get_string('forcenewattempt', 'scorm')); | |
c329e370 | 124 | $mform->addHelpButton('forcenewattempt', 'forcenewattempt', 'scorm'); |
30fc6e2d | 125 | $mform->setDefault('forcenewattempt', $cfg_scorm->forcenewattempt); |
6381fa56 | 126 | $mform->setAdvanced('forcenewattempt'); |
3268cf99 | 127 | |
6381fa56 | 128 | // Last attempt lock - lock the enter button after the last available attempt has been made |
129 | $mform->addElement('selectyesno', 'lastattemptlock', get_string('lastattemptlock', 'scorm')); | |
c329e370 | 130 | $mform->addHelpButton('lastattemptlock', 'lastattemptlock', 'scorm'); |
30fc6e2d | 131 | $mform->setDefault('lastattemptlock', $cfg_scorm->lastattemptlock); |
6381fa56 | 132 | $mform->setAdvanced('lastattemptlock'); |
3268cf99 | 133 | |
a4813c36 | 134 | // Activation period |
2b90f941 | 135 | /* $mform->addElement('static', '', '' ,'<hr />'); |
a4813c36 | 136 | $mform->addElement('static', 'activation', get_string('activation','scorm')); |
137 | $datestartgrp = array(); | |
138 | $datestartgrp[] = &$mform->createElement('date_time_selector', 'startdate'); | |
139 | $datestartgrp[] = &$mform->createElement('checkbox', 'startdisabled', null, get_string('disable')); | |
140 | $mform->addGroup($datestartgrp, 'startdategrp', get_string('from'), ' ', false); | |
141 | $mform->setDefault('startdate', 0); | |
142 | $mform->setDefault('startdisabled', 1); | |
143 | $mform->disabledIf('startdategrp', 'startdisabled', 'checked'); | |
144 | ||
145 | $dateendgrp = array(); | |
146 | $dateendgrp[] = &$mform->createElement('date_time_selector', 'enddate'); | |
147 | $dateendgrp[] = &$mform->createElement('checkbox', 'enddisabled', null, get_string('disable')); | |
148 | $mform->addGroup($dateendgrp, 'dateendgrp', get_string('to'), ' ', false); | |
149 | $mform->setDefault('enddate', 0); | |
150 | $mform->setDefault('enddisabled', 1); | |
151 | $mform->disabledIf('dateendgrp', 'enddisabled', 'checked'); | |
2b90f941 | 152 | */ |
3268cf99 | 153 | |
a73e2664 DM |
154 | // Framed / Popup Window |
155 | $mform->addElement('select', 'popup', get_string('display', 'scorm'), scorm_get_popup_display_array()); | |
156 | $mform->setDefault('popup', $cfg_scorm->popup); | |
157 | $mform->setAdvanced('popup'); | |
158 | ||
a4813c36 | 159 | // Width |
9528568b | 160 | $mform->addElement('text', 'width', get_string('width','scorm'), 'maxlength="5" size="5"'); |
30fc6e2d | 161 | $mform->setDefault('width', $cfg_scorm->framewidth); |
a4813c36 | 162 | $mform->setType('width', PARAM_INT); |
a73e2664 DM |
163 | $mform->setAdvanced('width'); |
164 | $mform->disabledIf('width', 'popup', 'eq', 0); | |
9528568b | 165 | |
a4813c36 | 166 | // Height |
9528568b | 167 | $mform->addElement('text', 'height', get_string('height','scorm'), 'maxlength="5" size="5"'); |
30fc6e2d | 168 | $mform->setDefault('height', $cfg_scorm->frameheight); |
a4813c36 | 169 | $mform->setType('height', PARAM_INT); |
a73e2664 DM |
170 | $mform->setAdvanced('height'); |
171 | $mform->disabledIf('height', 'popup', 'eq', 0); | |
a4813c36 | 172 | |
173 | // Window Options | |
174 | $winoptgrp = array(); | |
30fc6e2d | 175 | foreach(scorm_get_popup_options_array() as $key => $value){ |
176 | $winoptgrp[] = &$mform->createElement('checkbox', $key, '', get_string($key, 'scorm')); | |
177 | $mform->setDefault($key, $value); | |
178 | } | |
4b07d3a8 | 179 | $mform->addGroup($winoptgrp, 'winoptgrp', get_string('options','scorm'), '<br />', false); |
a4813c36 | 180 | $mform->setAdvanced('winoptgrp'); |
181 | $mform->disabledIf('winoptgrp', 'popup', 'eq', 0); | |
182 | ||
183 | // Skip view page | |
30fc6e2d | 184 | $mform->addElement('select', 'skipview', get_string('skipview', 'scorm'),scorm_get_skip_view_array()); |
c329e370 | 185 | $mform->addHelpButton('skipview', 'skipview', 'scorm'); |
30fc6e2d | 186 | $mform->setDefault('skipview', $cfg_scorm->skipview); |
a4813c36 | 187 | $mform->setAdvanced('skipview'); |
188 | ||
189 | // Hide Browse | |
190 | $mform->addElement('selectyesno', 'hidebrowse', get_string('hidebrowse', 'scorm')); | |
c329e370 | 191 | $mform->addHelpButton('hidebrowse', 'hidebrowse', 'scorm'); |
30fc6e2d | 192 | $mform->setDefault('hidebrowse', $cfg_scorm->hidebrowse); |
a4813c36 | 193 | $mform->setAdvanced('hidebrowse'); |
194 | ||
87db13b5 PH |
195 | // Display course structure |
196 | $mform->addElement('selectyesno', 'displaycoursestructure', get_string('displaycoursestructure', 'scorm')); | |
c329e370 | 197 | $mform->addHelpButton('displaycoursestructure', 'displaycoursestructure', 'scorm'); |
87db13b5 PH |
198 | $mform->setDefault('displaycoursestructure', $cfg_scorm->displaycoursestructure); |
199 | $mform->setAdvanced('displaycoursestructure'); | |
c329e370 | 200 | |
a4813c36 | 201 | // Toc display |
30fc6e2d | 202 | $mform->addElement('select', 'hidetoc', get_string('hidetoc', 'scorm'), scorm_get_hidetoc_array()); |
c329e370 | 203 | $mform->addHelpButton('hidetoc', 'hidetoc', 'scorm'); |
30fc6e2d | 204 | $mform->setDefault('hidetoc', $cfg_scorm->hidetoc); |
a4813c36 | 205 | $mform->setAdvanced('hidetoc'); |
206 | ||
207 | // Hide Navigation panel | |
208 | $mform->addElement('selectyesno', 'hidenav', get_string('hidenav', 'scorm')); | |
30fc6e2d | 209 | $mform->setDefault('hidenav', $cfg_scorm->hidenav); |
a4813c36 | 210 | $mform->setAdvanced('hidenav'); |
211 | ||
212 | // Autocontinue | |
213 | $mform->addElement('selectyesno', 'auto', get_string('autocontinue', 'scorm')); | |
c329e370 | 214 | $mform->addHelpButton('auto', 'autocontinue', 'scorm'); |
30fc6e2d | 215 | $mform->setDefault('auto', $cfg_scorm->auto); |
a4813c36 | 216 | $mform->setAdvanced('auto'); |
217 | ||
a679d64d | 218 | // Update packages timing |
30fc6e2d | 219 | $mform->addElement('select', 'updatefreq', get_string('updatefreq', 'scorm'), scorm_get_updatefreq_array()); |
220 | $mform->setDefault('updatefreq', $cfg_scorm->updatefreq); | |
a679d64d | 221 | $mform->setAdvanced('updatefreq'); |
a4813c36 | 222 | |
223 | //------------------------------------------------------------------------------- | |
224 | // Hidden Settings | |
225 | $mform->addElement('hidden', 'datadir', null); | |
d18e0fe6 | 226 | $mform->setType('datadir', PARAM_RAW); |
a4813c36 | 227 | $mform->addElement('hidden', 'pkgtype', null); |
d18e0fe6 | 228 | $mform->setType('pkgtype', PARAM_RAW); |
a4813c36 | 229 | $mform->addElement('hidden', 'launch', null); |
d18e0fe6 | 230 | $mform->setType('launch', PARAM_RAW); |
a4813c36 | 231 | $mform->addElement('hidden', 'redirect', null); |
d18e0fe6 | 232 | $mform->setType('redirect', PARAM_RAW); |
a4813c36 | 233 | $mform->addElement('hidden', 'redirecturl', null); |
d18e0fe6 | 234 | $mform->setType('redirecturl', PARAM_RAW); |
a4813c36 | 235 | |
236 | ||
237 | //------------------------------------------------------------------------------- | |
42f103be | 238 | $this->standard_coursemodule_elements(); |
a4813c36 | 239 | //------------------------------------------------------------------------------- |
240 | // buttons | |
241 | $this->add_action_buttons(); | |
242 | ||
243 | } | |
244 | ||
728d0599 | 245 | function data_preprocessing(&$default_values) { |
a4813c36 | 246 | global $COURSE; |
247 | ||
248 | if (isset($default_values['popup']) && ($default_values['popup'] == 1) && isset($default_values['options'])) { | |
1adc77e6 | 249 | if (!empty($default_values['options'])) { |
250 | $options = explode(',',$default_values['options']); | |
251 | foreach ($options as $option) { | |
252 | list($element,$value) = explode('=',$option); | |
253 | $element = trim($element); | |
254 | $default_values[$element] = trim($value); | |
255 | } | |
a4813c36 | 256 | } |
257 | } | |
258 | if (isset($default_values['grademethod'])) { | |
adefe70e | 259 | $default_values['grademethod'] = intval($default_values['grademethod']); |
a4813c36 | 260 | } |
efe95a6f PS |
261 | if (isset($default_values['width']) && (strpos($default_values['width'],'%') === false) && ($default_values['width'] <= 100)) { |
262 | $default_values['width'] .= '%'; | |
a4813c36 | 263 | } |
efe95a6f PS |
264 | if (isset($default_values['width']) && (strpos($default_values['height'],'%') === false) && ($default_values['height'] <= 100)) { |
265 | $default_values['height'] .= '%'; | |
a4813c36 | 266 | } |
267 | $scorms = get_all_instances_in_course('scorm', $COURSE); | |
268 | $coursescorm = current($scorms); | |
b76f2e60 DC |
269 | |
270 | $draftitemid = file_get_submitted_draft_itemid('packagefile'); | |
783f1486 | 271 | file_prepare_draft_area($draftitemid, $this->context->id, 'mod_scorm', 'package', 0); |
b76f2e60 DC |
272 | $default_values['packagefile'] = $draftitemid; |
273 | ||
a4813c36 | 274 | if (($COURSE->format == 'scorm') && ((count($scorms) == 0) || ($default_values['instance'] == $coursescorm->id))) { |
275 | $default_values['redirect'] = 'yes'; | |
9528568b | 276 | $default_values['redirecturl'] = '../course/view.php?id='.$default_values['course']; |
a4813c36 | 277 | } else { |
278 | $default_values['redirect'] = 'no'; | |
279 | $default_values['redirecturl'] = '../mod/scorm/view.php?id='.$default_values['coursemodule']; | |
280 | } | |
281 | if (isset($default_values['version'])) { | |
282 | $default_values['pkgtype'] = (substr($default_values['version'],0,5) == 'SCORM') ? 'scorm':'aicc'; | |
283 | } | |
284 | if (isset($default_values['instance'])) { | |
285 | $default_values['datadir'] = $default_values['instance']; | |
286 | } | |
d54e2145 | 287 | if (empty($default_values['timeopen'])) { |
413900b4 DM |
288 | $default_values['timeopen'] = 0; |
289 | } | |
290 | if (empty($default_values['timeclose'])) { | |
291 | $default_values['timeclose'] = 0; | |
d54e2145 | 292 | } |
a4813c36 | 293 | } |
294 | ||
a78890d5 | 295 | function validation($data, $files) { |
d3d98a3a | 296 | global $CFG; |
a78890d5 | 297 | $errors = parent::validation($data, $files); |
60243313 | 298 | |
9528568b | 299 | $type = $data['scormtype']; |
300 | ||
301 | if ($type === SCORM_TYPE_LOCAL) { | |
302 | if (!empty($data['update'])) { | |
303 | //ok, not required | |
a679d64d | 304 | |
d3d98a3a | 305 | } else if (empty($data['packagefile'])) { |
9528568b | 306 | $errors['packagefile'] = get_string('required'); |
307 | ||
308 | } else { | |
d3d98a3a DC |
309 | $files = $this->get_draft_files('packagefile'); |
310 | if (count($files)<1) { | |
311 | $errors['packagefile'] = get_string('required'); | |
9eb8dccc | 312 | return $errors; |
d3d98a3a DC |
313 | } |
314 | $file = reset($files); | |
315 | $filename = $CFG->dataroot.'/temp/scormimport/scrom_'.time(); | |
316 | make_upload_directory('temp/scormimport'); | |
317 | $file->copy_content_to($filename); | |
318 | ||
9528568b | 319 | $packer = get_file_packer('application/zip'); |
320 | ||
d3d98a3a | 321 | $filelist = $packer->list_files($filename); |
9528568b | 322 | if (!is_array($filelist)) { |
323 | $errors['packagefile'] = 'Incorrect file package - not an archive'; //TODO: localise | |
324 | } else { | |
325 | $manifestpresent = false; | |
326 | $aiccfound = false; | |
327 | foreach ($filelist as $info) { | |
328 | if ($info->pathname == 'imsmanifest.xml') { | |
329 | $manifestpresent = true; | |
330 | break; | |
331 | } | |
332 | if (preg_match('/\.cst$/', $info->pathname)) { | |
333 | $aiccfound = true; | |
334 | break; | |
335 | } | |
336 | } | |
337 | if (!$manifestpresent and !$aiccfound) { | |
338 | $errors['packagefile'] = 'Incorrect file package - missing imsmanifest.xml or AICC structure'; //TODO: localise | |
339 | } | |
340 | } | |
d3d98a3a | 341 | unlink($filename); |
9528568b | 342 | } |
343 | ||
344 | } else if ($type === SCORM_TYPE_EXTERNAL) { | |
345 | $reference = $data['packageurl']; | |
346 | if (!preg_match('/(http:\/\/|https:\/\/|www).*\/imsmanifest.xml$/i', $reference)) { | |
347 | $errors['packageurl'] = get_string('required'); // TODO: improve help | |
348 | } | |
349 | ||
350 | } else if ($type === 'packageurl') { | |
351 | $reference = $data['reference']; | |
352 | if (!preg_match('/(http:\/\/|https:\/\/|www).*(\.zip|\.pif)$/i', $reference)) { | |
353 | $errors['packageurl'] = get_string('required'); // TODO: improve help | |
354 | } | |
355 | ||
356 | } else if ($type === SCORM_TYPE_IMSREPOSITORY) { | |
357 | $reference = $data['packageurl']; | |
358 | if (stripos($reference, '#') !== 0) { | |
359 | $errors['packageurl'] = get_string('required'); | |
360 | } | |
60243313 | 361 | } |
362 | ||
a78890d5 | 363 | return $errors; |
a679d64d | 364 | } |
9528568b | 365 | |
366 | //need to translate the "options" and "reference" field. | |
ea38a6b9 | 367 | function set_data($default_values) { |
9528568b | 368 | $default_values = (array)$default_values; |
369 | ||
370 | if (isset($default_values['scormtype']) and isset($default_values['reference'])) { | |
371 | switch ($default_values['scormtype']) { | |
372 | case SCORM_TYPE_LOCALSYNC : | |
373 | case SCORM_TYPE_EXTERNAL: | |
374 | case SCORM_TYPE_IMSREPOSITORY: | |
375 | $default_values['packageurl'] = $default_values['reference']; | |
376 | } | |
377 | } | |
378 | unset($default_values['reference']); | |
379 | ||
380 | if (!empty($default_values['options'])) { | |
381 | $options = explode(',', $default_values['options']); | |
382 | foreach ($options as $option) { | |
383 | $opt = explode('=', $option); | |
384 | if (isset($opt[1])) { | |
9b426d03 | 385 | $default_values[$opt[0]] = $opt[1]; |
ea38a6b9 | 386 | } |
387 | } | |
ea38a6b9 | 388 | } |
9528568b | 389 | |
ea38a6b9 | 390 | $this->data_preprocessing($default_values); |
9528568b | 391 | parent::set_data($default_values); |
ea38a6b9 | 392 | } |
a4813c36 | 393 | } |
e5dd8e3b | 394 |