Project

General

Profile

Actions

SCORM

This article is currently just a little bit out of date because of a massive and frantic move in the SCORM development.
Notably, the frames structure has been kept (actually using frames instead of iframes) because
priorities on redesign have been put on the data rather than the visuals and some optional SCORM
"enhancements" have been added, which help make sure every SCORM information is carried over into
the Chamilo system. This is all available in Chamilo 1.8 CVS at the moment but not completely clean
and complete yet.

Introduction

This page is attempted as a complete study of the SCORM tool in Chamilo, including its history. It will probably be a great helper in the exchanges concerning the new SCORM tool (planned for Chamilo 1.8 as the development was a bit too late to make it for 1.7).

SCORM in general

SCORM (Sharable Content Object Reference Model (tm)) is a norm accepted as a standard by many e-learning courses producers (and management systems). It defines a set of messages a SCORM-compatible course and a SCORM-compatible e-learning platform must be able to exchange and how.

The information exchange is generally provided by the means of JavaScript (which can also be faked by other languages like Java, Flash, ...).

A SCORM content is composed of several SCO. A SCO (Sharable Content Object) is the smallest content item size defined in the SCORM norm. Each SCO must, if defined that way, be able to connect to a SCORM API in its environment and exchange messages with it.

SCORM has already several versions in its history. For this tool, we use SCORM version 1.2. The latest version at the moment is version 2004 (or 1.3), which we will not cover (yet) here, but we intend to have a SCORM tool as flexible as possible so we can develop a SCORM 2004 layer as we have developped a SCORM 1.2 layer.

