ACSA

ACSA is an ICOM client. They use their own SCORM 2004 LMS named UMS.

List of Courses

This client has the following courses produced by ICOM:

  • CSTS
  • ESTS
  • RSTS
    • Legislative Awareness
  • Construction Safety Awareness

Deployment

Devs need to follow this.

Support

Notes

Wiki notes

CSTS SCORM 2004

Production site. 208.106.250.17. The superuser password is "acsafetysa". Staging site. 208.106.251.17

Courses are installed by adding the manifest first then copying or uploading course files within the corresponding folder.

Stephen Brown is the creator of this LMS.

His Words of Wisdom: (Pulled from emails and poorly organized)

Overall

Firstly, since we require global objectives, the flag objectivesGlobalToSystem should be turned off on the organization tag. With it turned on, which is the default, any named objective will exist for the user across all courses and attempts. Courses should only persist data for the user for the current course, otherwise, it becomes a big mess and extremely difficult to debug.

<organization identifier="csts" structure="hierarchical" adlseq:objectivesGlobalToSystem="false">

Topics

Each topic must be mapped to a global objective that the exam can read. This is done using the primary objective of the topic, which the LMS automatically links to the satisfied and measure of the activity. A sequencing rule will also allow the topic to be skipped if already mastered. Since we want the overall module to be scored and mastered solely based on the exam, a roll-up rule is added to exclued the topic from the module score and satisfied. The module will still consider the topic for progress, which is correct (e.g. 3 of 4 topics completed = 75% progress on module). This is done by adding this to each topic's sequencing:

<imsss:sequencing>

<imsss:objectives>

<imsss:primaryObjective objectiveID="PRIMARYOBJ">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_1" writeSatisfiedStatus="true" writeNormalizedMeasure="true" />

</imsss:primaryObjective>

</imsss:objectives>

<imsss:sequencingRules>

<imsss:preConditionRule>

<imsss:ruleConditions conditionCombination="any">

<imsss:ruleCondition referencedObjective="PRIMARYOBJ" condition="satisfied" />

</imsss:ruleConditions>

<imsss:ruleAction action="skip"/>

</imsss:preConditionRule>

</imsss:sequencingRules>

<imsss:rollupRules rollupObjectiveSatisfied="false" objectiveMeasureWeight="0" />

</imsss:sequencing>

The mapInfo targetObjectiveID should be unique for each topic, I used a format of OBJ_CSTS_<module number>_<topic number>.

The primaryObjective's objectiveID doesn't really matter unless you wanted to refer to it in the SCO. It's automatically linked to the activity, so there's really no reason for a SCO to reference its primary objective.

Module Exams

The exam then requires the sequencing rules to only show if the topics are done. This is done by mapping the exam to the topic global objectives created above and disabling the exam as long as any of them are not satisfied. A primary objective is also added to the exam (in the format OBJ_CSTS_<module number>_QUIZ), which can be mapped in the same way to disable the course exam until all module exams are satisfied. In order to allow the mastery requirement to be updated outside of the course, the exam is set to be satisfiedByMeasure. The exam SCO should read the minNormalizedMeasure and use this to determine if the student was satisfied.

<imsss:sequencing>

<imsss:controlMode choice='true' flow='true' />

<imsss:deliveryControls tracked='true'

completionSetByContent='false'

objectiveSetByContent='false' />

<imsss:objectives>

<imsss:primaryObjective objectiveID = "PRIMARYOBJ" satisfiedByMeasure="true">

<imsss:minNormalizedMeasure>1.0</imsss:minNormalizedMeasure>

<imsss:mapInfo targetObjectiveID = "OBJ_CSTS_1_QUIZ" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:primaryObjective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_1">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_1" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_2">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_2" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_3">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_3" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_4">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_4" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_5">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_5" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_6">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_6" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

</imsss:objectives>

<imsss:sequencingRules>

<imsss:preConditionRule>

<imsss:ruleConditions conditionCombination="any">

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_1" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_1" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_2" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_2" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_3" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_3" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_4" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_4" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_5" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_5" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_6" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_6" condition="objectiveStatusKnown" operator="not" />

</imsss:ruleConditions>

