scorm to cmi5 - scorm xapi experience api elearning experts · the auth token is what you’re...

64
? SCORM to cmi5 An Implementor’s Guide

Upload: others

Post on 22-Aug-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

?

SCORM to cmi5An Implementor’s Guide

Page 2: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Bits To Convert

Manifest: What’s inside?Launch: Make it go!Runtime: Tell me about it!

What does the SCORM standard cover: Packaging (the ZIP file), Manifests (the loading instructions) and Runtime (the SCORM commands). The ZIP file is the same, so to convert from SCORM to cmi5, we have to map the manifests, change the launch mechanism, and rewrite the runtime commands. That doesn’t sound so bad, does it?

Page 3: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

What’s a Manifest?

✴ Central component of content package

✴ Describes structure of material

✴ Indicates launchable components

✴ XML file

SCORM manifests answer the “where” part of e-learning packages. Where is my content segmented, where are the startup files located, where do I send the user to? If you’re familiar with SCORM 2004 manifest, with their fancy sequencing and navigation, that bottle of Jaeger probably looks pretty appealing right now. S&N is hard!

Page 4: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Manifest Comparisons

SCORM cmi5

Filename imsmanifest.xml cmi5.xml

Activity Tree SCO AU

Activities Activity Leaf Node AU

Containers in the Tree Aggregation Block

SCO = Sharable Content ObjectAU = Assignable Unit

Looking at how cmi5 stacks up, it has a pretty similar organization as SCORM does. Blocks are the containing elements that make up the navigation tree, and AUs are the leaf nodes that are launchable like SCORM SCOs.

Page 5: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM 1.2 Manifest<?xml version="1.0" encoding="utf-8"?> <manifest identifier="_62yRKuq1asJ_course_id" version="1.0"> <metadata> <schema>ADL SCORM</schema> <schemaversion>1.2</schemaversion> </metadata> <organizations default="Simple_SCORM_Packager_Tutorial_ORG"> <organization identifier="Simple_SCORM_Packager_Tutorial_ORG"> <title>Simple SCORM Packager Tutorial</title> <item identifier="Simple_SCORM_Packager_Tutorial_SCO" isvisible="true" identifierref="__62yRKuq1asJ_course_id_RES"> <title>Simple SCORM Packager Tutorial</title> </item> </organization> </organizations> <resources> <resource identifier="__62yRKuq1asJ_course_id_RES" type="webcontent" href="index_lms.html" adlcp:scormtype="sco"> <file href="story_content/thumbnail.jpg"/> </resource> </resources> </manifest>

SCORM manifests have a few identifiable bits. The metadata block can tell us about which version of SCORM this is, the organizations for the clickable navigation tree in the LMS, and the resources for what it launches. So let’s overlay this onto a cmi5 XML file…

Page 6: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Convert to cmi5!

<?xml version="1.0" encoding="utf-8"?> <manifest identifier="_62yRKuq1asJ_course_id" version="1.0"> <metadata> <schema>ADL SCORM</schema> <schemaversion>1.2</schemaversion> </metadata> <organizations default="Simple_SCORM_Packager_Tutorial_ORG"> <organization identifier="Simple_SCORM_Packager_Tutorial_ORG"> <title>Simple SCORM Packager Tutorial</title> <item identifier="Simple_SCORM_Packager_Tutorial_SCO" isvisible="true" identifierref="__62yRKuq1asJ_course_id_RES"> <title>Simple SCORM Packager Tutorial</title> </item> </organization> </organizations> <resources> <resource identifier="__62yRKuq1asJ_course_id_RES" type="webcontent" href="index_lms.html" adlcp:scormtype="sco"> <file href="story_content/thumbnail.jpg"/> </resource> </resources> </manifest>

<?xml version="1.0" encoding="utf-8"?> <courseStructure xmlns="https://w3id.org/xapi/profiles/cmi5/v1/CourseStructure.xsd"> <course id="http://jcasolutions.com/courses/_62yRKuq1asJ_course_id"> <title> <langstring lang="en-US">Simple SCORM Packager Tutorial</langstring> </title> <description> <langstring lang="en-US">Simple SCORM Packager Tutorial</langstring> </description> </course> <au id="http://jcasolutions.com/courses/_62yRKuq1asJ_course_id/activity1"> <title> <langstring lang="en-US">Simple SCORM Packager Tutorial</langstring> </title> <description> <langstring lang="en-US">Simple SCORM Packager Tutorial</langstring> </description> <url>index_lms.html</url> </au> </courseStructure>