The SCORM norm is edited by a company called Advanced Distributed Learning. You can get more information on this company and the SCORM norm [http://www.adlnet.org/scorm/history/ here]

Several official documents are available about SCORM 1.2. The two main documents of interest to us are the SCORM Runtime Environment document and the SCORM Content Aggregation Model document.

'''SCORM Runtime Environment''' explains the '''SCORM API''' (set of standard functions made available to the SCORM content by the e-Learning Management System) and the different responsabilities both sides (content and LMS) have, respectively. It also explains the '''Data Model''', which describes the objects available in SCORM, or the data SCORM information should be kept into.

'''SCORM Content Aggregation Model''' explains how to aggregate learning resources together to build a "learning experience", or as we call it in Chamilo, a "learning path". It describes the structure of an '''imsmanifest.xml''' file, '''meta-data''' and the overall '''packaging''' of a SCORM resource.

SCORM for Chamilo 1.6

The SCORM tool in Chamilo 1.6 was largely developed by Isthvan Mandak and Denes Nagy based on SCORM examples. Considering this fact, it can be said that this tool provided a very essential feature in Chamilo, as many other e-learning tools did not integrate SCORM at all.

This section is about the current SCORM tool, how it works, what information it stores and how far it goes into the SCORM integration. This section will also expose some flaws found in this tool that are the reasons for the tool redesign (see "Planning SCORM for Chamilo 1.8" section below).

Code 1.6

If you are reading this document, you are encouraged to do it with a copy of the Chamilo code available on the website.

The following schema might help you understand how the SCORM tool works in Chamilo.

[[image:scorm_process.png]]

The main code for the SCORM tool is in claroline/scorm. Let's see the composing files one by one.

  • blank.php
    This script is a blank page used to show on the lower left edge of the scorm viewer page. It contains the "message" css class, which will be used by JavaScript functions to display report messages during the SCORM navigation
  • closesco.php
    This script will be loaded (but not displayed) when a SCO is closed and sent a closing signal. The script will then write the corresponding closing information into the scorm database of the Chamilo installation
  • contents.php
    This script is loaded in the lower-right frame and is the main content-display script. It actually updates the SCORM database in Chamilo (to register the opening of a SCO) and displays the resource in the frame. It also deals with the stats display when the user clicked on the stats icon in the SCORM navigation bar
  • headerpage.php
    This script is used to display the header part of the Chamilo platform (includes HTML header parts)
  • index.php
    This script should be used as the main page but is obviously not in use anymore (as the in-file comment shows)
  • load.php
    This script is used as the navigation bar inside the SCORM tool. It allows getting back, forward, restart the learning path, display the status and switch between full screen and embedded mode
  • opensco.php
    This script opens a SCO into the destination frame (the lower-right frame) and initialises PHP session values (as well as loading contents.php and scormfunctions.php if needed)
  • scormbuilder* scripts
    These scripts, if still in use, enable the building of imsmanifest.xml files.
  • scormdocument.php
    This is the main entry point to SCORM and Chamilo learning paths. It actually displays the list of learning paths available and allows basic edition of the existing learnpaths.
  • scormfunctions.php
    This script is in fact mainly a JavaScript containing the official set of SCORM API functions to be made available to the contents loaded in the viewer. Giving access to these functions is done by loading them before the content. Once the content is launched, JavaScript functions inside the content look for an available SCORM API and connects to it with JavaScript. This means that JavaScript is a mandatory element to use the SCORM tool and that loading these functions in Chamilo is mandatory as well to get any interaction with the content
  • scormparsing.lib.php
    This script contains a library of functions used in the parsing of the imsmanifest.xml file. The imsmanifest file is generally read once and its contents are input in the Chamilo SCORM database
  • showinframes.php
    This script is the main viewer window. It declares all the frames used by the SCORM tool. It is mainly an HTML file, with a few checks for the type of content.
  • XMLencode.php
    This script only contains one function which detects the character encoding of a imsmanifest.xml file. This is used later on for the messages display (to use the same encoding in Chamilo and in the content)

Database 1.6

The database structure is pretty simple. One table contains the information relative to the learnpath in general (title, course) and the other contains the SCORM items and their status, scores, ...
[[image:Scorm.png]]

SCORM signals (Chamilo 1.6)

The Chamilo 1.6 SCORM tool supports only a small subset of the available SCORM signals. Or actually, only a small subset of the parameters given to the functions calls GetValue(x) and SetValue(x,y).

The basic SCORM signals are given by pair thatdo the same thing (they only change names): {|border=1
!style="background:#efefef;" | First header !!style="background:#efefef;" | Same function with LMS prefix !!style="background:#efefef;" | What it does...

|- |Initialize || LMSInitialize || Initialises the SCORM object in the e-learning system in JS global scope (the document object) |- | GetValue || LMSGetValue || Gets the value of one of the SCO attributes |- | SetValue || LMSSetValue || Sets the value of one of the SCO attributes |- | Commit || LMSCommit || Calls the e-learning system "save" function to save the SCO attributes into the e-learning database |- | Finish || LMSFinish || Puts an end to the use of the current JS object (the SCO item has been finished) |- | GetLastError || LMSGetLastError || Gets the last error (not supported - fooled with "No error" message) |- | GetErrorString || LMSGetErrorString || Gets the error string (not supported - fooled with "No error" message) |- | GetDiagnostic || LMSGetDiagnostic || Gets a diagnostic (not supported - fooled with "No error" message) |}

The important bit here is the two functions GetValue(x) and SetValue(x,y). Let's analyse the possible 'x' values here.
The CMI is the JavaScript object containing volatile information about the opened SCO item. {|border=1
!style="background:#efefef;" | Parameter !!style="background:#efefef;" | Usage !!style="background:#efefef;" | Support for GetValue? !!style="background:#efefef;" | Support for SetValue? |- | cmi.core._children<br />cmi.core_children || Contains the elements supported by the CMI || static - only returns "entry, exit, lesson_status, student_id, student_name, lesson_location, total_time, credit, lesson_mode, score, session_time" in any case || |- | cmi.core.entry || ? || None. Returns "" || |- | cmi.core.exit || ? || None. Returns "" || |- | cmi.core.lesson_status || Status of the current SCO item || Dynamic. Gets it into the SCORM database in Chamilo || Dynamic. When set and commited, it is recorder in the Chamilo database |- | cmi.core.student_id || The ID of the student viewing the SCO, Chamilo-wise || Dynamic. Gets it from the session variables || None. Cannot set the user ID |- | cmi.core.student_name || The full name of the student viewing the SCO || Dynamic. Gets it from the session variables || None. Cannot set the user name |- | cmi.core.lesson_location || The id (or page) of the lesson, in the SCORM package terms || None. Returns "" || None. |- | cmi.core.total_time || The total time spent on this SCO || None. Returns "0000:00:00.00" || Dynamic. On commit, writes the value into the database. |- | cmi.core.score._children || Gets the attributes of the score object children || Static. Returns "raw,min,max" || None. |- | cmi.core.score.raw || Gets the score for the current SCO || Dynamic. Returns the score recorder into the CMI object at the moment, or "0" if none || Dynamic. On commit, writes the value into the database |- | cmi.core.score.max || Gets the maximum score for the current SCO || Static. Returns "100" || Dynamic. On commit, writes the value into the database. |- | cmi.core.score.min || Gets the maximum score for the current SCO || Static. Returns "0" || Dynamic. On commit, writes the value into the database. |- | cmi.core.score || Gets the score attribute for the current SCO || Static. Returns "0" || None. |- | cmi.core.credit || Gets the credit attribute for the current SCO || Static. Returns "no-credit" || ? |- | cmi.core.lesson_mode || Gets the lesson mode for the current SCO || Static. Returns "normal" || ? |- | cmi.suspend_data || Gets data stored during the last view of this SCO || None. Returns "" || None. |- | cmi.launch_data || ? || None. Returns "" || None. |- | cmi.objectives._count || Gets the attempt count. This should allow multi-uses of the same SCO || None. Returns "0" || None. |- | default (all other messages) || - || None. Returns "" || None. |}

SCORM for Chamilo 1.8

The new SCORM tool aims are:
  • Be much more compatible with SCORM thus allowing more courses sources to work in Chamilo
    • Allowing and dealing with assets and SCO resource types (done)
    • Allowing multi-views of the same SCO (or "attempts") (now debugging)
    • Enable SCORM/AICC "interactions" (now debugging)
  • Re-integrate SCORM learning paths into the same structure as the Chamilo learnpaths
    • Extend the Chamilo learnpath capabilities
    • Allow a hash field in the database to contain the CMI structure (or something extendable)
  • Make the learnpath tool easier to extend
    • Use an object-oriented approach to learnpaths and learnpath-items, allowing children classes to define refined behaviours (done)
    • Enable AICC compatibility (in progress)
    • Enable SCORM 2004 norm compliance
  • Make the learnpath tool easier to understand
  • Redesign the SCORM/learnpath viewer to avoid the numerous frames and non-sequential processing problems (in fullscreen - static frames embedded mode is delayed)
  • Add optional live error-logging (currently there is no way to track the JavaScript messages sent to the learning path without allowing popups to stop you all the way) (done - might extend later to record to a file if needed)
  • Being much better documented (this page is a first step towards this goal)

Use Cases

Soon (when needed)

Code

The code would be split into two parent (abstract) classes: learnpath and lpItem which would define the main code for the learning paths. Children classes like ChamiloLearnpath, ChamiloLPItem, scormLearnpath and scormLPItem would inherit from these classes and thus only add the necessary specialised code for Chamilo and SCORM learning paths.

This is for the background code.

The frontend code would be divided in a set of scripts that allow basic and more complex operations on the learnpaths. A first draft (only a draft) can be found on the picture below.
[[image:new_scorm_process2.png]]

The learning path viewer would only become a single page with an <iframe> tag embedded that would display the content. No other frame would be used, thus simplifying the code tracking much more.

Classes hierarchy

The following schema represents a draft of the class structure as it will be. For the new tool, only the Chamilo and SCORM 1.2 learnpath subclasses will be developed (not 1.3 and AICC) but the development is made thinking about these extensions (and actually already using some to prove their development is greatly simplified compared to the current SCORM tool).

The triangles represent class inheritance ("extends") which is handled by PHP4, while the diamonds represent class composition which is not handled by PHP4 but will be faked in the new tool's code.

[[image:New_scorm_class.png]]

Note that the lower classes (scorm_item, ...) might not need to exist as the behaviour will change in the reader depending on the "item_type" attribute. The classes really need to be different for each type of learning path, but each of them has its own types of items which can be kept in the learnpath-child class

Note:
-----
As for the parsing of the imsmanifest.xml file, the difficulties encountered so far with a classical array
structure have led me towards developing a set of classes for each major element of the imsmanifest.xml (see
section 2.3.5 in the CAM documentation). So there is a class for the &lt;organization&gt; tag, a class for
the &lt;item&gt; tag, one for the &lt;metadata&gt; tag (precious to René) and one for the &lt;resource&gt; tag.
I now realise that these classes might be used as well later for the imsmanifest.xml editing. We'll see
what future development give on that side.

Database

The database will be extended with two more tables (the "attempts/views" recording tables) and merged into the courses tables.

In this drawing, "+" means primary key, "#" means foreign key and "-" means everything else. Note that the MySQL server versions supported by Chamilo do not all support integrity constraints and so the foreign keys integrity checks are done inside the Chamilo code instead of inside the database.

The prerequisites will be stored as a string in the lp_item table and parsed at learning path opening (using the AICC scripting rules defined in the SCORM documentation).

This drawing will probably be changing a bit in the following weeks.

[[Image:New_scorm_db.png]]

The lp_type table does not actually exist. lp_types are
  • 1 for Chamilo-type learning paths
  • 2 for SCORM 1.2-type learning paths
  • 3 for AICC-type learning paths
  • 4 for SCORM 2004-type learning paths (not yet implemented)

A max_score row now exists in lp_item_view.

A new table lp_iv_objective has been created to record SCORM objectives

SCORM messages

The basic SCORM signals are given by pair that do the same thing (they only change names): {|
!style="background:#efefef;" | First header !!style="background:#efefef;" | Same function with LMS prefix !!style="background:#efefef;" | What it does...

|- |Initialize || LMSInitialize || Initialises the SCORM object in the e-learning system in JS global scope (the document object) |- | GetValue || LMSGetValue || Gets the value of one of the SCO attributes |- | SetValue || LMSSetValue || Sets the value of one of the SCO attributes |- | Commit || LMSCommit || Calls the e-learning system "save" function to save the SCO attributes into the e-learning database |- | Finish || LMSFinish || Puts an end to the use of the current JS object (the SCO item has been finished) |- | GetLastError || LMSGetLastError || Gets the last error. Conformant (API calls might get error code refining). |- | GetErrorString || LMSGetErrorString || Gets the error string. Conformant. |- | GetDiagnostic || LMSGetDiagnostic || Gets a diagnostic. Not fully conformant yet (lack of support from vendors). |}

The important bit here is the two functions GetValue(x) and SetValue(x,y). Let's analyse the possible 'x' values.
The CMI is the JavaScript object containing volatile information about the opened SCO item.

SCO object properties

The following table is an exhaustive list of SCO object properties as defined by the SCORM 1.2 Runtime Environment official document (published by ADLNet on October 2001).
  • The green lines indicate support for the feature.
  • The white lines indicate lack of support, and only happens for non-mandatory elements, although the right error code is sent to the SCO to indicate that the feature is not implemented.

{|border=1
!style="background:#efefef;" | Color !!style="background:#efefef;" | Meaning |- style="background-color:#77ee77;" | || Fully implemented |- style="background-color:#88aa88;" | || Partially implemented |- style="background-color:#99ff99;" | || Implemented on top of SCORM (extra) |- style="background-color:#ffffff;" | || Not implemented |}

{|border=1
!style="background:#efefef;" | Parameter !!style="background:#efefef;" | Usage !!style="background:#efefef;" | Support for GetValue? !!style="background:#efefef;" | Support for SetValue? |- style="background-color:#77ee77;" | cmi.core._children<br />cmi.core_children || Contains the elements supported by the CMI || static - returns "entry, exit, lesson_status, student_id, student_name, lesson_location, total_time, credit, lesson_mode, score, session_time" as expected || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.core.student_id || The ID of the student viewing the SCO, Chamilo-wise || Dynamic. Gets it from the session variables || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.core.student_name || The full name of the student viewing the SCO || Dynamic. Gets it from the session variables || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.core.lesson_location || The id (or page) of the lesson, in the SCORM package terms || Dynamic. || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.core.credit || Gets the credit attribute for the current SCO || Dynamic. Depends on LP prevent_reinit attribute (icon to change) and current item status || N/A |- style="background-color:#77ee77;" | cmi.core.lesson_status || Status of the current SCO item || Dynamic. Gets it into the SCORM database in Chamilo at first opening, then inside the JavaScript object || Dynamic. When set and commited, it is recorder in the object then in the Chamilo database upon LMSCommit() or LMSFinish() |- style="background-color:#77ee77;" | cmi.core.entry || Tells if the user has been in the SCO before || ab-initio, resume or empty string || N/A. Read Only. |- style="background-color:#99ff99;" | cmi.core.score || Not defined by SCORM 1.2 (additional feature). Gets the score attribute for the current SCO || Dynamic. || N/A. Read-only |- style="background-color:#77ee77;" | cmi.core.score._children || Gets the attributes of the score object children || Static. Returns "raw,min,max" (conformant) || N/A. Read-only |- style="background-color:#77ee77;" | cmi.core.score.raw || Gets the score already granted for the current SCO || Dynamic. Returns the score recorder into the CMI object at the moment, or "0" if none || Dynamic. On commit, writes the value into the database |- style="background-color:#77ee77;" | cmi.core.score.max || Gets the maximum score for the current SCO || Dynamic. || Dynamic. On commit, writes the value into the database. |- style="background-color:#77ee77;" | cmi.core.score.min || Gets the maximum score for the current SCO || Dynamic. || Dynamic. On commit, writes the value into the database. |- style="background-color:#77ee77;" | cmi.core.total_time || The total time spent on this SCO || Dynamic. || Dynamic. On commit, writes the value into the database. |- style="background-color:#77ee77;" | cmi.core.lesson_mode || Gets the lesson mode for the current SCO || Dynamic. Depends on LP prevent_reinit attribute (icon to change) and current item status || N/A. Read-only |- style="background-color:#77ee77;" | cmi.core.exit || Records information on how or why the student has left. Can be anything, set by the SCO || Returns "" + Error code 404. Element write-only || Records the exit string into database on commit. |- style="background-color:#77ee77;" | cmi.core.session_time || Time of spent in the current session of that SCO's use. Added to total_time || Error 401 - Not implemented yet (although could be 404 - write only in the future) || Sums up to total time. |- style="background-color:#77ee77;" | cmi.suspend_data || Gets data stored during the last view of this SCO || Dynamic. || Dynamic. |- style="background-color:#77ee77;" | cmi.launch_data || Uses data given in imsmanifest.xml as datafromlms, adlcp:datafromlms or even launchdata for vendors who do not implement this correctly, at parse time. || Dynamic. || N/A. Read-only |- | cmi.comments || Not implemented/Not mandatory - Lets user give comments through the SCO (has to be dealt with by the SCO) || Error 401 || Error 401 |- | cmi.comments_from_lms || Implemented in 1.8.5 - Lets profesor give comments through the LMS (has to be dealt with by the SCO) || Error 401 || Error 401 |- style="background-color:#77ee77;" | cmi.objectives._children || Implemented in 1.8.5 - Gets the objectives data || Returns 'id,score,status' || N/A. Read-only |- style="background-color:#77ee77;" | cmi.objectives._count || Implemented in 1.8.5 - Gets the number of objectives || Dynamic || N/A. Read-only |- style="background-color:#77ee77;" | cmi.objectives.n.id || Implemented in 1.8.5 - Sets/Gets the objective n's id || Dynamic || Dynamic |- style="background-color:#77ee77;" | cmi.objectives.n.score._children || Implemented in 1.8.5 - Gets the objective n's children (should be raw,max,min) || Returns 'raw,max,min' || N/A. Read-only |- style="background-color:#77ee77;" | cmi.objectives.n.score.raw || Implemented in 1.8.5 - Gets/Sets the objective n's raw score || Dynamic || Dynamic |- style="background-color:#77ee77;" | cmi.objectives.n.score.max || Implemented in 1.8.5 - Gets/Sets the objective n's max score || Dynamic || Dynamic |- style="background-color:#77ee77;" | cmi.objectives.n.score.min || Implemented in 1.8.5 - Gets/Sets the objective n's min score || Dynamic || Dynamic |- style="background-color:#77ee77;" | cmi.objectives.n.status || Implemented in 1.8.5 - Gets/Sets the objective n's status || Dynamic || Dynamic |- style="background-color:#77ee77;" | cmi.student_data._children || Returns the children of the student_data object || Returns 'mastery_score,max_time_allowed' || Error 401 |- style="background-color:#77ee77;" | cmi.student_data.mastery_score || Returns the mastery score for this item, as set by imsmanifest.xml || Dynamic. || N/A. Read only. Error 401 |- style="background-color:#77ee77;" | cmi.student_data.max_time_allowed || Returns the maximum time allowed for this item, as set by imsmanifest.xml || Dynamic. || N/A. Read only. Error 401 |- | cmi.student_data.time_limit_action || Not implemented/Not mandatory. Returns the type of action to be taken on time limit reached for this item, as set by imsmanifest.xml || Not implemented. Error 401 || N/A. Read only. Error 401 |- | cmi.student_preference._children || Not implemented/Not mandatory - Gets the implemented children of the student_preference object || Error 401 || Error 401 |- | cmi.student_preference.audio || Not implemented/Not mandatory - Gets/Sets the audio volume preference for this user || Error 401 || Error 401 |- | cmi.student_preference.language || Not implemented/Not mandatory - Gets/Sets language the preference for this user || Error 401 || Error 401 |- | cmi.student_preference.speed || Not implemented/Not mandatory - Gets/Sets the speed preference for this user || Error 401 || Error 401 |- | cmi.student_preference.text || Not implemented/Not mandatory - Gets/Sets the text/subtitle preference for this user (on/default/off) || Error 401 || Error 401 |- style="background-color:#77ee77;" | cmi.interactions._children || Returns the list of supported children of the interaction object || Returns 'id, time, type, correct_responses, weighting, student_response, result,latency' || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.interactions._count || Returns the current number of records in the interactions list || Dynamic (based on array size in JS) || N/A. Read-only. |- style="background-color:#77ee77;" | cmi.interactions.n.id || Unique identifier for an interaction (string) || N/A. Write-only. || Sets the interaction in the database on commit. |- | cmi.interactions.n.objectives._count || Not implemented/Not mandatory - Returns the number of objectives || Error 401 || Error 401 |- | cmi.interactions.n.objectives.n.id || Not implemented/Not mandatory - Sets objective ID || Error 401 || Error 401 |- style="background-color:#77ee77;" | cmi.interactions.n.time || Time when the interaction was completed || N/A. Write-only. || Sets the interaction completion time in the database on commit. |- style="background-color:#77ee77;" | cmi.interactions.n.type || The interaction type (true-false,choice,fill-in,matching,performance,sequencing,likert,numeric) || N/A. Write-only. || Sets the interaction type in the database on commit. |- | cmi.interactions.n.correct_responses._count || Not implemented/Not mandatory - Returns the supported sub-elements of correct_responses || Error 401 || Error 401 |- | cmi.interactions.n.correct_responses.n.pattern || Not implemented/Not mandatory - Returns pattern for the correct_response || Error 401 || Error 401 |- style="background-color:#88aa88;" | cmi.interactions.n.weighting || Importance of the interaction. Not fully implemented (does not allow calculation based on this value and the result. || N/A. Write-only. || Sets the interaction importance/weight in the database on commit. |- style="background-color:#77ee77;" | cmi.interactions.n.student_response || Actual response of the student. This can be compared to the patterns of correct_responses || N/A. Write-only. || Sets the interaction response in the database on commit. |- style="background-color:#77ee77;" | cmi.interactions.n.result || Actual result from the student's response || N/A. Write-only. || Sets the interaction result in the database on commit. |- style="background-color:#77ee77;" | cmi.interactions.n.latency || Time from the presentation of the interaction to the student's response || N/A. Write-only. || Sets the interaction response time in the database on commit. |}

The elements not supported in the table above are:
  • not used by any of our users nor the common SCORM publishers
  • not necessary to get an excellent user experience
  • not mandatory in light of the SCORM 1.2 specification
  • difficult to implement or unclearly defined

We are adding support for new elements on a regular basis (aprroximately every 4 months) as demand appears but, as of september 2007, we are getting at the end of the demand.

I found that the most mysterious and badly sampled SCORM object properties are certainly cmi.objectives and cmi.interactions. There is a lot of information about their children, but not real example of what it could be used for.

It is quite obvious though, that objectives are the possible steps one might want to setup inside one SCO item (like for example passing one test inside a flash SCO).
It is also obvious that interactions are all the exchanges that can exist between the user and the SCO.

But none of these elements is mandatory, and they are both very laborious to implement in a LMS (because if you use a database system behind it, you will need one additional table for each type). Interactions have quite a lot of possible children as well as objectives children (luckily objectives cannot contain interactions).

Also, I haven't found any information about what happens when someone enters the same SCORM twice. There are two possible cases here. The first one is we don't deal with different "attempts". So the student has only one possible attempt on one SCORM, and if he wants to re-enter the SCORM, he will be able to overwrite his previous results. I cannot believe this would be the suggested way to deal with it.
The second case is that each time you leave the SCORM, you "lock" your results in the LMS memory, and next time you want to come back at it, you open a completely new session. This sounds a bit better, but what about SCORMs that last several hours? Can you really afford to do it in one go?

So I guess the answer is in the middle. The best way to do it would be to allow the user to go through the SCORM and, only if he completes it (and the "completes" bit is to be discussed), lock the SCORM results and only allow a new session next time. If someone knows the answer, please contact me directly (I think my e-mail address should be around here somewhere... yannick at Chamilo dot org)

AICC_script prerequisites

The CAM (Content Aggregation Model) documentation of SCORM 1.2 mentions a very small table about the AICC_script operators but does mention that SCORM packages use it. A very small but complete implementation of a parser for this scripting language has been developed in the learnpath.class.php file to enable Chamilo to deal with prerequisites of this form, be it for SCORM or other learnpath tools in Chamilo.

Later on, this might be improved by using the (freshly discovered) AICC_script interpreter developed in Java (and rewriting it in PHP and making it available as a separate project) [http://sasi.sourceforge.net/ SASI project]

For information, and hopefully not breaking any copyright rules by so doing (SCORM is an open standard after all), here is a very small excerpt of the CAM document for SCORM 1.2 that talks about AICC script.

{|border=1 | Operator || Details |-
! AND '&' | All elements separated by an & must be compete for the expression to be evaluated as complete.
S34 & S36 & S38
SCOs number S34, S36 and S38 must all be complete ("passed" or "completed") for the group to be considered complete. |-
! OR (vertical bar) | If any of the elements separated by an | are complete ("passed" or "completed") the expression is considered true.
S34="passed" | S36="passed" | S38="passed"
If any one of the SCOs, S34, S36, or S38, are passed then the group is considered complete. |-
! NOT ~ | An operator that returns incomplete (false) if the following element or expression is complete, and returns complete (true) if the following element or expression is incomplete (false).
Element Identifier: S34
Requirement: ~S35
The student may enter SCO S34 as long as SCO S35 has not been completed (that is, the status of S35 must be "incomplete", "failed", or "not attempted"). If SCO S35 is complete, the student may not enter SCO S34. |-
! EQUALS = | An operator that returns true when representations on both sides of the symbol have the same values.
Element Identifier: S34
Requirement: S33="passed"
The student may enter SCO S34 if he has passed SCO S33 |-
! NOT EQUALS <> | An operator that returns true when elements on both sides of the symbol have different values.
Element Identifier: S34
Requirement: S35<>"passed"
The student may enter SCO S34 as long as he or she has not passed SCO S35. Notice the difference between this expression and the example for the not operator. The equivalent of ~S35 is (S35<>"passed" & S35<>"completed") |-
! Set {} | A list of learning content elements (SCO or Block) separated by commas and surrounded by curly brackets -- { }. A set differs from a Block, in that the set is defined only for purposes of the prerequisite file. A set has no effect on the structure of the learning content. {S34, S36, S37, S39}
SCOs S34, S36, S37 and S39 are part of a set |-
! Separator ',' | The comma is used to separate the members of a set. Each member of the set can be evaluated as a Boolean element – complete or incomplete. {S34, S36, S37, S39}
SCOs S34, S36, S37 and S39 are each separated by a comma in this set |-
! X* | X is an integer number. This operator means that X or more members of the set that follows must be complete for the expression to be complete (true).
Element Identifier: S38
Requirement: 3*{S34, S36, S37, S39}
Any three or more of the following SCOs – S34, S36, S37, S39 -- must be complete ("passed" or "completed") before the student can enter SCO S38 |-
! Precedence () | The expression inside the parenthesis ( ) must be evaluated before combining its results with other parts of the logical statement. Parentheses may be nested. (Operator precedence is the same as in the C programming language – including the use of parenthesis.)
Element Identifier: S39
Requirement: S34 & S35 | S36
In this statement, completing S36 all by itself enables the student to enter S39.
Element Identifier: S39
Requirement: S34 & (S35 | S36)
Adding the parenthesis, makes it necessary to complete ("passed" or "completed") at least two units (S36 all by itself is no longer enough) to enter unit S39. |}

This full set of prerequisites are now available in the new SCORM tool (still in tests)

SCORM structure (imsmanifest)

It is good to give an idea, in short and simplified, of what an imsmanifest.xml file is made of and why it is mandatory to have one suche file in each SCORM package.

If you think of a written analysis given to you as a stack of sheets, you will have a very hard time to try and get this stack sorted. The same applies to files on a classical file system. While you can order the files by date or by name, it is pretty difficult to create an sequential order that will have to be followed by any person opening your files on a random operating system.

As a table of contents would help you in the first case, a good way to solve the second case is to have a separate file that contains a structured representation of the sequential order you want the user to follow. This structured file will contain the names of the files that need to be loaded, in which order.

Now the imsmanifest.xml file is exactly that. A structured representation of the order you want your students to use when going through the SCORM learning path. But it also contains more, allowing to give additional information on each file (minimum score expected, type of file, keywords, ...) as well as information on the overall learning path.

A typical (simplified) imsmanifest.xml will look like this:

<?xml version="1.0"?>
&lt;manifest identifier="SingleCourseManifest" version="1.1"
xmlns="http://www.imsproject.org/xsd/imscp_rootv1p1p2"
xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_rootv1p2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd
http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd
http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd">
&lt;metadata/&gt;
&lt;organizations default="B0"&gt;
&lt;organization identifier="B0"&gt;
&lt;title&gt;Maritime Navigation&lt;/title&gt;
&lt;item identifier="B100" isvisible="true"&gt;
&lt;title&gt;Inland Rules of the Road (HTML Format)&lt;/title&gt;
&lt;item identifier="S100001" identifierref="R_S100001" isvisible="true"&gt;
&lt;title&gt;References and Lesson Objective&lt;/title&gt;
&lt;/item&gt;
&lt;/item&gt;
&lt;metadata&gt;
&lt;schema&gt;ADL SCORM&lt;/schema&gt;
&lt;schemaversion&gt;1.2&lt;/schemaversion&gt;
&lt;adlcp:location&gt;Course01.xml&lt;/adlcp:location&gt;
&lt;/metadata&gt;
&lt;/organization&gt;
&lt;/organizations&gt;
&lt;resources&gt;
&lt;resource identifier="R_S100001" type="webcontent"
adlcp:scormtype="sco" href="Course01/Lesson01/sco01.htm">
&lt;metadata&gt;
&lt;schema&gt;ADL SCORM&lt;/schema&gt;
&lt;schemaversion&gt;1.2&lt;/schemaversion&gt;
&lt;adlcp:location&gt;Course01/Lesson01/sco01.xml&lt;/adlcp:location&gt;
&lt;/metadata&gt;
&lt;file href="Course01/Lesson01/sco01.htm" /&gt;
&lt;dependency identifierref="R_D1"/&gt;
&lt;/resource&gt;
&lt;/resources&gt;
&lt;/manifest&gt;

You can probably spot quite easily the different major elements:
- manifest
- metadata
- organizations
- organization
- item
- metadata
- resources
- resource
- metadata
- file
- dependency

The last elements (resources) are the ones we will try to keep inside Chamilo.

To parse these imsmanifest.xml files, there are now five SCORM classes in total in the new SCORM tool:
- scorm (the global object),
- scormOrganization (for each organization),
- scormResource (for each resource)
- scormMetadata (for each metadata info - not used at the moment but there for the future)
- scormItem (for each item)

To the exception of scorm and scormItem, these classes are only used for the parsing so far, as a scormOrganization is in fact one learning path (so if we have multiple ones at the moment it might still be hasardous to import such imsmanifest).

Frontend

Note:
This section is no longer valid, as a jump as been made backwards to ensure iframes were actually displaying in the right space we were giving them.
So we've reverted to using frames. This is not an evolution, but a sad reversion to ensure we don't have two scrollbars showing for only one content.

For the SCORM viewing part, the frontend will remain the same in appearance. Code-wise though, it will undergo major changes as everything will be CSS based. No more frames except for an <iframe> to view the content itself, which will allow much more flexibility.

The main window will display the Chamilo header and include the SCORM (or other models) API, which will be more respectful of the SCORM recommandations about having the API in the parent frame (not a sister frame as it is now).

The left column will still be there and contain the table of content [1], the navigation bar [2] and the messaging zone [3]. Thanks to CSS, a designer will have the ability to hide all or part of the left menu, to switch it to the right side, to make it "float" over the rest of the page and even to make it semi-transparent with several browsers (not yet recommended as IE6 doesn't handle well enough images transparency).

The (SCORM) learning path edition frontends will be developped by graphic designers to enable easy management of your resources (design to be disclosed).

The messages sequencing problem

This problem has now been overcome and is only mentioned here for historical reasons

A massive problem now appears in the development of the Chamilo SCORM tool. It is what we decided to call the sequencing problem. When playing with frames (being <frameset> or <iframe> tags equally), and a lot of JavaScript, we quickly fall over a problem of playing with a two-levels application.

The PHP code is only server-side, while the JavaScript code is only client-side.

The frames structure implies an asynchronous messaging process, where one action triggered in the browser in turn triggers a JavaScript message that triggers a frame refresh.
JavaScript messages can happen (and should, for the well-being of the visual interface) at the same time on several frames. This means that when a page is complete, a message is sent to the Table Of Contents frame to update the small green tick (only JavaScript), another is sent to an invisible frame that saves the data to the database (JavaScript followed by PHP) and yet another one queries the database to see which element is next (navigation bar updates - JavaScript followed by PHP). Another message is sent to a frame to refresh the content of the current content frame, so that it goes to the next element (JavaScript followed by PHP).

This sounds all very nice. The problem is that, in order to do that, you need order, or sequencing, so that a JavaScript message doesn't update the database after the new data has been checked out to display the updated frames. This is where things become complicated.

In order to do such sequencing, we need to have one static, centralized peace of JavaScript that will get a message and send it to the server before any other messages is processed.

This is the current blocking step in the development of this new tool. More info later...

The easiest and cleanest way to overcome that issue would probably to use AJAX, but so far the tools we analysed to deal with AJAX don't overcome properly their own problem with IE<7 where ActiveX need to be activated to actually have it working.
With XAJAX, the operation would probably be limited to using the right design pattern to sequence the JavaScript calls. Plans are that XAJAX will have overcome this issue in version 0.5, which is not yet scheduled.

Another way is to design design-patterns directly in a JavaScript library but we are short on skills to do it properly.

How others do it

In the process of implementing the new SCORM tool in Chamilo, I have had a look at other open-source e-learning systems and how they deal with SCORM (namely Moodle and Ganesha). It comes out of this analysis that both of them use a one page per document system, where when you switch from one document to another, you expressely refresh the page.
This has the advantage of simplifying the whole process extremely, as a page refresh can be used to refresh the SCORM API, thus allowing all the attributes of the API object to be refreshed at once. This means that you don't have to bother about replacing values in your API object to reflect the change of document. The new page loads the new document together with the API, and the API is then adapted to the only document on the page.

The saving process is done by using the XML requests capabilities of JavaScript, but not completely, so it works basically in the same way the Chamilo saving process works, by loading a different script with parameters about the current SCO document to save.

The main difference with Chamilo is that we want the user to feel a maximum in desktop-like environment, meaning he doesn't have to wait for the whole page to refresh before he can actually see the next document and move over. When he clicks on a link to change the document, the central frame where the document shows is replaced by the new document, and the whole API object is refreshed (not reloaded) so that it is ready with clean and accurate information for that new SCO document.
This has brought a lot of difficulties on my shoulders, as it appears the JavaScript API object is not that easy to refresh, meaning that I had to use AJAX, which itself caused a lot of problems (the xajax library we use having some difficulties dealing with multiple frames in very specific conditions).

The current state in Chamilo

We are using AJAX (and more precisely the AJAX PHP library xajax) and it turned out to work very nicely.

For the record, this is what I wrote about a month earlier. It is not correct anymore, but the process is more or less the same.

An important thing to note before reading the following: some SCORM content only authorize the SCORM API (on the LMS side) to be located in the top frame or top window.  
This means that the API cannot be changed in place by just reloading a specific SCORM-API frame and leaving the main frame untouched.

Currently, we have:

- The first loading and display is perfect, everything is initialised from the system database, so no possible problem

- The user clicks on a link (be it a navigation icon or the links in the toc) and triggers a call to a new document

- Chamilo saves the current data if the content is not SCORM or is an asset. If the content is SCORM, changing (unloading the current) document will trigger an LMSCommit() call, or should.

- Chamilo gets the new document data into the API object (refreshes all the object attributes at once) and saves the old ones to enable the next SCORM LMSCommit() to be processed normally (read on...). This HAS TO use AJAX functionalities, as the API object needs to be updated in place.

- Chamilo swaps the document in the document frame (at which point the SCORM API in the current document should trigger an LMSCommit(), which will then check a flag saying if the data should be taken from the new attributes or the old ones)

- Chamilo refreshes the table of content using AJAX to tick green the completed elements

- Chamilo refreshes the navigation bar using AJAX to update the progress bar

- Chamilo refreshed the message frame using AJAX

AICC

AICC compatibility is scheduled for mid-october in development release.

Although AICC includes a different way of dealing with requests, it is pretty much similar to SCORM in the type of data exchanged between the content and the LMS (Chamilo).

In Chamilo 1.8, AICC will only be supported at the mandatory scale, which means only mandatory messages will be implemented. However, more of the AICC messages set could be easily added with additional time, to use all the data already stored for SCORM in the Chamilo database.

AICC defines several norms. The only one that applies in the Chamilo case is the CMI (Computer Managed Instruction) subset. We decided to go for CMI version 4, which is the latest version to date.

Parsing AICC packages

The rules for AICC packages are defined in section 8 of the [http://www.aicc.org/docs/tech/cmi001v4.pdf "AICC CMIv4 documentation"].
Basically, 4 to 7 different files have to be present in the same directory. These files are formatted using the "ini file" format (can possibly be parsed by parse_ini_file() PHP function), others are CSV-like files, so the parsing is quite easy.

Some data that is found in these files cannot yet be stored in the Chamilo database structure, so some data will be kept inside these files, but we will keep a reference to them in order to parse them later if necessary.

Bindings
AICC is divided into three main access methods, called "bindings" in [http://www.aicc.org/docs/tech/cmi001v4.pdf "AICC CMIv4 documentation"] : file, HACP and API.

''File''

The file binding isn't applied in our case, as it concerns simple file management, not implying any web server.

''HACP''

HACP (stands for "HTTP/S based AICC/CMI Protocol" and) is the HTTP-based communication protocol/access method that allows a content to communicate with the Chamilo LMS. Basically, it sends requests to the LMS to a specific script, giving all the parameters via the POST or GET methods.

''API''

API is pretty similar to the SCORM API. It is actually so similar that we are going to re-use the scormfunctions library to enable this mode. The content thus interacts with the Chamilo LMS by sending JavaScript calls to a global JavaScript object declared in the main frame in Chamilo. These calls are then managed by XAJAX to update the server's database according to the user's progression.

Supported AICC CMI messages in Chamilo 1.8 NewSCORM tool (AICC/CMI Communication Data Model)

{|border=1
!style="background:#efefef;" | HACP Parameter name (case insensitive) !!style="background:#efefef;" | HACP obligations !!style="background:#efefef;" | API Parameter name !!style="background:#efefef;" | API obligations |- | Student_ID || GetParam() || cmi.core.student_id || LMSGetValue() |- | Student_Name || GetParam() || cmi.core.student_name || LMSGetValue() |- | Lesson_Location || GetParam(), PutParam() || cmi.core.lesson_location || LMSGetValue(), LMSSetValue() |- | Credit || GetParam() || cmi.core.credit || LMSGetValue() |- | Lesson_Status || GetParam(), PutParam() || cmi.core.lesson_status || LMSGetValue(), LMSSetValue() |- | Exit /appended to Lesson_Status/ || PutParam() || cmi.core.exit || LMSSetValue() |- | Entry /appended to Lesson_Status/ || GetParam() || cmi.core.entry || LMSGetValue() |- | Score (=raw[,max[,min]]) || GetParam(), PutParam() || cmi.core.score.raw (,.max,.min) || LMSGetValue(), LMSSetValue() |- | Time || PutParam() || cmi.core.session_time || LMSSetValue() |- | Time || GetParam() || cmi.core.total_time || LMSGetValue() |- | Lesson_Mode || GetParam() || cmi.core.lesson_mode || LMSGetValue() |- | [Core_Lesson] || GetParam(), PutParam() || cmi.suspend_data || LMSGetValue(), LMSSetValue() |- | [Core_Vendor] || GetParam() || cmi.launch_data || LMSGetValue() |}

Supported AICC CMI course information in Chamilo 1.8 NewSCORM tool (AICC/CMI Course Structure Data Model)

We are considering making Chamilo temporarily handle level 3a of this Data Model as we have already a built-in AICC prerequisites parser included in the development of the SCORM 1.2 specification. As objectives and interactions should be included soon, we might even get up to level 3!!

{|border=1
!style="background:#efefef;" | Parameter !!style="background:#efefef;" | Obligations !!style="background:#efefef;" | Sent via... |- | Course.Creator || pending... || - |- | Course.ID || pending... || Get (Evaluation.Course_ID) |- | Course.System || pending... || - |- | Course.Title || pending... || - |- | Course.Level || pending... || - (LMS info message if not supported) |- | Course.Max Fields CST || pending... || - |- | Course.Max Fields ORT|| (not mandatory) pending... || - |- | Course.Total AUs || pending... || - |- | Course.Total Blocks || pending... || - |- | Course.Total Objectives || pending... || - |- | Course.Total Complex Objectives || pending... || - |- | Course.Version || pending... || - |- | Course Behavior || pending... || - |- | Course Behavior.Max Normal || pending... || When exceeded, Get(core.credit) returns "no-credit" and then lesson_mode is "Browse" |- | Course Description || pending... || - |- | Course Elements || pending... || - |- | Course Elements.System ID || pending... || - (must be unique to the LMS)(course_code.lp_id?) |- | Course Elements.Developer ID || pending... || Get(Evaluation.Lesson_ID or Objectives.ID) |- | Course Elements.Title || pending... || - (use for TOC/stats?) |- | Course Elements.Description|| pending... || - (use in stats?) |- | Course Elements.Type || pending... || ? |- | Course Elements.File Name || pending... || - (entry point URL) |- | Course Elements.Mastery Score || pending... || Get(Student Data.Mastery Score) |- | Course Elements.Max Score|| pending... || Substitute to core.score.max if not exists |- | Course Elements.Max Time Allowed || pending... || Get(Student Data.Max Time Allowed) |- | Course Elements.Time Limit Action|| pending... ||Get(Student Data.Time Limit Action) |- | Course Elements.Development System || pending... || - |- | Course Elements.Launch Data || pending... || core.launch_data |- | Course Elements.Web Launch Parameters || pending... || appended at end of URL |- | Course Elements.AU Password || pending... || check HACP request for password and send error message if wrong |- | Course Elements.Members || pending... || - helps determine status of whole course |- | Course Elements.Members.System ID || pending... || special |- | Course Elements.Prerequisite || pending... || special |- | Course Elements.Completions || pending... || special |- | Course Elements.Completions.Requirement || pending... || special |- | Course Elements.Completions.Status if True || pending... || special |- | Course Elements.Completions.Next AU if True || pending... || special |- | Course Elements.Completions.Goto after Next || pending... || special |}

Dumb Content

AICC defines "Dumb Content" as elements of an AICC package that do not conform to tracking communications, i.e, pages that do not send any message to the LMS. The AICC guidelines mention this is left to the LMS to decide. In Chamilo, these Dumb Contents will be dealt with as if they were SCORM "Assets", i.e. they will be set as completed as soon as opened, and the time will be tracked to the best possible accuracy by looking for the "onclose" JavaScript event.

Chamilo tests scoring integration

In the tons of things that have to be thought about, the revamp of the SCORM tool also brought the problem of the exercises score reporting back into the newscorm tool. If a test is linked from the newscorm tool, the score you achieve by taking it should be reported into the new lp tables.

The old way of doing it was to use a special script, claroline/exercice/savescores.php, which would directly write data into the database. Of course, a better a way of doing it would be, now, to send a javascript message to the newscorm tool, just like SCORM contents do, in order to update the score. However, as a first step, the only thing done has been to update the savescores.php script to accept one additional parameter (taken from the session) to know the view we are in, so that it involves minimum changes for like-before efficiency.

After a few minutes of writing this I realised things were not that simple. savescores.php is actually only used with HotPotatoes tests. A change has to be made to exercice/exercise_result.php to update the lp_item_view table. This works, but something keeps overwriting the change.

Coming soon

SCORM 2004

SCORM 2004 compatibility is scheduled for mid-november and might add yet other database structure alterations.

Migration process

A migration script is available (and activated on campus updates) to move all the existing learning paths and SCORM paths to the new database structure safely and without any additional worries.

As this is a technical article, I should also mention that all SCORM learning paths need to have their imsmanifest.xml files re-parsed in order to get all the important data into the new tables.

For example, the 1.6.* way of keeping a pointer to a SCO resource is to keep its SCORM ID (as defined in imsmanifest.xml) into the DB table. As such, it prevents Chamilo to directly access the file in the SCORM directory and forces it to re-read imsmanifest.xml each time to get the correspondance between the SCO ID and the physical file.

Keeping a strict synchronisation between the imsmanifest.xml file and the data in the database allow us to have a editable imsmanifest.xml and keep the SCORM learnpath exportable at any time.

Updated by Yannick Warnier over 8 years ago · 1 revisions