<imsss:ruleAction action="disabled"/>

</imsss:preConditionRule>

</imsss:sequencingRules>

</imsss:sequencing>

You'll notice some extra conditions, due to SCORM 2004 having a strange condition that is opposite of what would be logical. A satisfied status can be true, false, or unknown (or null, in that it hasn't been set). The logical opposite of satisfied=true should be satisfied=not true, but in SCORM 2004 the opposite of satisfied=true is satisfied=false which means that satisfied=unknown is neither satisfied nor not satisfied. All other conditions behave logically, only not satisfied behaves this way. As a result, a rule to check if an objective hasn't been satisfied requires 2 conditions, satisfied=false OR objectiveSatisfiedKnown=false.

The exam SCO should also update the topic objectives (i.e. a failure of a topic 3 question in module 2 exam should set loc_OBJ_CSTS_2_3 success_status to failed). This would disable the module exam after any failed objective until they retake the related topic content. With the sequencing rule on each topic, mastered topics can be skipped if their objective is satisfied after the exam has been taken, whereas failed topics become part of their path.

Module Groups

The parent module items should rollup the progress completion based on all child items (topics and exams), but the score and mastery determination should be based on the module exam. This is accomplished above by excluding the topics from the satisfied and weighting rollup. The final course exam should be disabled until all modules are completed, which requires the module to also write to a global objective (I'm using format OBJ_CSTS_<module number>):

<imsss:sequencing>

<imsss:controlMode choice='true' flow='true' />

<imsss:deliveryControls tracked='true' completionSetByContent='false' objectiveSetByContent='false' />

<imsss:objectives>

<imsss:primaryObjective objectiveID = "PRIMARYOBJ">

<imsss:mapInfo targetObjectiveID = "OBJ_CSTS_1" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:primaryObjective>

</imsss:objectives>

</imsss:sequencing>

Final Course Exam

The final course exam should be disabled until all modules are complete, accomplished similar to the module exams except it reads the module global objectives (I'm only using module 1 in example below):

<imsss:sequencing>

<imsss:controlMode choice='true' flow='true' />

<imsss:deliveryControls tracked='true' completionSetByContent='false' objectiveSetByContent='false' />

<imsss:objectives>

<imsss:primaryObjective objectiveID = "PRIMARYOBJ" satisfiedByMeasure="true">

<imsss:minNormalizedMeasure>1.0</imsss:minNormalizedMeasure>

<imsss:mapInfo targetObjectiveID = "OBJ_CSTS_FINAL_QUIZ" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:primaryObjective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

</imsss:objectives>

<imsss:sequencingRules>

<imsss:preConditionRule>

<imsss:ruleConditions conditionCombination="any">

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1" condition="objectiveStatusKnown" operator="not" />

</imsss:ruleConditions>

<imsss:ruleAction action="disabled"/>

</imsss:preConditionRule>

</imsss:sequencingRules>

</imsss:sequencing>

I didn't update the module rollup rules, but they should be similar to the topic/exam rules, in that the course mark should exclude the module scores and mastery - i.e. the course mark and mastery should be based solely on the final course exam. The course progress completion is fine remaining as defaulted, being a percentage of modules completed.

SCO suspend

- Each SCO sets adl.nav.request to "suspendAll" on initial launch, which seems to be overridden if using the embedded courseware menu. If using the LMS menu, however, adl.nav.request is not overridden, which results in the LMS exiting the course if navigating between any activities. Can this be changed such that adl.nav.request only gets set when a navigation selection is made in the activity?

cmi.exit relates to the tracking data and the state the SCO is left (time-out, suspend, etc.), whereas adl.nav.request defines what the LMS is supposed to do AFTER the SCO terminates. If the SCO terminates with a pending suspendAll nav request, the LMS will suspend the SCO, suspend the course, and exit out of the course.

Score Scaled

The objectives score.scaled is the objective measure and is used by the LMS in determinations. The other scores are just metadata about the score. If the user got 4/5, all the LMS cares about is that the score is 0.8, but the score.min and score.max would be set to 1 and 5 for the range and the raw would be set to 4. None of these mean anything to the LMS, only the normalized score.scaled value of 0.8.

Setting quiz questions to fail a lesson

You outline that failure of a topic 3 question in module 2 exam should set loc_obj_csts_2_3 success_status to failed hence disabling the exam.

The manifest settings, if set, would make retaking the quiz and reviewing the lessons impossible while making them retake the lessons and mini quiz’s all over again, thus extending the length of the course. What section accounts for this rule so that I may leave it out of the manifest.

I only just saw your review mode a few days ago and, yes, this would make the review rules in the sequencing unnecessary.

The only difference would be in the objectives section of the exam as you won't require the objectives write maps in the exam, but you will need it for the primary objective. You will still need the objectives and their default read maps, as the exam rules need to know the status of the topics in order to disable.

<imsss:sequencing>

<imsss:controlMode choice='true' flow='true' />

<imsss:deliveryControls tracked='true'

completionSetByContent='false'

objectiveSetByContent='false' />

<imsss:objectives>

<imsss:primaryObjective objectiveID = "PRIMARYOBJ" satisfiedByMeasure="true">

<imsss:minNormalizedMeasure>1.0</imsss:minNormalizedMeasure>

<imsss:mapInfo targetObjectiveID = "OBJ_CSTS_1_QUIZ" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:primaryObjective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_1">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_1" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_2">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_2" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_3">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_3" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_4">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_4" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_5">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_5" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_6">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_6" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:objective>

</imsss:objectives>

<imsss:sequencingRules>

<imsss:preConditionRule>

<imsss:ruleConditions conditionCombination="any">

<imsss:ruleCondition referencedObjective="PRIMARYOBJ" condition="satisfied" />

</imsss:ruleConditions>

<imsss:ruleAction action="skip"/>

</imsss:preConditionRule>

</imsss:sequencingRules>

<imsss:rollupRules rollupObjectiveSatisfied="false" objectiveMeasureWeight="0" />

</imsss:sequencing>

Quiz unlocked after Lesson completed

The problem is that the only sequencing rule currently on the exam is that it is disabled once the exam is satisfied. Compare this with the original manifest snippet I sent, it needs to have a rule set for each topic objective that disables the exam. The issue seems to have occurred when you asked the follow up question and I gave the snippet that didn't write the objectives for the exam, for some reason the rules didn't come across with my copy-paste.

Here is what the module exam sections should contain:

<imsss:sequencing>

<imsss:controlMode choice='true' flow='true' />

<imsss:deliveryControls tracked='true' completionSetByContent='false' objectiveSetByContent='false' />

<imsss:objectives>

<imsss:primaryObjective objectiveID = "PRIMARYOBJ" satisfiedByMeasure="true">

<imsss:minNormalizedMeasure>1.0</imsss:minNormalizedMeasure>

<imsss:mapInfo targetObjectiveID = "OBJ_CSTS_1_QUIZ" writeSatisfiedStatus = "true" writeNormalizedMeasure = "true" />

</imsss:primaryObjective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_1">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_1" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_2">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_2" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_3">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_3" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_4">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_4" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_5">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_5" />

</imsss:objective>

<imsss:objective objectiveID="loc_OBJ_CSTS_1_6">

<imsss:mapInfo targetObjectiveID="OBJ_CSTS_1_6" />

</imsss:objective>

</imsss:objectives>

<imsss:sequencingRules>

<imsss:preConditionRule>

<imsss:ruleConditions conditionCombination="any">

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_1" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_1" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_2" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_2" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_3" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_3" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_4" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_4" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_5" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_5" condition="objectiveStatusKnown" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_6" condition="satisfied" operator="not" />

<imsss:ruleCondition referencedObjective="loc_OBJ_CSTS_1_6" condition="objectiveStatusKnown" operator="not" />

</imsss:ruleConditions>

<imsss:ruleAction action="disabled"/>

</imsss:preConditionRule>

</imsss:sequencingRules>

</imsss:sequencing>

The final exam also has to reference every module in the sequencing rules, it currently will enable when Module 1 is complete.

Scorm Prod tester

FYI, Tobias, there is another call that you can make in the LMS - instead of adl.nav.organization you can call adl.nav.organizationalert, which will pop up the results of adl.nav.organization in an alert box. I have found this handy to use for debugging, since Claude's Diagnostic course doesn't show the XML results of the call.

SCO Success Status to Satisfy Objectives

That's the issue, then. The manifest will needs to set Objective Set by Content to true or the content will need to set success status on each launch.

>> When a lesson is set to complete there still needs a success status set in order for a rollup? It can’t be assumed that the rollup objective has been satisfied?

It's not a rollup issue, the LMS will assume the objective is satisifed if it isn't communicated by the content and Objective Set by Content is false. As a result, the global objective is being satisfied by just clicking on the topic and the quiz is being unlocked having just viewed the topics.

I'm not sure why SCORM made the default rollup for the objective and the lesson independent. If completion_status is set, it would be more logical to me that the LMS shouldn't touch the objective rollup. The defaults are in place to ensure that a simple SCO with no tracking will work with sequencing. If the defaults are used (Objective Set by Content defaults to false) and progress isn't returned, the SCO is assumed completed and if success isn't returned, the SCO is assumed to be passed.

Success Status is used to communicate the pass/fail of the lesson and is separate from rollup. The Success Status may or may not rollup, depending on the rollup rules.

I would suggest setting Objective Set by Content = true in the manifest for all items. You should then check the primary objective on SCO load. If the objective status is unknown, set completion status to incomplete. At the end of the SCO, set completion status to complete and the objective to passed. This will ensure that the objective only gets completed when the end of the content is hit for each topic and doesn't get reset if the user was to review content they already mastered.

cmi.success_status maps to the primary objective

completionSetByContent

>>Should I have “completionSetByContent= true” as well, since the sco is setting the completion status.

You can, but the setting is only necessary if you will have content that won't set the completion status.

>> Is there simply any way the manifest rollup rules can be triggered by completions alone?

Yes, but the global objectives are easier to control and debug sequencing as they exist outside of the content. ACSA can view these globals to determine if a user completed certain lessons or topics at a glance. It also enables the content to share data such as completions so that it can tell if an item has been already mastered.

Completion and mastery are 2 independent things. You can complete something without achieving mastery or you can master something without completing or even viewing it (e.g. pretest). Completion is a status of the lesson or attempt, whereas mastery is a status of the objectives.

>> what if in the future a quiz has one attempt and user fails but I want the objective to be satisfied

What would be the use case for this? If a user fails the quiz, why would you want the objective to be satisfied? You can mark secondary objectives as satisfied, but the primary objective should be the pass/fail of the quiz itself.

Navigation not returning completions

If not specified in the import, useCurrentAttemptProgressInfo defaults to true. This flag will cause the LMS to only use the tracking data that occurred in the parent's current attempt. When you relaunch the course, the root node is now a new attempt and any tracking data on the child nodes from the previous attempt are not considered.

It is best to always have useCurrentAttemptProgressInfo and useCurrentAttemptObjectiveInfo off.

The odd part is that it defaults to true, as they do have some use but it would be in rare cases. For example, it would be used if you want everything in a module to clear if the student was to reattempt any topic inside it. The student would click through the module 1 as per normal and see their progress, but if they ever selected an item outside of module 1 and came back, their tracking would be cleared for everything in module 1.

One other flag is ObjectivesGlobalToSystem, which defaults to true but should always be set to false. If false, this will result in the objectives being attached to the user's tracking for the course and be reset if the user ever requires recertification. If true, the objectives exist forever and any course that uses the same named objective will get the objective data. As far as I'm concerned, this would never be desired.

Exit button not setting lesson complete

I figured it out. It looks like your content is invoking a suspendAll on use of that 'Exit' button. SuspendAll will save your state, but will not invoke rollup upon completion. It is one of those finicky SCORM 2004 things. We have created a package property that will help with this called "Invoke rollup at Suspend All". I took the course with this enabled and it behaved as it should.

How Average Scoring work for course score http://support.scorm.com/entries/101557-default-score-rollup-in-scorm-2004 Also needs to add this for each section and root objective so that the score rolls up from sco to section to course <imsss:rollupRules objectiveMeasureWeight="1"/>