SCORM cmi5

cmi5 looks really similar, right? This single SCO example maps on pretty easily, with the top of the navigation tree in SCORM (the red box) becoming a Course Block in cmi5. The leaf node becomes an AU (the blue box), and the resource that maps to that leaf node becomes a <url> tag in the AU (the green box). Arguably, the cmi5 structure is more sensical, as it’s somewhat uncommon for SCO resources to be reused, and the amount of retyping is negligible.

Page 7: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Mastery score

✴ SCORM 1.2: <adlcp:masteryscore>100</adlcp:masteryscore> 

✴ SCORM 2004:<imsss:minNormalizedMeasure>0.6</imsss:minNormalizedMeasure> 

✴ cmi5:<au … masteryScore=“1.0">

Other Things To Convert

Mastery score is a common gotcha of SCORM; we hear regular confusion from customers about courses doing unexpected things when it’s in there. Good news, it’s been kept in cmi5!

Page 8: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Per-SCO/AU Parameters

✴ SCORM 1.2 and 2004: <item parameters=“a=1&b=2”>or <resource href=“...?a=1&b=2”>

✴ cmi5:<au> <launchParameters>{'a':1,'b':2}</launchParameters></au>

Other Things To Convert

cmi5 took a slight step forward and a slight step back on parameter management. Good news, no more query strings and worrying about when it gets escaped. Bad news, now you’re writing JSON, and LMSes are still going to make bad decisions about when to escape query strings. It’s also a slight limitation of the HTTP standard, because parameters are repeatable, but most JSON implementations don’t let you use the same key twice in an object. But it’s legal, I promise! Don’t do it.

Page 9: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Impedance Mismatch

Things there aren’t equivalents for:

✴ SCORM 1.2: None

✴ SCORM 2004:

✴ Sequencing

✴ Most parts of rollup

✴ “moveOn” or bust

Bad news for you die-hard SCORM 2004 folks: most of the things that SCORM 2004 brought to the manifest portion of the standard, there isn’t an option to move it forward. You’re going to have to simplify that logic somewhat significantly. For rollup, there’s a very simple “moveOn” command that you can specify passed or completed logic against, but there’s no way to have other AUs require them as prerequisites. It’s only good for other learning objects in your LMS, or if your LMS goes above and beyond the call of duty and adds flow support within a single cmi5 package.

Page 10: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Launch!

Page 11: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

LMS Responsibilities

✴ Lots!

AU (your content’s) Responsibilities

✴ Get your auth token

✴ Only get it once!

Get the Launch Data

Launch

In SCORM, launching is wholly the LMS’s responsibility. In cmi5, it’s almost wholly the LMS’s responsibility. Your task is to get the data the course needs to know in order to make valid cmi5 statements later on, and handle some simple exit behavior.

Page 12: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Query parameters

✴ actor

✴ activityId

✴ endpoint

✴ fetch

✴ registration

Launch URL

These are the only 5 parameters that your AU has to care about, besides the ones you might use yourself. They’ll look something like…

Page 13: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

http://www.enfixlp.com/ssptutorial/index_lms.html?endpoint=http://enfixlp.com/xapip/base/&fetch=http://enfixlp.com/xapip/authtoken?k=2390289x0&actor={"objectType":"Agent","account":{"homePage":“http://enfixlp.com","name":"gav"}&registration=760e3480-ba55-4991-94b0-01820dbd23a2&activityId=http://jcasolutions.com/courses/_62yRKuq1asJ

Launch URL

…this, in practice. This URL has them already decoded, what you see in your browser’s Location bar might not be so friendly to read. Let’s break it apart.

Page 14: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Launch URL Breakdown

http://www.enfixlp.com/ssptutorial/index_lms.html?endpoint=http://enfixlp.com/xapip/base/

