MDL-7097 - API debug. Change the control of debugging over to SCORM admin settings.
[moodle.git] / mod / scorm / datamodels / scorm_13.js.php
1 <?php
2     require_once($CFG->dirroot.'/mod/scorm/locallib.php');
3     
4     if (isset($userdata->status)) {
5         if (!isset($userdata->{'cmi.exit'}) || (($userdata->{'cmi.exit'} == 'time-out') || ($userdata->{'cmi.exit'} == 'normal'))) { 
6                 $userdata->entry = 'ab-initio';
7         } else {
8             if (isset($userdata->{'cmi.exit'}) && (($userdata->{'cmi.exit'} == 'suspend') || ($userdata->{'cmi.exit'} == 'logout'))) {
9                 $userdata->entry = 'resume';
10             } else {
11                 $userdata->entry = '';
12             }
13         }
14     }
15 ?>
17 // Used need to debug cmi content (if you uncomment this, you must comment the definition inside SCORMapi1_3)
18 //var cmi = new Object(); 
20 //
21 // SCORM 1.3 API Implementation
22 //
23 function SCORMapi1_3() {
24     // Standard Data Type Definition
25     var CMIString200 = '^.{0,200}$';
26     var CMIString250 = '^.{0,250}$';
27     var CMIString1000 = '^.{0,1500}$';
28     var CMIString4000 = '^.{0,4000}$';
29     var CMIString64000 = '^.{0,64000}$';
30     var CMILang = '^([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?$|^$';
31     var CMILangString250 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,250}$)?';
32     var CMILangString4000 = '^(\{lang=([a-zA-Z]{2,3}|i|x)(\-[a-zA-Z0-9\-]{2,8})?\})?([^\{].{0,4000}$)?';
33     var CMITime = '^(19[7-9]{1}[0-9]{1}|20[0-2]{1}[0-9]{1}|203[0-8]{1})((-(0[1-9]{1}|1[0-2]{1}))((-(0[1-9]{1}|[1-2]{1}[0-9]{1}|3[0-1]{1}))(T([0-1]{1}[0-9]{1}|2[0-3]{1})((:[0-5]{1}[0-9]{1})((:[0-5]{1}[0-9]{1})((\\.[0-9]{1,2})((Z|([+|-]([0-1]{1}[0-9]{1}|2[0-3]{1})))(:[0-5]{1}[0-9]{1})?)?)?)?)?)?)?)?$';
34     var CMITimespan = '^P(\\d+Y)?(\\d+M)?(\\d+D)?(T(((\\d+H)(\\d+M)?(\\d+(\.\\d{1,2})?S)?)|((\\d+M)(\\d+(\.\\d{1,2})?S)?)|((\\d+(\.\\d{1,2})?S))))?$';
35     var CMIInteger = '^\\d+$';
36     var CMISInteger = '^-?([0-9]+)$';
37     var CMIDecimal = '^-?([0-9]{1,4})(\\.[0-9]{1,18})?$';
38     var CMIIdentifier = '^\\S{0,250}[a-zA-Z0-9]$';
39     var CMIShortIdentifier = '^[\\w\.]{1,250}$';
40     var CMILongIdentifier = '^\\S{0,4000}[a-zA-Z0-9]$';
41     var CMIFeedback = '^.*$'; // This must be redefined
42     var CMIIndex = '[._](\\d+).';
43     var CMIIndexStore = '.N(\\d+).';
44     // Vocabulary Data Type Definition
45     var CMICStatus = '^completed$|^incomplete$|^not attempted$|^unknown$';
46     var CMISStatus = '^passed$|^failed$|^unknown$';
47     var CMIExit = '^time-out$|^suspend$|^logout$|^normal$|^$';
48     var CMIType = '^true-false$|^choice$|^(long-)?fill-in$|^matching$|^performance$|^sequencing$|^likert$|^numeric$|^other$';
49     var CMIResult = '^correct$|^incorrect$|^unanticipated$|^neutral$|^-?([0-9]{1,4})(\\.[0-9]{1,18})?$';
50     var NAVEvent = '^previous$|^continue$|^exit$|^exitAll$|^abandon$|^abandonAll$|^suspendAll$|^{target=\\S{0,200}[a-zA-Z0-9]}choice$';
51     var NAVBoolean = '^unknown$|^true$|^false$';
52     var NAVTarget = '^previous$|^continue$|^choice.{target=\\S{0,200}[a-zA-Z0-9]}$'
53     // Children lists
54     var cmi_children = '_version, comments_from_learner, comments_from_lms, completion_status, credit, entry, exit, interactions, launch_data, learner_id, learner_name, learner_preference, location, max_time_allowed, mode, objectives, progress_measure, scaled_passing_score, score, session_time, success_status, suspend_data, time_limit_action, total_time';
55     var comments_children = 'comment, timestamp, location';
56     var score_children = 'max, raw, scaled, min';
57     var objectives_children = 'progress_measure, completion_status, success_status, description, score, id';
58     var student_data_children = 'mastery_score, max_time_allowed, time_limit_action';
59     var student_preference_children = 'audio_level, audio_captioning, delivery_speed, language';
60     var interactions_children = 'id, type, objectives, timestamp, correct_responses, weighting, learner_response, result, latency, description';
61     // Data ranges
62     var scaled_range = '-1#1';
63     var audio_range = '0#*';
64     var speed_range = '0#*';
65     var text_range = '-1#1';
66     var progress_range = '0#1';
67     var learner_response = {
68         'true-false':{'format':'^true$|^false$', 'max':1, 'delimiter':'', 'unique':false},
69         'choice':{'format':CMIIdentifier, 'max':36, 'delimiter':'[,]', 'unique':true},
70         'fill-in':{'format':CMILangString250, 'max':10, 'delimiter':'[,]', 'unique':false},
71         'long-fill-in':{'format':CMILangString4000, 'max':1, 'delimiter':'', 'unique':false},
72         'matching':{'format':CMIShortIdentifier, 'format2':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false},
73         'performance':{'format':'^$|'+CMIShortIdentifier, 'format2':CMIDecimal+'|^$|'+CMIShortIdentifier, 'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false},
74         'sequencing':{'format':CMIShortIdentifier, 'max':36, 'delimiter':'[,]', 'unique':false},
75         'likert':{'format':CMIShortIdentifier, 'max':1, 'delimiter':'', 'unique':false},
76         'numeric':{'format':CMIDecimal, 'max':1, 'delimiter':'', 'unique':false},
77         'other':{'format':CMIString4000, 'max':1, 'delimiter':'', 'unique':false}
78     }
79     var correct_responses = {
80         'true-false':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false,
81                       'format':'^true$|^false$', 
82                       'limit':1},
83         'choice':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':true, 'duplicate':false,
84                   'format':CMIIdentifier},
85         'fill-in':{'pre':'^(\{case_matters=(true|false)\})(\{order_matters=(true|false)\})?|^(\{order_matters=(true|false)\})(\{case_matters=(true|false)\})?',
86                    'max':10, 'delimiter':'[,]', 'unique':false, 'duplicate':false,
87                    'format':CMILangString250},
88         'long-fill-in':{'pre':'^(\{case_matters=(true|false)\})?', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':true,
89                         'format':CMILangString4000},
90         'matching':{'pre':'', 'max':36, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':true,
91                     'format':CMIShortIdentifier, 'format2':CMIShortIdentifier},
92         'performance':{'pre':'^(\{order_matters=(true|false)\})?',
93                        'max':250, 'delimiter':'[,]', 'delimiter2':'[.]', 'unique':false, 'duplicate':true,
94                        'format':'^$|'+CMIShortIdentifier, 'format2':CMIDecimal+'|^$|'+CMIShortIdentifier},
95         'sequencing':{'pre':'', 'max':36, 'delimiter':'[,]', 'unique':false, 'duplicate':false,
96                       'format':CMIShortIdentifier},
97         'likert':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false,
98                   'format':CMIShortIdentifier,
99                   'limit':1},
100         'numeric':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false,
101                    'format':CMIDecimal,
102                    'limit':1},
103         'other':{'pre':'', 'max':1, 'delimiter':'', 'unique':false, 'duplicate':false,
104                  'format':CMIString4000,
105                  'limit':1}
106     }
108     // The SCORM 1.3 data model
109     var datamodel =  {
110         'cmi._children':{'defaultvalue':cmi_children, 'mod':'r'},
111         'cmi._version':{'defaultvalue':'1.0', 'mod':'r'},
112         'cmi.comments_from_learner._children':{'defaultvalue':comments_children, 'mod':'r'},
113         'cmi.comments_from_learner._count':{'mod':'r', 'defaultvalue':'0'},
114         'cmi.comments_from_learner.n.comment':{'format':CMILangString4000, 'mod':'rw'},
115         'cmi.comments_from_learner.n.location':{'format':CMIString250, 'mod':'rw'},
116         'cmi.comments_from_learner.n.timestamp':{'format':CMITime, 'mod':'rw'},
117         'cmi.comments_from_lms._children':{'defaultvalue':comments_children, 'mod':'r'},
118         'cmi.comments_from_lms._count':{'mod':'r', 'defaultvalue':'0'},
119         'cmi.comments_from_lms.n.comment':{'format':CMILangString4000, 'mod':'r'},
120         'cmi.comments_from_lms.n.location':{'format':CMIString250, 'mod':'r'},
121         'cmi.comments_from_lms.n.timestamp':{'format':CMITime, 'mod':'r'},
122         'cmi.completion_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.completion_status'})?$userdata->{'cmi.completion_status'}:'unknown' ?>', 'format':CMICStatus, 'mod':'rw'},
123         'cmi.completion_threshold':{'defaultvalue':<?php echo isset($userdata->threshold)?'\''.$userdata->threshold.'\'':'null' ?>, 'mod':'r'},
124         'cmi.credit':{'defaultvalue':'<?php echo isset($userdata->credit)?$userdata->credit:'' ?>', 'mod':'r'},
125         'cmi.entry':{'defaultvalue':'<?php echo $userdata->entry ?>', 'mod':'r'},
126         'cmi.exit':{'defaultvalue':'<?php echo isset($userdata->{'cmi.exit'})?$userdata->{'cmi.exit'}:'' ?>', 'format':CMIExit, 'mod':'w'},
127         'cmi.interactions._children':{'defaultvalue':interactions_children, 'mod':'r'},
128         'cmi.interactions._count':{'mod':'r', 'defaultvalue':'0'},
129         'cmi.interactions.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
130         'cmi.interactions.n.type':{'pattern':CMIIndex, 'format':CMIType, 'mod':'rw'},
131         'cmi.interactions.n.objectives._count':{'pattern':CMIIndex, 'mod':'r', 'defaultvalue':'0'},
132         'cmi.interactions.n.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
133         'cmi.interactions.n.timestamp':{'pattern':CMIIndex, 'format':CMITime, 'mod':'rw'},
134         'cmi.interactions.n.correct_responses._count':{'defaultvalue':'0', 'pattern':CMIIndex, 'mod':'r'},
135         'cmi.interactions.n.correct_responses.n.pattern':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'},
136         'cmi.interactions.n.weighting':{'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'},
137         'cmi.interactions.n.learner_response':{'pattern':CMIIndex, 'format':'CMIFeedback', 'mod':'rw'},
138         'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'},
139         'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'},
140         'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
141         'cmi.launch_data':{'defaultvalue':<?php echo isset($userdata->datafromlms)?'\''.$userdata->datafromlms.'\'':'null' ?>, 'mod':'r'},
142         'cmi.learner_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r'},
143         'cmi.learner_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r'},
144         'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'},
145         'cmi.learner_preference.audio_level':{'defaultvalue':'1', 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
146         'cmi.learner_preference.language':{'defaultvalue':'', 'format':CMILang, 'mod':'rw'},
147         'cmi.learner_preference.delivery_speed':{'defaultvalue':'1', 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
148         'cmi.learner_preference.audio_captioning':{'defaultvalue':'0', 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
149         'cmi.location':{'defaultvalue':<?php echo isset($userdata->{'cmi.location'})?'\''.$userdata->{'cmi.location'}.'\'':'null' ?>, 'format':CMIString1000, 'mod':'rw'},
150         'cmi.max_time_allowed':{'defaultvalue':<?php echo isset($userdata->maxtimeallowed)?'\''.$userdata->maxtimeallowed.'\'':'null' ?>, 'mod':'r'},
151         'cmi.mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r'},
152         'cmi.objectives._children':{'defaultvalue':objectives_children, 'mod':'r'},
153         'cmi.objectives._count':{'mod':'r', 'defaultvalue':'0'},
154         'cmi.objectives.n.id':{'pattern':CMIIndex, 'format':CMILongIdentifier, 'mod':'rw'},
155         'cmi.objectives.n.score._children':{'defaultvalue':score_children, 'pattern':CMIIndex, 'mod':'r'},
156         'cmi.objectives.n.score.scaled':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
157         'cmi.objectives.n.score.raw':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'},
158         'cmi.objectives.n.score.min':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'},
159         'cmi.objectives.n.score.max':{'defaultvalue':null, 'pattern':CMIIndex, 'format':CMIDecimal, 'mod':'rw'},
160         'cmi.objectives.n.success_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMISStatus, 'mod':'rw'},
161         'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'},
162         'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
163         'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
164         'cmi.progress_measure':{'defaultvalue':<?php echo isset($userdata->{'cmi.progess_measure'})?'\''.$userdata->{'cmi.progress_measure'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
165         'cmi.scaled_passing_score':{'defaultvalue':<?php echo isset($userdata->{'cmi.scaled_passing_score'})?'\''.$userdata->{'cmi.scaled_passing_score'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
166         'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'},
167         'cmi.score.scaled':{'defaultvalue':<?php echo isset($userdata->{'cmi.score.scaled'})?'\''.$userdata->{'cmi.score.scaled'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
168         'cmi.score.raw':{'defaultvalue':<?php echo isset($userdata->{'cmi.score.raw'})?'\''.$userdata->{'cmi.score.raw'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
169         'cmi.score.min':{'defaultvalue':<?php echo isset($userdata->{'cmi.score.min'})?'\''.$userdata->{'cmi.score.min'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
170         'cmi.score.max':{'defaultvalue':<?php echo isset($userdata->{'cmi.score.max'})?'\''.$userdata->{'cmi.score.max'}.'\'':'null' ?>, 'format':CMIDecimal, 'mod':'rw'},
171         'cmi.session_time':{'format':CMITimespan, 'mod':'w', 'defaultvalue':'PT0H0M0S'},
172         'cmi.success_status':{'defaultvalue':'<?php echo isset($userdata->{'cmi.success_status'})?$userdata->{'cmi.success_status'}:'unknown' ?>', 'format':CMISStatus, 'mod':'rw'},
173         'cmi.suspend_data':{'defaultvalue':<?php echo isset($userdata->{'cmi.suspend_data'})?'\''.$userdata->{'cmi.suspend_data'}.'\'':'null' ?>, 'format':CMIString64000, 'mod':'rw'},
174         'cmi.time_limit_action':{'defaultvalue':<?php echo isset($userdata->timelimitaction)?'\''.$userdata->timelimitaction.'\'':'null' ?>, 'mod':'r'},
175         'cmi.total_time':{'defaultvalue':'<?php echo isset($userdata->{'cmi.total_time'})?$userdata->{'cmi.total_time'}:'PT0H0M0S' ?>', 'mod':'r'},
176         'adl.nav.request':{'defaultvalue':'_none_', 'format':NAVEvent, 'mod':'rw'}
177     };
178     //
179     // Datamodel inizialization
180     //
181         var cmi = new Object();
182         cmi.comments_from_learner = new Object();
183         cmi.comments_from_learner._count = 0;
184         cmi.comments_from_lms = new Object();
185         cmi.comments_from_lms._count = 0;
186         cmi.interactions = new Object();
187         cmi.interactions._count = 0;
188         cmi.learner_preference = new Object();
189         cmi.objectives = new Object();
190         cmi.objectives._count = 0;
191         cmi.score = new Object();
193     // Navigation Object
194     var adl = new Object();
195         adl.nav = new Object();
196         adl.nav.request_valid = new Array();
198     for (element in datamodel) {
199         if (element.match(/\.n\./) == null) {
200             if ((typeof eval('datamodel["'+element+'"].defaultvalue')) != 'undefined') {
201                 eval(element+' = datamodel["'+element+'"].defaultvalue;');
202             } else {
203                 eval(element+' = "";');
204             }
205         }
206     }
208 <?php
209     // reconstitute objectives, comments_from_learner and comments_from_lms
210     scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.objectives', array('score'));
211     scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_learner', array());
212     scorm_reconstitute_array_element($scorm->version, $userdata, 'cmi.comments_from_lms', array());
213 ?>
215     if (cmi.completion_status == '') {
216         cmi.completion_status = 'not attempted';
217     } 
218     
219     //
220     // API Methods definition
221     //
222     var Initialized = false;
223     var Terminated = false;
224     var diagnostic = "";
226     function Initialize (param) {
227         errorCode = "0";
228         if (param == "") {
229             if ((!Initialized) && (!Terminated)) {
230                 Initialized = true;
231                 errorCode = "0";
232                 <?php 
233                     if (scorm_debugging($scorm)) {
234 //                        echo 'alert("Initialized SCORM 1.3");';
235                         echo 'LogAPICall("Initialize", param, "", errorCode);';
236                     }
237                 ?>
238                 return "true";
239             } else {
240                 if (Initialized) {
241                     errorCode = "103";
242                 } else {
243                     errorCode = "104";
244                 }
245             }
246         } else {
247             errorCode = "201";
248         }
249         <?php 
250             if (scorm_debugging($scorm)) {
251 //                echo 'alert("Initialize: "+GetErrorString(errorCode));';
252                 echo 'LogAPICall("Initialize", param, "", errorCode);';
253             }
254         ?>
255         return "false";
256     }
257     
258     function Terminate (param) {
259         errorCode = "0";
260         if (param == "") {
261             if ((Initialized) && (!Terminated)) {
262                 <?php 
263                     if (scorm_debugging($scorm)) {
264 //                        echo 'alert("Terminated SCORM 1.3");';
265                         echo 'LogAPICall("Terminate", param, "", 0);';
266                     }
267                 ?>
268                 Initialized = false;
269                 Terminated = true;
270                 var result = StoreData(cmi,true);
271                 if (adl.nav.request != '_none_') {
272                     switch (adl.nav.request) {
273                         case 'continue':
274                             setTimeout('top.nextSCO();',500);
275                         break;
276                         case 'previous':
277                             setTimeout('top.prevSCO();',500);
278                         break;
279                         case 'choice':
280                         break;
281                         case 'exit':
282                         break;
283                         case 'exitAll':
284                         break;
285                         case 'abandon':
286                         break;
287                         case 'abandonAll':
288                         break;
289                     }
290                 } else {
291                     if (<?php echo $scorm->auto ?> == 1) {
292                         setTimeout('top.nextSCO();',500);
293                     }
294                 }    
295                 return "true";
296             } else {
297                 if (Terminated) {
298                     errorCode = "113";
299                 } else {
300                     errorCode = "112";
301                 }
302             }
303         } else {
304             errorCode = "201";
305         }
306         <?php 
307             if (scorm_debugging($scorm)) {
308                 echo 'alert("Terminate: "+GetErrorString(errorCode));';
309             }
310         ?>
311         return "false";
312     }
313     
314     function GetValue (element) {
315         errorCode = "0";
316         diagnostic = "";
317         if ((Initialized) && (!Terminated)) {
318             if (element !="") {
319                 var expression = new RegExp(CMIIndex,'g');
320                 var elementmodel = String(element).replace(expression,'.n.');
321                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
322                     if (eval('datamodel["'+elementmodel+'"].mod') != 'w') {
324                         element = String(element).replace(/\.(\d+)\./, ".N$1.");
325                         element = element.replace(/\.(\d+)\./, ".N$1.");
327                         var elementIndexes = element.split('.');
328                         var subelement = element.substr(0,3);
329                         var i = 1;
330                         while ((i < elementIndexes.length) && (typeof eval(subelement) != "undefined")) {
331                             subelement += '.'+elementIndexes[i++];
332                         }
334                         if (subelement == element) {
336                             if ((typeof eval(subelement) != "undefined") && (eval(subelement) != null)) {
337                                 errorCode = "0";
338                                 <?php 
339                                     if (scorm_debugging($scorm)) {
340 //                                        echo 'alert("GetValue("+element+") -> "+eval(element));';
341                                         echo 'LogAPICall("GetValue", element, eval(element), 0);';
342                                     }
343                                 ?>
344                                 return eval(element);
345                             } else {
346                                 errorCode = "403";
347                             }
348                         } else {
349                             errorCode = "301";
350                         }
351                     } else {
352                         //errorCode = eval('datamodel["'+elementmodel+'"].readerror');
353                         errorCode = "405";
354                     }
355                 } else {
356                     var childrenstr = '._children';
357                     var countstr = '._count';
358                     var parentmodel = '';
359                     if (elementmodel.substr(elementmodel.length-childrenstr.length,elementmodel.length) == childrenstr) {
360                         parentmodel = elementmodel.substr(0,elementmodel.length-childrenstr.length);
361                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
362                             errorCode = "301";
363                             diagnostic = "Data Model Element Does Not Have Children";
364                         } else {
365                             errorCode = "401";
366                         }
367                     } else if (elementmodel.substr(elementmodel.length-countstr.length,elementmodel.length) == countstr) {
368                         parentmodel = elementmodel.substr(0,elementmodel.length-countstr.length);
369                         if ((typeof eval('datamodel["'+parentmodel+'"]')) != "undefined") {
370                             errorCode = "301";
371                             diagnostic = "Data Model Element Cannot Have Count";
372                         } else {
373                             errorCode = "401";
374                         }
375                     } else {
376                         parentmodel = 'adl.nav.request_valid.';
377                         if (element.substr(0,parentmodel.length) == parentmodel) {
378                             if (element.substr(parentmodel.length).match(NAVTarget) == null) {
379                                 errorCode = "301";
380                             } else {
381                                 if (adl.nav.request == element.substr(parentmodel.length)) {
382                                     return "true";
383                                 } else if (adl.nav.request == '_none_') {
384                                     return "unknown";
385                                 } else {
386                                     return "false";
387                                 }
388                             }
389                         } else {
390                             errorCode = "401";
391                         }
392                     }
393                 }
394             } else {
395                 errorCode = "301";
396             }
397         } else {
398             if (Terminated) {                
399                 errorCode = "123";
400             } else {
401                 errorCode = "122";
402             }
403         }
404         <?php 
405             if (scorm_debugging($scorm)) {
406 //                echo 'alert("GetValue("+element+") -> "+GetErrorString(errorCode));';
407                 echo 'LogAPICall("GetValue", element, "", errorCode);';
408             }
409         ?>
410         return "";
411     }
412     
413     function SetValue (element,value) {
414         errorCode = "0";
415         diagnostic = "";
416         if ((Initialized) && (!Terminated)) {
417             if (element != "") {
418                 var expression = new RegExp(CMIIndex,'g');
419                 var elementmodel = String(element).replace(expression,'.n.');
420                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
421                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
422                         if (eval('datamodel["'+elementmodel+'"].format') != 'CMIFeedback') {
423                             expression = new RegExp(eval('datamodel["'+elementmodel+'"].format'));
424                         } else {
425                             // cmi.interactions.n.type depending format accept everything at this stage
426                             expression = new RegExp(CMIFeedback);
427                         }
428                         value = value+'';
429                         var matches = value.match(expression);
430                         if ((matches != null) && ((matches.join('').length > 0) || (value.length == 0))) {
431                             // Value match dataelement format
433                             if (element != elementmodel) {
434                                 //This is a dynamic datamodel element
436                                 var elementIndexes = element.split('.');
437                                 var subelement = 'cmi';
438                                 var parentelement = 'cmi';
439                                 for (var i=1;(i < elementIndexes.length-1) && (errorCode=="0");i++) {
440                                     var elementIndex = elementIndexes[i];
441                                     if (elementIndexes[i+1].match(/^\d+$/)) {
442                                         if ((parseInt(elementIndexes[i+1]) > 0) && (elementIndexes[i+1].charAt(0) == 0)) {
443                                             // Index has a leading 0 (zero), this is not a number
444                                             errorCode = "351";
445                                         }
446                                         parentelement = subelement+'.'+elementIndex;
447                                         if ((typeof eval(parentelement) == "undefined") || (typeof eval(parentelement+'._count') == "undefined")) {
448                                             errorCode="408";
449                                         } else {
450                                             if (elementIndexes[i+1] > eval(parentelement+'._count')) {
451                                                 errorCode = "351";
452                                                 diagnostic = "Data Model Element Collection Set Out Of Order";
453                                             }
454                                             subelement = subelement.concat('.'+elementIndex+'.N'+elementIndexes[i+1]);
455                                             i++;
457                                             if (((typeof eval(subelement)) == "undefined") && (i < elementIndexes.length-2)) {
458                                                 errorCode="408";
459                                             }
460                                         }
461                                     } else {
462                                         subelement = subelement.concat('.'+elementIndex);
463                                     }
464                                 }
466                                 if (errorCode == "0") {
467                                     // Till now it's a real datamodel element
469                                     element = subelement.concat('.'+elementIndexes[elementIndexes.length-1]);
471                                     if ((typeof eval(subelement)) == "undefined") {
472                                         switch (elementmodel) {
473                                             case 'cmi.objectives.n.id': 
474                                                 if (!duplicatedID(element,parentelement,value)) {
475                                                     if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) {
476                                                         eval(parentelement+'._count++;');
477                                                         eval(subelement+' = new Object();');
478                                                         var subobject = eval(subelement);
479                                                         subobject.success_status = datamodel["cmi.objectives.n.success_status"].defaultvalue;
480                                                         subobject.completion_status = datamodel["cmi.objectives.n.completion_status"].defaultvalue;
481                                                         subobject.progress_measure = datamodel["cmi.objectives.n.progress_measure"].defaultvalue;
482                                                         subobject.score = new Object();
483                                                         subobject.score._children = score_children;
484                                                         subobject.score.scaled = datamodel["cmi.objectives.n.score.scaled"].defaultvalue;
485                                                         subobject.score.raw = datamodel["cmi.objectives.n.score.raw"].defaultvalue;
486                                                         subobject.score.min = datamodel["cmi.objectives.n.score.min"].defaultvalue;
487                                                         subobject.score.max = datamodel["cmi.objectives.n.score.max"].defaultvalue;
488                                                     }
489                                                 } else {
490                                                     errorCode="351";
491                                                     diagnostic = "Data Model Element ID Already Exists";
492                                                 }
493                                             break;
494                                             case 'cmi.interactions.n.id':
495                                                 if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) {
496                                                     eval(parentelement+'._count++;');
497                                                     eval(subelement+' = new Object();');
498                                                     var subobject = eval(subelement);
499                                                     subobject.objectives = new Object();
500                                                     subobject.objectives._count = 0;
501                                                 } 
502                                             break;
503                                             case 'cmi.interactions.n.objectives.n.id':
504                                                 if (typeof eval(parentelement) != "undefined") {
505                                                     if (!duplicatedID(element,parentelement,value)) {
506                                                         if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) {
507                                                             eval(parentelement+'._count++;');
508                                                             eval(subelement+' = new Object();');
509                                                         }
510                                                     } else {
511                                                         errorCode="351";
512                                                         diagnostic = "Data Model Element ID Already Exists";
513                                                     }
514                                                 } else {
515                                                     errorCode="408";
516                                                 }
517                                             break;
518                                             case 'cmi.interactions.n.correct_responses.n.pattern':
519                                                 if (typeof eval(parentelement) != "undefined") {
521                                                     // Use cmi.interactions.n.type value to check the right dataelement format
522                                                     if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) {
523                                                         var interactiontype = eval(String(parentelement).replace('correct_responses','type'));
524                                                         if ((typeof correct_responses[interactiontype].limit == 'undefined') ||
525                                                             (eval(parentelement+'._count') < correct_responses[interactiontype].limit)) {
526                                                             if (correct_responses[interactiontype].pre != '') {
527                                                                 matches = value.match(correct_responses[interactiontype].pre);
528                                                                 if (matches != null) {
529                                                                     value = value.substr(0,matches[1].length);
530                                                                 }
531                                                             }
532                                                             var nodes = new Array();
533                                                             if (correct_responses[interactiontype].delimiter != '') {
534                                                                 nodes = value.split(correct_responses[interactiontype].delimiter);
535                                                             } else {
536                                                                 nodes[0] = value;
537                                                             }
538                                                             if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) {
539                                                                 expression = new RegExp(correct_responses[interactiontype].format);
540                                                                 for (var i=0; (i < nodes.length) && (errorCode=="0"); i++) {
541                                                                     if (typeof correct_responses[interactiontype].delimiter2 != 'undefined') {
542                                                                         values = nodes[i].split(correct_responses[interactiontype].delimiter2);
543                                                                         if (values.length == 2) {
544                                                                             matches = values[0].match(expression);
545                                                                             if (matches == null) {
546                                                                                 errorCode = "406";
547                                                                             } else {
548                                                                                 var expression2= new RegExp(correct_responses[interactiontype].format2);
549                                                                                 matches = values[1].match(expression2);
550                                                                                 if ((matches == null) || (matches.join('').length == 0)) {
551                                                                                     errorCode = "406";
552                                                                                 }
553                                                                             }
554                                                                         } else {
555                                                                             errorCode = "406";
556                                                                         }
557                                                                     } else {
558                                                                         matches = nodes[i].match(expression);
559                                                                         if (matches == null) {
560                                                                             errorCode = "406";
561                                                                         } else {
562                                                                             if ((nodes[i] != '') && (correct_responses[interactiontype].unique)) {
563                                                                                 for (var j=0; (j<i) && (errorCode=="0"); j++) {
564                                                                                     if (nodes[i] == nodes[j]) {
565                                                                                         errorCode = "406";
566                                                                                     }
567                                                                                 }
568                                                                             }
569                                                                         }
570                                                                     }
571                                                                 }
572                                                             } else if (nodes.length > correct_responses[interactiontype].max) {
573                                                                 errorCode = "351";
574                                                                 diagnostic = "Data Model Element Pattern Too Long";
575                                                             }
576                                                             if ((errorCode == "0") &&
577                                                                ((correct_responses[interactiontype].duplicate == false) || 
578                                                                (!duplicatedPA(element,parentelement,value)))) {
579                                                                eval(parentelement+'._count++;');
580                                                                eval(subelement+' = new Object();');
581                                                             } else {
582                                                                 errorCode="351";
583                                                                 diagnostic = "Data Model Element Pattern Already Exists";
584                                                             }
585                                                         } else {
586                                                             errorCode="351";
587                                                             diagnostic = "Data Model Element Collection Limit Reached";
588                                                         }
589                                                     } else {
590                                                         errorCode="351";
591                                                         diagnostic = "Data Model Element Collection Set Out Of Order";
592                                                     }
593                                                 } else {
594                                                     errorCode="408";
595                                                 }
596                                             break;
597                                             default:
598                                                 if ((parentelement != 'cmi.objectives') && (parentelement != 'cmi.interactions') && (typeof eval(parentelement) != "undefined")) {
599                                                     if (elementIndexes[elementIndexes.length-2] == eval(parentelement+'._count')) {
600                                                         eval(parentelement+'._count++;');
601                                                         eval(subelement+' = new Object();');
602                                                     } else {
603                                                         errorCode="351";
604                                                         diagnostic = "Data Model Element Collection Set Out Of Order";
605                                                     } 
606                                                 } else {
607                                                     errorCode="408";
608                                                 }
609                                             break;
610                                         }
611                                     } else {
612                                         switch (elementmodel) {
613                                             case 'cmi.objectives.n.id':
614                                                 if (eval(element) != value) {
615                                                     errorCode = "351";
616                                                     diagnostic = "Write Once Violation";
617                                                 }
618                                             break; 
619                                             case 'cmi.interactions.n.objectives.n.id':
620                                                 if (duplicatedID(element,parentelement,value)) {
621                                                     errorCode = "351";
622                                                     diagnostic = "Data Model Element ID Already Exists";
623                                                 }
624                                             break;
625                                             case 'cmi.interactions.n.type':
626                                                 var subobject = eval(subelement);
627                                                 subobject.correct_responses = new Object();
628                                                 subobject.correct_responses._count = 0;
629                                             break;
630                                             case 'cmi.interactions.n.learner_response':
631                                                 if (typeof eval(subelement+'.type') == "undefined") {
632                                                     errorCode="408";
633                                                 } else {
634                                                     // Use cmi.interactions.n.type value to check the right dataelement format
635                                                     interactiontype = eval(subelement+'.type');
636                                                     var nodes = new Array();
637                                                     if (learner_response[interactiontype].delimiter != '') {
638                                                         nodes = value.split(learner_response[interactiontype].delimiter);
639                                                     } else {
640                                                         nodes[0] = value;
641                                                     }
642                                                     if ((nodes.length > 0) && (nodes.length <= learner_response[interactiontype].max)) {
643                                                         expression = new RegExp(learner_response[interactiontype].format);
644                                                         for (var i=0; (i < nodes.length) && (errorCode=="0"); i++) {
645                                                             if (typeof learner_response[interactiontype].delimiter2 != 'undefined') {
646                                                                 values = nodes[i].split(learner_response[interactiontype].delimiter2);
647                                                                 if (values.length == 2) {
648                                                                     matches = values[0].match(expression);
649                                                                     if (matches == null) {
650                                                                         errorCode = "406";
651                                                                     } else {
652                                                                         var expression2 = new RegExp(learner_response[interactiontype].format2);
653                                                                         matches = values[1].match(expression2);
654                                                                         if (matches == null) {
655                                                                             errorCode = "406";
656                                                                         }
657                                                                     }
658                                                                 } else {
659                                                                     errorCode = "406";
660                                                                 }
661                                                             } else {
662                                                                 matches = nodes[i].match(expression);
663                                                                 if (matches == null) {
664                                                                     errorCode = "406";
665                                                                 } else {
666                                                                     if ((nodes[i] != '') && (learner_response[interactiontype].unique)) {
667                                                                         for (var j=0; (j<i) && (errorCode=="0"); j++) {
668                                                                             if (nodes[i] == nodes[j]) {
669                                                                                 errorCode = "406";
670                                                                             }
671                                                                         }
672                                                                     }
673                                                                 }
674                                                             }
675                                                         }
676                                                     } else if (nodes.length > learner_response[interactiontype].max) {
677                                                         errorCode = "351";
678                                                         diagnostic = "Data Model Element Pattern Too Long";
679                                                     }
680                                                 }
681                                              break;
682                                             case 'cmi.interactions.n.correct_responses.n.pattern':
683                                                                                          subel= subelement.split('.');
684                                                                                          subel1= 'cmi.interactions.'+subel[2];
685                                                         
687                                                  if (typeof eval(subel1+'.type') == "undefined") {
689                                                     errorCode="408";
690                                                 } else {
691                         
692         
693                                                     // Use cmi.interactions.n.type value to check the right //dataelement format
694                                                     interactiontype = eval(subel1+'.type');
695                                                     var nodes = new Array();
696                                                     if (correct_responses[interactiontype].delimiter != '') {
697                                                         nodes = value.split(correct_responses[interactiontype].delimiter);
698                                                     } else {
699                                                         nodes[0] = value;
700                                                     }
701         
702                                                     if ((nodes.length > 0) && (nodes.length <= correct_responses[interactiontype].max)) {
703                                                         expression = new RegExp(correct_responses[interactiontype].format);
704                                                         for (var i=0; (i < nodes.length) && (errorCode=="0"); i++) {
705                                                             if (typeof correct_responses[interactiontype].delimiter2 != 'undefined') {
706                 
707         
708                                                                 values = nodes[i].split(correct_responses[interactiontype].delimiter2);
709                                                                 if (values.length == 2) {
710                 
711                                                                     matches = values[0].match(expression);
712                                                                     if (matches == null) {
713                 
714                                                                         errorCode = "406";
715                                                                     } else {
716                 
717                                                                         var expression2 = new RegExp(correct_responses[interactiontype].format2);
718                                                                         matches = values[1].match(expression2);
719                                                                         if (matches == null) {
720         
721                                                                             errorCode = "406";
722                                                                         }
723                                                                     }
724                                                                 } else {
725                                                                          errorCode = "406";
726                                                                 }
727                                                             } else {
729                                                                 matches = nodes[i].match(expression);
730                                                                 //if ((matches == null) || (matches.join('').length == 0)) {
731                                                                 if ((matches == null && value != "")||(matches == null && interactiontype=="true-false")){
733                                                                     errorCode = "406";
734                                                                 } else {
736                                                                     if ((nodes[i] != '') && (correct_responses[interactiontype].unique)) {
737                                                                         for (var j=0; (j<i) && (errorCode=="0"); j++) {
738                                                                             if (nodes[i] == nodes[j]) {
739         
740                                                                                 errorCode = "406";
741                                                                             }
742                                                                         }
743                                                                     }
744                                                                     }
745                                                             }
746                                                         }
747                                                     } else if (nodes.length > correct_responses[interactiontype].max) {
748         
749                                                         errorCode = "351";
750                                                         diagnostic = "Data Model Element Pattern Too Long";
751                                                     }
752         
753                                                 }
754                                              break;
755                                         } 
756                                     }
757                                 }
758                             }
759                             //Store data
760                             if (errorCode == "0") {
762                                 if ((typeof eval('datamodel["'+elementmodel+'"].range')) != "undefined") {
763                                     range = eval('datamodel["'+elementmodel+'"].range');
764                                     ranges = range.split('#');
765                                     value = value*1.0;
766                                     if (value >= ranges[0]) {
767                                         if ((ranges[1] == '*') || (value <= ranges[1])) {
768                                             eval(element+'=value;');
769                                             errorCode = "0";
770                                             <?php 
771                                                 if (scorm_debugging($scorm)) {
772 //                                                    echo 'alert("SetValue("+element+","+value+") -> OK");';
773                                                     echo 'LogAPICall("SetValue", element, value, errorCode);';
774                                                 }
775                                             ?>
776                                             return "true";
777                                         } else {
778                                             errorCode = '407';
779                                         }
780                                     } else {
781                                         errorCode = '407';
782                                     }
783                                 } else {
784                                     eval(element+'=value;');
785                                     errorCode = "0"; 
786                                     <?php 
787                                         if (scorm_debugging($scorm)) {
788 //                                           echo 'alert("SetValue("+element+","+value+") -> OK");';
789                                             echo 'LogAPICall("SetValue", element, value, errorCode);';
790                                         }
791                                     ?>
792                                     return "true";
793                                 }
794                             }
795                         } else {
796                             errorCode = "406";
797                         }
798                     } else {
799                         errorCode = "404";
800                     }
801                 } else {
802                     errorCode = "401"
803                 }
804             } else {
805                 errorCode = "351";
806             }
807         } else {
808             if (Terminated) {
809                 errorCode = "133";
810             } else {
811                 errorCode = "132";
812             }
813         }
814         <?php 
815             if (scorm_debugging($scorm)) {
816                 echo 'LogAPICall("SetValue", element, value, errorCode);';
817             }
818         ?>
819         return "false";
820     }
821     
822     function Commit (param) {
823         errorCode = "0";
824         if (param == "") {
825             if ((Initialized) && (!Terminated)) {
826                 result = StoreData(cmi,false);
827                 <?php 
828                     if (scorm_debugging($scorm)) {
829                         echo 'LogAPICall("Commit", param, "", 0);';
830                         //echo 'alert("Data Commited");';
831                     }
832                 ?>
833                 return "true";
834             } else {
835                 if (Terminated) {
836                     errorCode = "143";
837                 } else {
838                     errorCode = "142";
839                 }
840             }
841         } else {
842             errorCode = "201";
843         }
844         <?php 
845             if (scorm_debugging($scorm)) {
846                 echo 'LogAPICall("Commit", param, "", 0);';
847 //                echo 'alert("Commit: "+GetErrorString(errorCode));';
848             }
849         ?>
850         return "false";
851     }
852     
853     function GetLastError () {
854      <?php 
855         if (scorm_debugging($scorm)) {
856             echo 'LogAPICall("GetLastError", "", "", errorCode);';
857         }
858     ?>
859         return errorCode;
860     }
861     
862     function GetErrorString (param) {
863         if (param != "") {
864             var errorString = "";
865             switch(param) {
866                 case "0":
867                     errorString = "No error";
868                 break;
869                 case "101":
870                     errorString = "General exception";
871                 break;
872                 case "102":
873                     errorString = "General Inizialization Failure";
874                 break;
875                 case "103":
876                     errorString = "Already Initialized";
877                 break;
878                 case "104":
879                     errorString = "Content Instance Terminated";
880                 break;
881                 case "111":
882                     errorString = "General Termination Failure";
883                 break;
884                 case "112":
885                     errorString = "Termination Before Inizialization";
886                 break;
887                 case "113":
888                     errorString = "Termination After Termination";
889                 break;
890                 case "122":
891                     errorString = "Retrieve Data Before Initialization";
892                 break;
893                 case "123":
894                     errorString = "Retrieve Data After Termination";
895                 break;
896                 case "132":
897                     errorString = "Store Data Before Inizialization";
898                 break;
899                 case "133":
900                     errorString = "Store Data After Termination";
901                 break;
902                 case "142":
903                     errorString = "Commit Before Inizialization";
904                 break;
905                 case "143":
906                     errorString = "Commit After Termination";
907                 break;
908                 case "201":
909                     errorString = "General Argument Error";
910                 break;
911                 case "301":
912                     errorString = "General Get Failure";
913                 break;
914                 case "351":
915                     errorString = "General Set Failure";
916                 break;
917                 case "391":
918                     errorString = "General Commit Failure";
919                 break;
920                 case "401":
921                     errorString = "Undefinited Data Model";
922                 break;
923                 case "402":
924                     errorString = "Unimplemented Data Model Element";
925                 break;
926                 case "403":
927                     errorString = "Data Model Element Value Not Initialized";
928                 break;
929                 case "404":
930                     errorString = "Data Model Element Is Read Only";
931                 break;
932                 case "405":
933                     errorString = "Data Model Element Is Write Only";
934                 break;
935                 case "406":
936                     errorString = "Data Model Element Type Mismatch";
937                 break;
938                 case "407":
939                     errorString = "Data Model Element Value Out Of Range";
940                 break;
941                 case "408":
942                     errorString = "Data Model Dependency Not Established";
943                 break;
944             }
945             <?php 
946             if (scorm_debugging($scorm)) {
947                 echo 'LogAPICall("GetErrorString", param,  errorString, 0);';
948             }
949              ?>
950             return errorString;
951         } else {
952            <?php 
953             if (scorm_debugging($scorm)) {
954                 echo 'LogAPICall("GetErrorString", param,  "No error string found!", 0);';
955             }
956              ?>
957             return "";
958         }
959     }
960     
961     function GetDiagnostic (param) {
962         if (diagnostic != "") {
963             <?php 
964                 if (scorm_debugging($scorm)) {
965                     echo 'LogAPICall("GetDiagnostic", param, diagnostic, 0);';
966                 }
967             ?>
968             return diagnostic;
969         }
970         <?php 
971             if (scorm_debugging($scorm)) {
972                 echo 'LogAPICall("GetDiagnostic", param, param, 0);';
973             }
974         ?>
975         return param;
976     }
978     function duplicatedID (element, parent, value) {
979         var found = false;
980         var elements = eval(parent+'._count');
981         for (var n=0;(n < elements) && (!found);n++) {
982             if ((parent+'.N'+n+'.id' != element) && (eval(parent+'.N'+n+'.id') == value)) {
983                 found = true;
984             }
985         } 
986         return found;
987     }
989     function duplicatedPA (element, parent, value) {
990         var found = false;
991         var elements = eval(parent+'._count');
992         for (var n=0;(n < elements) && (!found);n++) {
993             if ((parent+'.N'+n+'.pattern' != element) && (eval(parent+'.N'+n+'.pattern') == value)) {
994                 found = true;
995             }
996         } 
997         return found;
998     }
1000     function getElementModel(element) {
1001         if (typeof datamodel[element] != "undefined") {
1002             return element;
1003         } else {
1004             var expression = new RegExp(CMIIndex,'g');
1005             var elementmodel = String(element).replace(expression,'.n.');
1006             if (typeof datamodel[elementmodel] != "undefined") {
1007                 return elementmodel;
1008             }
1009         }
1010         return false;
1011     }
1013     function AddTime (first, second) {
1014         <?php 
1015 //            if (scorm_debugging($scorm)) {
1016 //                echo 'alert("AddTime: "+first+" + "+second);';
1017 //            }
1018         ?>
1019         var timestring = 'P';
1020         var matchexpr = /^P((\d+)Y)?((\d+)M)?((\d+)D)?(T((\d+)H)?((\d+)M)?((\d+(\.\d{1,2})?)S)?)?$/;
1021         var firstarray = first.match(matchexpr);
1022         var secondarray = second.match(matchexpr);
1023         if ((firstarray != null) && (secondarray != null)) {
1024             var secs = parseFloat(firstarray[13],10)+parseFloat(secondarray[13],10);  //Seconds
1025             var change = Math.floor(secs / 60);
1026             secs = secs - (change * 60);
1027             var mins = parseInt(firstarray[11],10)+parseInt(secondarray[11],10)+change;   //Minutes
1028             change = Math.floor(mins / 60);
1029             mins = mins - (change * 60);
1030             var hours = parseInt(firstarray[9],10)+parseInt(secondarray[9],10)+change;  //Hours
1031             change = Math.floor(hours / 24);
1032             hours = hours - (change * 24);
1033             var days = parseInt(firstarray[6],10)+parseInt(secondarray[6],10)+change; // Days
1034             var months = parseInt(firstarray[4],10)+parseInt(secondarray[4],10)
1035             var years = parseInt(firstarray[2],10)+parseInt(secondarray[2],10)
1036         }
1037         if (years > 0) {
1038             timestring += years + 'Y';
1039         }
1040         if (months > 0) {
1041             timestring += months + 'M';
1042         }
1043         if (days > 0) {
1044             timestring += days + 'D';
1045         }
1046         if ((hours > 0) || (mins > 0) || (secs > 0)) {
1047             timestring += 'T';
1048             if (hours > 0) {
1049                 timestring += hours + 'H';
1050             }
1051             if (mins > 0) {
1052                 timestring += mins + 'M';
1053             }
1054             if (secs > 0) {
1055                 timestring += secs + 'S';
1056             }
1057         }
1058         return timestring;
1059     }
1061     function TotalTime() {
1062         var total_time = AddTime(cmi.total_time, cmi.session_time);
1063         return '&'+underscore('cmi.total_time')+'='+encodeURIComponent(total_time);
1064     }
1066     function CollectData(data,parent) {
1067         var datastring = '';
1068         for (property in data) {
1069             if (typeof data[property] == 'object') {
1070                 datastring += CollectData(data[property],parent+'.'+property);
1071             } else {
1072                 var element = parent+'.'+property;
1073                 var expression = new RegExp(CMIIndexStore,'g');
1074                 var elementmodel = String(element).replace(expression,'.n.');
1075                 if ((typeof eval('datamodel["'+elementmodel+'"]')) != "undefined") {
1076                     if (eval('datamodel["'+elementmodel+'"].mod') != 'r') {
1077                         var elementstring = '&'+underscore(element)+'='+encodeURIComponent(data[property]);
1078                         if ((typeof eval('datamodel["'+elementmodel+'"].defaultvalue')) != "undefined") {
1079                             if (eval('datamodel["'+elementmodel+'"].defaultvalue') != data[property]) {
1080                                 datastring += elementstring;
1081                             }
1082                         } else {
1083                             datastring += elementstring;
1084                         }
1085                     }
1086                 }
1087             }
1088         }
1089         return datastring;
1090     }
1092     function StoreData(data,storetotaltime) {
1093         var datastring = '';
1094         if (storetotaltime) {
1095             if (cmi.mode == 'normal') {
1096                 if (cmi.credit == 'credit') {
1097                     if ((cmi.completion_threshold != null) && (cmi.progress_measure != null)) {
1098                         if (cmi.progress_measure >= cmi.completion_threshold) {
1099                             cmi.completion_status = 'completed';
1100                         } else {
1101                             cmi.completion_status = 'incomplete';
1102                         }
1103                     }
1104                     if ((cmi.scaled_passed_score != null) && (cmi.score.scaled != '')) {
1105                         if (cmi.score.scaled >= cmi.scaled_passed_score) {
1106                             cmi.success_status = 'passed';
1107                         } else {
1108                             cmi.success_status = 'failed';
1109                         }
1110                     }
1111                 }
1112             }
1113             datastring += TotalTime();
1114         }
1115         datastring += CollectData(data,'cmi');
1116         var element = 'adl.nav.request';
1117         var navrequest = eval(element) != datamodel[element].defaultvalue ? '&'+underscore(element)+'='+encodeURIComponent(eval(element)) : '';
1118         datastring += navrequest;
1119         datastring += '&attempt=<?php echo $attempt ?>';
1120         datastring += '&scoid=<?php echo $scoid ?>';
1121         <?php
1122 //            if (scorm_debugging($scorm)) {
1123 //                echo 'popupwin(datastring);';
1124 //            }
1125         ?>
1126         var myRequest = NewHttpReq();
1127         var result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/datamodel.php","id=<?php p($id) ?>&sesskey=<?php p($USER->sesskey) ?>"+datastring);
1128         <?php
1129 //            if (scorm_debugging($scorm)) {
1130 //                echo 'popupwin(result);';
1131 //            }
1132         ?>
1133         var results = String(result).split('\n');
1134         if ((results.length > 2) && (navrequest != '')) {
1135             eval(results[2]);
1136         }
1137         errorCode = results[1];
1138         return results[0];
1139     }
1140     
1141     this.Initialize = Initialize;
1142     this.Terminate = Terminate;
1143     this.GetValue = GetValue;
1144     this.SetValue = SetValue;
1145     this.Commit = Commit;
1146     this.GetLastError = GetLastError;
1147     this.GetErrorString = GetErrorString;
1148     this.GetDiagnostic = GetDiagnostic;
1149     this.version = '1.0';
1152 var API_1484_11 = new SCORMapi1_3();
1154 <?php
1155 // pull in the debugging utilities
1156 if (scorm_debugging($scorm)) {
1157     include_once($CFG->dirroot.'/mod/scorm/datamodels/debug.js.php');
1158     echo 'AppendToLog("Moodle SCORM 1.3 API Loaded, Activity: '.$scorm->name.', SCO: '.$sco->identifier.'", 0);';
1160  ?>