SCORM tool redesign

From Dokeos

Jump to: navigation, search

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 Dokeos system. This is all available in Dokeos 1.8 CVS at the moment but not completely clean 
and complete yet.

Contents

Introduction

This page is attempted as a complete study of the SCORM tool in Dokeos, including its history. It will probably be a great helper in the exchanges concerning the new SCORM tool (planned for Dokeos 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 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 Dokeos, a "learning path". It describes the structure of an imsmanifest.xml file, meta-data and the overall packaging of a SCORM resource.

SCORM for Dokeos 1.6

The SCORM tool in Dokeos 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 Dokeos, 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 Dokeos 1.8" section below).

Code 1.6

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

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

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 Dokeos 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 Dokeos (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 Dokeos 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 Dokeos 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 Dokeos 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 Dokeos 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 Dokeos 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 (Dokeos 1.6)

The Dokeos 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):

First header Same function with LMS prefix 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.

Parameter Usage Support for GetValue? Support for SetValue?
cmi.core._children
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 Dokeos Dynamic. When set and commited, it is recorder in the Dokeos database
cmi.core.student_id The ID of the student viewing the SCO, Dokeos-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 Dokeos 1.8

The new SCORM tool aims are:

  • Be much more compatible with SCORM thus allowing more courses sources to work in Dokeos
    • 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 Dokeos learnpaths
    • Extend the Dokeos 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 dokeosLearnpath, dokeosLPItem, scormLearnpath and scormLPItem would inherit from these classes and thus only add the necessary specialised code for Dokeos 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.

Some initial code documentation can be found here.

Classes hierarchy

The following schema represents a draft of the class structure as it will be. For the new tool, only the Dokeos 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 <organization> tag, a class for 
the <item> tag, one for the <metadata> tag (precious to René) and one for the <resource> 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 Dokeos do not all support integrity constraints and so the foreign keys integrity checks are done inside the Dokeos 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 Dokeos-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):

First header Same function with LMS prefix 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.
Color Meaning
Fully implemented
Partially implemented
Implemented on top of SCORM (extra)
Not implemented


Parameter Usage Support for GetValue? Support for SetValue?
cmi.core._children
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.
cmi.core.student_id The ID of the student viewing the SCO, Dokeos-wise Dynamic. Gets it from the session variables N/A. Read-only.
cmi.core.student_name The full name of the student viewing the SCO Dynamic. Gets it from the session variables N/A. Read-only.
cmi.core.lesson_location The id (or page) of the lesson, in the SCORM package terms Dynamic. N/A. Read-only.
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
cmi.core.lesson_status Status of the current SCO item Dynamic. Gets it into the SCORM database in Dokeos at first opening, then inside the JavaScript object Dynamic. When set and commited, it is recorder in the object then in the Dokeos database upon LMSCommit() or LMSFinish()
cmi.core.entry Tells if the user has been in the SCO before ab-initio, resume or empty string N/A. Read Only.
cmi.core.score Not defined by SCORM 1.2 (additional feature). Gets the score attribute for the current SCO Dynamic. N/A. Read-only
cmi.core.score._children Gets the attributes of the score object children Static. Returns "raw,min,max" (conformant) N/A. Read-only
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
cmi.core.score.max Gets the maximum score for the current SCO Dynamic. Dynamic. On commit, writes the value into the database.
cmi.core.score.min Gets the maximum score for the current SCO Dynamic. Dynamic. On commit, writes the value into the database.
cmi.core.total_time The total time spent on this SCO Dynamic. Dynamic. On commit, writes the value into the database.
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
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.
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.
cmi.suspend_data Gets data stored during the last view of this SCO Dynamic. Dynamic.
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
cmi.objectives._children Implemented in 1.8.5 - Gets the objectives data Returns 'id,score,status' N/A. Read-only
cmi.objectives._count Implemented in 1.8.5 - Gets the number of objectives Dynamic N/A. Read-only
cmi.objectives.n.id Implemented in 1.8.5 - Sets/Gets the objective n's id Dynamic Dynamic
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
cmi.objectives.n.score.raw Implemented in 1.8.5 - Gets/Sets the objective n's raw score Dynamic Dynamic
cmi.objectives.n.score.max Implemented in 1.8.5 - Gets/Sets the objective n's max score Dynamic Dynamic
cmi.objectives.n.score.min Implemented in 1.8.5 - Gets/Sets the objective n's min score Dynamic Dynamic
cmi.objectives.n.status Implemented in 1.8.5 - Gets/Sets the objective n's status Dynamic Dynamic
cmi.student_data._children Returns the children of the student_data object Returns 'mastery_score,max_time_allowed' Error 401
cmi.student_data.mastery_score Returns the mastery score for this item, as set by imsmanifest.xml Dynamic. N/A. Read only. Error 401
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
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.
cmi.interactions._count Returns the current number of records in the interactions list Dynamic (based on array size in JS) N/A. Read-only.
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
cmi.interactions.n.time Time when the interaction was completed N/A. Write-only. Sets the interaction completion time in the database on commit.
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
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.
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.
cmi.interactions.n.result Actual result from the student's response N/A. Write-only. Sets the interaction result in the database on commit.
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 dot warnier at dokeos dotcom)

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 Dokeos to deal with prerequisites of this form, be it for SCORM or other learnpath tools in Dokeos.

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) 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.

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) 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"?>
 <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">
  <metadata/>
  <organizations default="B0">
     <organization identifier="B0"> 
        <title>Maritime Navigation</title>
        <item identifier="B100" isvisible="true">
           <title>Inland Rules of the Road (HTML Format)</title>
           <item identifier="S100001" identifierref="R_S100001" isvisible="true">
              <title>References and Lesson Objective</title>
           </item>
        </item>
        <metadata>
           <schema>ADL SCORM</schema>
           <schemaversion>1.2</schemaversion>
           <adlcp:location>Course01.xml</adlcp:location>
        </metadata>
     </organization>
  </organizations>
  <resources>
     <resource identifier="R_S100001" type="webcontent"
               adlcp:scormtype="sco" href="Course01/Lesson01/sco01.htm">
        <metadata>
           <schema>ADL SCORM</schema>
           <schemaversion>1.2</schemaversion>
           <adlcp:location>Course01/Lesson01/sco01.xml</adlcp:location>
        </metadata>
        <file href="Course01/Lesson01/sco01.htm" />
        <dependency identifierref="R_D1"/>
     </resource>
  </resources>
 </manifest>

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 Dokeos.

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 Dokeos 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 Dokeos 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 Dokeos, 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 Dokeos saving process works, by loading a different script with parameters about the current SCO document to save.

The main difference with Dokeos 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 Dokeos

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

- Dokeos 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.

- Dokeos 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.

- Dokeos 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)

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

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

- Dokeos 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 (Dokeos).

In Dokeos 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 Dokeos database.

AICC defines several norms. The only one that applies in the Dokeos 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 "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 Dokeos 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 "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 Dokeos 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 Dokeos LMS by sending JavaScript calls to a global JavaScript object declared in the main frame in Dokeos. These calls are then managed by XAJAX to update the server's database according to the user's progression.

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

HACP Parameter name (case insensitive) HACP obligations API Parameter name 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 Dokeos 1.8 NewSCORM tool (AICC/CMI Course Structure Data Model)

We are considering making Dokeos 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!!

Parameter Obligations 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 Dokeos, 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.

Dokeos 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 Dokeos 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.

Personal tools