&fetch=http://enfixlp.com/xapip/authtoken?k=2f39028d9

&actor={"objectType":"Agent","account":{"homePage":“http://enfixlp.com","name":“gav"}

&registration=760e3480-ba55-4991-94b0-01820dbd23a2

&activityId=http://jcasolutions.com/_62yRKuq1asJ

LRS URL

Auth URL

Learner

Registration ID in LMS

Course Activity ID

The LRS URL is the base path where your LMS commands will go. Statements will be written to that URL plus /statements will be appended on. The Auth URL is where your content can get any information you use to identify yourself to the LRS later on. The actor is the current learner. The registration is how the LMS keeps straight exactly which attempt this is, for which learner, for which course. The activity ID is the AU’s representation of what course you’re in.

Page 15: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

HTTP POST to “fetch” URLEx: http://enfixlp.com/xapip/authtoken?k=2f39028d9

JSON response with token: {

"auth-token": “QWxhZGRpbjpvcGVuIHNlc2FtZQ==" }

Don’t call it again! {

"error-code": "1", "error-text": "The authorization token has already been returned." }

Getting the Auth Token

The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it once, and you get it only once. You’ll tuck this into the Basic Authentication HTTP header of your xAPI library of choice.

Page 16: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

LMS-provided

✴ Describes context information for student launch

✴ Defines custom launch parameters

✴ Tells course where to go after completion

Stored as an xAPI Activity State

✴ Looked up by:

✴ activityId: The AU ID

✴ agent: The agent from the Launch URL

✴ registration: The registration from the Launch URL

✴ stateId: “LMS.LaunchData”

Launch Data

Launch data is what has all the bits that we need to do make the course run per the limitations of the cmi5 standard. It’s stored as a standard xAPI state.

Page 17: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

{ "contextTemplate": { "contextActivities": { "grouping": [ { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } ] }, "extensions": { "https://w3id.org/xapi/cmi5/context/extensions/sessionid": "3738c07f-e8f2-46df-8d9e-11ccda3a191c" } }, "launchMode": "Normal", "returnURL": "http://enfixlp.com/courses/", "launchMethod": "AnyWindow", "launchParameters": "Start=1&FastForward=On", "entitlementKey": {"courseStructure": "xyz-123-9999", "alternate": "abc-456-1111"}, "moveOn": "CompletedOrPassed" }

Launch Data

Inside, we have the contextTemplate, which you’re going to see a lot of shortly in your cmi5 statements. The launchMethod tells the AU how to display the content, and the launchParameters what the content was opened as.

Page 18: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Runtime

So now it’s time for the hard part! The SCORM runtime is where all the heavy lifting is.

Page 19: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM Runtime Environment Commands

SCORM 1.2 SCORM 2004

LMSInitialize(“”) Initialize(“”)

LMSSetValue(key, value) SetValue(key, value)

LMSGetValue(key) GetValue(key)

LMSFinish(“”) Terminate(“”)

Familiar commands from a familiar spec. These are the primary commands that you’ll have to replace with cmi5-equivalent operations.

Page 20: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Theoretically, any Internationalized Resource Identifier (IRI)

In practice: Usually known, well-defined verbs in IRI form

For this talk, verbs defined in the SCORM xAPI Profile:

✴ initialized

✴ terminated

✴ scored

✴ completed

✴ etc.

xAPI Verbs

Verbs communicate the action and intention of the statement.

Page 21: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Runtime, Compared

SCORM 1.2 SCORM 2004 xAPI / cmi5 verbs

LMSInitialize(“”) Initialize(“”) “initialized”

LMSSetValue(key, value)

SetValue(key, value)

(Mapped by key,HTTP POST/PUT)

LMSGetValue(key) GetValue(key) (Mapped by key,HTTP GET)

LMSFinish(“”) Terminate(“”) “terminated”

So when we throw cmi5 into the mix, here’s the rough equivalent statement mapping for those SCORM functions.

Page 22: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

A cmi5 Session, Briefly

Step Number Action

Prequel Course is launched; launch data is gathered

0 Session opens: “initialized”

1 to (N-1) <One or more xAPI statements>

N Session closes: “terminated”

The cmi5 session represents the valid time in which we can send Statements during the learner experience.

Page 23: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Simple, just use the initialized verb

http://adlnet.gov/expapi/verbs/initialized

Let’s try it!

Initialized

How hard could this be?

Page 24: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

{ "actor": { "objectType": "Agent", "name": "George Vilches", "account": { "homePage": "https://enfixlp.com/", "name": "gav" } }, "verb": { "id": "http://adlnet.gov/expapi/verbs/initialized", "display": { "en": "initialized" } }, "object": { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } }

Initialized

Here’s the new statement, you can see the initialized bit. Let’s send it to the LRS.

Page 25: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Uh oh…

Every one of you will be familiar with this screen soon enough. Chrome’s debugging panel is a gem.

Page 26: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Uh oh…

Valid xAPI != Valid cmi5

So maybe it’s not that simple. What was definitely a valid xAPI statement, is not a valid cmi5 statement.

Page 27: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

“cmi5 defined”

✴ Known quantities

“cmi5 allowed”

✴ Fits within the session

“cmi5 not-allowed”

✴ Everything else

cmi5 Statements

cmi5 defined is where all the critical bits are at. Everything else is just squeezing in and around that primary workflow (or rejected outright from it).

Page 28: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

“cmi5 defined”

Defined in the cmi5 xAPI Profile

“context” requires several parts

✴ LMS.LaunchData

✴ “contextTemplate”

✴ Include everything in every statement.

✴ Must have cmi5 category activity

✴ “id”: "https://w3id.org/xapi/cmi5/context/categories/cmi5"

{ "contextTemplate": { "contextActivities": { "grouping": [ { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } ] }, "extensions": { "https://w3id.org/xapi/cmi5/context/extensions/sessionid": "3738c07f-e8f2-46df-8d9e-11ccda3a191c" } },

cmi5 defined is a very strict set of rules for formatting xAPI statements, and you have to add in a bunch of extra parts for each type of statement. The contextTemplate has to be in there from the Launch Data, as well as a few activities.

Page 29: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Actor

✴ Must be objectType: “Agent”

✴ Must be “account” type

Limited verb choices

“id” required

“timestamp” required

“cmi5 defined” (cont’d)

Actors in xAPI can usually be all sorts of things, like Groups of people or e-mail addresses. cmi5 says they can only be the homepage and name pairing, under account. Statements also require an “id” even if you’re using the POST endpoint that wouldn’t require them. Same with timestamp.

Page 30: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Only usable within the session

✴ Between initialized and terminated

All other valid xAPI statements

“id” still required

“timestamp” still required

Recommended: xAPI SCORM Profile

“cmi5 allowed”

All the other things that can be done with xAPI that don’t conflict with the other cmi5 rules (like multiple passed/failed statements) can be done here, so long as you put the id and timestamp on the statement, and you do them within the initialized and terminated blocks. Let’s try initializing things again.

Page 31: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

{ "id": "6f8e1135-c9fe-4e02-ae1f-a0f7468745eb", "actor": { "objectType": "Agent", "name": "George Vilches", "account": { "homePage": "https://enfixlp.com/", "name": "gav" } }, "verb": { "id": "http://adlnet.gov/expapi/verbs/initialized", "display": { "en": "initialized" } }, "object": { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } }, "context": { "registration": "4eb0e063-669b-479a-86b3-f9be9ac88a1d",

"contextActivities": { "grouping": [ { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } ], "category": [ { "objectType": "Activity", "id": "https://w3id.org/xapi/cmi5/context/categories/cmi5" } ] }, "extensions": { "https://w3id.org/xapi/cmi5/context/extensions/sessionid": "c7b6f0a9-482c-4c03-acc1-548289126963" } }, "timestamp": "2016-06-09T15:34:26.887Z" }

Initialized, Take 2

Red = cmi5 required components

So here’s all the new bits! The context has all the additional components from LaunchData, and the new required bits.

Page 32: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

User Statuses

Passed / Failed: exactly one, exactly once

Completed: exactly once

cmi5 defined has some very strict rules about passing and failing.

Page 33: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM 1.2: LMSSetValue(“cmi.core.lesson_status”, “passed”)

SCORM 2004:SetValue(“cmi.success_status”, “passed”)

cmi5

✴ “result” key required

✴ “score” optional

✴ “duration” required

Passed / Failed

xAPI has a “result” object as part of the spec. Passed and failed statements have specific needs around the result.

Page 34: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Passed / Failed{ "id": "6f8e1135-c9fe-4e02-ae1f-a0f7468745eb", "actor": { "objectType": "Agent", "name": "George Vilches", "account": { "homePage": "https://enfixlp.com/", "name": "gav" } }, "verb": { "id": “http://adlnet.gov/expapi/verbs/passed", "display": { "en": "initialized" } }, "object": { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } }, "result": { "success": true, "duration": ”PT9.55S” }, "context": { "registration": "4eb0e063-669b-479a-86b3-f9be9ac88a1d", "contextActivities": { "grouping": [ { "objectType": "Activity",

"id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } ], "category": [ { "objectType": "Activity", "id": "https://w3id.org/xapi/cmi5/context/categories/cmi5" } ] }, "extensions": { "https://w3id.org/xapi/cmi5/context/extensions/sessionid": "c7b6f0a9-482c-4c03-acc1-548289126963" } }, "timestamp": "2016-06-09T15:34:26.887Z" }

Here’s a minimum valid passed statement. Oof.

Page 35: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM 1.2: LMSSetValue(“cmi.core.lesson_status”, “completed”)

SCORM 2004:SetValue(“cmi.completion_status”, “completed”)

xAPI

✴ “result” key required

‣ “score” optional

‣ “duration” required

Completed

Completed has pretty much the same rules.

Page 36: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Completed{ "id": "6f8e1135-c9fe-4e02-ae1f-a0f7468745eb", "actor": { "objectType": "Agent", "name": "George Vilches", "account": { "homePage": "https://enfixlp.com/", "name": "gav" } }, "verb": { "id": “http://adlnet.gov/expapi/verbs/completed", "display": { "en": "initialized" } }, "object": { "objectType": "Activity", "id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } }, "result": { "completion": true, "duration": ”PT9.55S” }, "context": { "registration": "4eb0e063-669b-479a-86b3-f9be9ac88a1d", "contextActivities": { "grouping": [ { "objectType": "Activity",

"id": "http://jcasolutions.com/courses/_62yRKuq1asJ/activity1", "definition": { "name": { "en-US": "Simple SCORM Packager Tutorial" }, "description": { "en-US": "..." } } } ], "category": [ { "objectType": "Activity", "id": "https://w3id.org/xapi/cmi5/context/categories/cmi5" } ] }, "extensions": { "https://w3id.org/xapi/cmi5/context/extensions/sessionid": "c7b6f0a9-482c-4c03-acc1-548289126963" } }, "timestamp": "2016-06-09T15:34:26.887Z" }

So a valid completed statement isn’t any lighter.

Page 37: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

*Record Scratch*

SCORM allows passed/failed to be sent repeatedly

Where’s the scores?

How do we only send the right one?

But now we have a problem. SCORM lets you spam these commands. The order you submit the keys in doesn’t matter. What do we do?

Page 38: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Hold the statements back

✴ Wait for cmi.{core.}score.raw

✴ Wait for the first “passed”

✴ Wait for LMSFinish / Terminate

Void the statements

✴ Requires good LRS support for voiding

No one-size-fits-all solution

More Impedance Mismatch

There’s a lot of potential ways to group the data, and none of them are going to be completely right for all cases. You have to know a bit about your content to make the right choice.

Page 39: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

xAPI SCORM Profile

Interactions

Objectives

Custom xAPI statements

✴ So long as they’re “cmi5 allowed”

✴ Any verb

✴ cmi5 context template, no cmi5 category ID

What Else Can We Get?

The other xAPI bits we can shove into the cmi5 session, just stick to cmi5 allowed rules and you’ll be fine.

Page 40: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Just like initialized

Don’t send anything after this!

Redirect to LMS.LaunchData “returnURL”

Terminated

Unlike a SCORM package, where the LMS often makes the choice about what happens after LMSFinish(), It’s the AU’s job to exit correctly. Once you send that terminate command, sometime thereafter you have to do what LMS.LaunchData instructs you to.

Page 41: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Wrappers

This isn’t good candy, but maybe we can hide the nougat.

Page 42: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

All sorts of things will get in your way with pre-existing content

✴ SCORM to cmi5 requires big course changes

✴ Weak publishing tool support for cmi5

✴ Course publishing JS hard to edit

✴ JS object required

✴ SCORM 1.2: API

✴ SCORM 2004: API_1484_11

Problems Converting Existing Content

Converting content is hard, especially if you didn’t originally build it.

Page 43: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Magic?

Intercept those calls!Replace them with cmi5!

What if we can provide a solution that doesn’t involve changing the content at all?

Page 44: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Create container HTML page

✴ iframe

✴ Don’t forget allowfullscreen tag for video!

✴ <iframe src="index.htm" width="100%" height="100%" style="position:absolute;top:0;bottom:0;left:0;right:0;overflow:hidden;" frameborder="0" scrolling="no" allowfullscreen></iframe>

✴ Popup

✴ Many LMSes already popup once

✴ Confusing experiences

Building a Wrapper

No matter which you choose, someone’s arbitrary content isn’t going to play nice. It’s best if you can support both.

Page 45: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Virtual SCORM API

Provide virtual JS objectSCORM 1.2 (API) or SCORM 2004 (API_1484_11)

Time to make a make LMS in the browser!

Page 46: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

var API = { LMSInitialize: function(empty) { }, LMSFinish: function(empty) { }, LMSGetValue: function(key) { }, LMSSetValue: function(key, value) { }, LMSCommit: function(empty) { }, LMSGetLastError: function() { }, LMSGetErrorString: function(errorCode) { }, LMSGetDiagnostic(errorCode) { } };

SCORM 1.2 Virtual API

Page 47: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

var API_1484_11 = { Initialize: function(empty) { }, Terminate: function(empty) { }, GetValue: function(key) { }, SetValue: function(key, value) { }, Commit: function(empty) { }, GetLastError: function() { }, GetErrorString: function(errorCode) { }, GetDiagnostic(errorCode) { } };

SCORM 2004 Virtual API

Page 48: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Initialize isn’t Special

Just put the Statement in there, and done

Page 49: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

To Commit or To Immediate?

Commit(“”) requires a fully caching adapter.Don’t.

What we mean here is that if you want to do a perfect SCORM behavior mirror, you can’t immediately write even a single value, you have to wait for Commit() and Finish(). In practical terms, this means your implementation would have to be almost a fully conformant SCORM adapter, to correctly cache and validate things to hold them.For most cases, that’s probably overkill, and it’s best to just do the behavior when a SetValue() occurs. It’s not precise, but in our estimation it’s good enough for the 99%.

Page 50: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Convert calls as they come in

Cache/buffer as needed

✴ passed / failed (waiting for score)

✴ completed (waiting for passed / failed)

Some keys will need to be stored in different formats

✴ Ex: Session / Duration:

✴ SCORM 1.2: cmi.core.session_time: 0000:01:27

✴ cmi5: duration (ISO8601): PT0H1M27S

SetValue Conversion Challenges

Converting SetValue is where your troubles begin. This is where you need to have a decent understanding of the content you’re trying to wrap.

Page 51: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Write Twice, Read Never?

Where do we save these?Statements AND States!

Let’s use as much of the xAPI standard as we can!

Page 52: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Make Statements where useful

✴ cmi5 required (passed, failed)

✴ Likely reportables (cmi.interactions.n…)

Make States all the time, every SCORM key

✴ More on this in the GetValue section

Misses the read-only keys, but might be good enough

✴ If it’s not, you’ll have to build a fully conformant adapter; yuck!

SetValue Saves

Page 53: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Two approaches to fetching:

✴ Pull all potential values up front

✴ Fetch as you need them

Two approaches to storing:

✴ Fat Storage: All in one key

✴ Thin Storage: Each in their own key

GetValue Gets Expensive

Fat and thin storage are referring to the size of the object(s) being put into the LRS. Fat means that the JSON object itself is particularly large, relatively. Thin is because we compose lots of separate JSON objects.

Page 54: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM Lives in the Present

SCORM is Synchronous!

Synchronicity is usually cited as anathema to the modern browser, but we’re working with a standard from 1998 here. Sometimes you have to give a little.

Page 55: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Steps:

1. Make a storage object

2. Make a list of all the “static” SCORM keys

1. Regular keys like cmi.core.score.raw

2. Count keys like cmi.interactions._count

3. Load these all from the state, store, maybe as separate keys?

4. Iterate through the iterable keys

1. Ex: cmi.interactions.n.[id, type, timestamp, weighting, learner_response, result]

2. Plus all the nested iterables:

1. Ex:cmi.interactions.n.objectives.n.id

GetValue Fetching Ahead of Time

This isn’t the easiest workflow, to be sure. You have to know the entire standard’s key offerings ahead of time, and it makes course initialization potentially very slow.

Page 56: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Fetch each key when you need it

Synchronous course activity means blocking HTTP requests

✴ AJAX without the first A!

Could cause stutter in courses that GetValue() often

GetValue Just In Time

If you get them along the way, the course can start a lot faster potentially, but it might jerk as synchronous calls get hit in critical locations.

Page 57: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Store all values in a single JSON object

Store in a single State

Pros:

✴ Single State Get gives you all data, less in-course stutter

✴ Much less network fetch overhead, especially for courses that reuse the same keys

Cons:

✴ Requires a smarter JS API object to manage keys

✴ Write network activity could be more expensive if you have a lot of keys; bandwidth based on lots of large requests of mostly unchanging data

GetValue Fat Storage

Page 58: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Store each value in a separate key

Pros:

✴ Can be fetched inline with course, if LRS and network are sufficiently fast

✴ For larger sets of keys, much less network write traffic

Cons:

✴ More likely to cause in-course stutter

GetValue Thin Storage

Page 59: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SetValue and GetValue, Summarized

Thin Storage Fat Storage

Low GetValue()Low SetValue() 👍 👍Low GetValue()High SetValue() 👍 👎High GetValue()Low SetValue() 🤷 👍High GetValue()High SetValue() 👎 👎

Emoji make everything better.Why the shrug there? Because it’s very dependent on your content and your LRS’s operation as to how that experience goes, mores than the other properties. You can technically make SetValue() async if you must (just return immediately and believe it worked), and that lets you get away with “High SetValue” being a thumbs up for thin storage, but there’s no way to do that for GetValue().

Page 60: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

But can it chop, slice and dice?

Still no one size fits all solution

There’s no substitute for knowing how your content works in a SCORM context.

Page 61: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM to xAPI:

✴ https://github.com/adlnet/SCORM-to-xAPI-Wrapper

SCORM to cmi5:

✴ https://github.com/JCASolutions/scorm_to_cmi5_wrapper

Open Source Wrappers

Thanks, ADL! We’ve done what we can to try to ease the pains around this, and we’re still experimenting with ideas to make it more configurable and flexible.

Page 62: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

SCORM and cmi5 manifests are pretty much the same

Launch puts a little more work on the AU

cmi5 xAPI statements ask for a lot!

Consider using a cmi5 wrapper instead of modifyingyour course

Wrap Up

Page 63: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Questions?

Page 64: SCORM to cmi5 - SCORM xAPI Experience API eLearning Experts · The auth token is what you’re going to put into every future LRS request; this is your secret key. You HTTP GET it

Resources

cmi5 Specification: https://github.com/AICC/CMI-5_Spec_Current/blob/quartz/cmi5_spec.mdcmi5 Samples: http://aicc.github.io/CMI-5_Spec_Current/samples/xAPI SCORM Profilehttps://github.com/adlnet/xAPI-SCORM-Profile/blob/master/xapi-scorm-profile.mdCommon xAPI verbs:http://xapi.vocab.pub/describe/?url=https://w3id.org/xapi/adl

Contact info:

George [email protected]

321-296-8166 x203