<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>VSSCORM &#187; Run Time Environment</title>
	<atom:link href="http://www.vsscorm.net/category/scorm-rte/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.vsscorm.net</link>
	<description>A Very Simple SCORM Interface</description>
	<lastBuildDate>Thu, 08 Sep 2011 14:45:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Step 61 &#8211; Error Checking in LMSSetValue and LMSGetValue</title>
		<link>http://www.vsscorm.net/2011/09/08/step-61-error-checking-in-lmssetvalue-and-lmsgetvalue/</link>
		<comments>http://www.vsscorm.net/2011/09/08/step-61-error-checking-in-lmssetvalue-and-lmsgetvalue/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 14:45:52 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1670</guid>
		<description><![CDATA[I want to carry a couple of basic tests within LMSSetValue and LMSGetValue to see: whether the specified data element is supported; and whether it has the necessary read or write privileges and then set the error code appropriately. This &#8230; <a href="http://www.vsscorm.net/2011/09/08/step-61-error-checking-in-lmssetvalue-and-lmsgetvalue/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I want to carry a couple of basic tests within LMSSetValue and LMSGetValue to see:</p>
<ol>
<li>whether the specified data element is supported; and</li>
<li>whether it has the necessary read or write privileges</li>
</ol>
<p>and then set the error code appropriately. This is a pretty minimal set of tests &#8211; I&#8217;m probably going to have to add some others later &#8211; but it&#8217;s a starting point. Here&#8217;s the code.</p>
<p><span id="more-1670"></span></p>
<pre class="brush:php; first-line: 1; html-script: false;">
function LMSGetValue(varname) {

  // not initialized or already finished
  if ((! flagInitialized) || (flagFinished)) {
    errorCode = '301';
    return '';
  }

  // not implemented
  if ( ! isSupported(varname) ) {
    errorCode = '401';
    return '';
  }

  // not readable
  if ( ! dataElementRead ) {
    errorCode = '404';
    return '';
  }

  // otherwise, return the requested data
  errorCode = '0';
  return cache[varname];

}

// --------------------------------------------------------

function LMSSetValue(varname,varvalue) {

  // not initialized or already finished
  if ((! flagInitialized) || (flagFinished)) {
    errorCode = '301';
    return "false";
  }

  // not implemented
  if ( ! isSupported(varname) ) {
    errorCode = '401';
    return 'false';
  }

  // not writeable
  if ( ! dataElementWrite ) {
    errorCode = '403';
    return 'false';
  }

  // otherwise, set the requested data, and return success value
  cache[varname] = varvalue;
  errorCode = '0';
  return "true";

}
</pre>
<p>The additions are pretty straightforward.</p>
<ul>
<li><strong>Lines 9 to 13</strong>, and <strong>37 to 41</strong> check to see whether the data element specified by the SCO is actually implemented (if you remember, I&#8217;m currently supporting all of the mandatory data elements, but only two of the optional elements). If the data element isn&#8217;t supported, the error code is set to &#8217;401&#8242;. <br />&nbsp;
<li><strong>Lines 15 to 19</strong>, and <strong>43 to 47</strong> test whether the data element is readable (for the LMSGetValue function) or writeable (for the LMSSetValue function) and, if it fails, sets error code &#8217;404&#8242; or &#8217;403&#8242; respecively.<br />&nbsp;
</ul>
<p>Note that, if the functions are successful, the error code is set to &#8217;0&#8242; before exit to indicate success. According to the SCORM RTE specification, every call to an API function must result in the error code being set &#8211; whether it&#8217;s successful or not.</p>
<p>Next time, I&#8217;m going to step away from the main VSSCORM code and do some work on a test harness that will allow me to monitor the SCO-LMS communications in order to make sure that all of this is working.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2011/09/08/step-61-error-checking-in-lmssetvalue-and-lmsgetvalue/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Step 60 &#8211; Supported Data Elements</title>
		<link>http://www.vsscorm.net/2011/09/06/step-60-supported-data-elements/</link>
		<comments>http://www.vsscorm.net/2011/09/06/step-60-supported-data-elements/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 14:55:06 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1658</guid>
		<description><![CDATA[One of the things that has caught me out in a couple of recent cases is that the SCORM standard makes SCO developers rely on error codes to determine whether or not certain elements are supported. I describe one specific &#8230; <a href="http://www.vsscorm.net/2011/09/06/step-60-supported-data-elements/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>One of the things that has caught me out in a couple of recent cases is that the SCORM standard makes SCO developers rely on error codes to determine whether or not certain elements are supported. I describe one specific example in an earlier post &#8211; <a href="http://www.vsscorm.net/2010/07/13/step-54-error-handling/" title="Step 54 – Error Handling?">Step 54 &#8211; Error Handling</a>. </p>
<p>In a sensible system, the initialization process would provide the SCO with a complete list of supported elements so that it wouldn&#8217;t have to go through all this rigmarole. But that&#8217;s too much to hope for, so I need a simple way to check whether a data element is supported or not, and I&#8217;ll also need to check whether it&#8217;s readable and/or writeable.</p>
<p><span id="more-1658"></span></p>
<p>I&#8217;m going to start with my favorite weapon of choice &#8211; a JavaScript object (associative array for the perl and PHP fans). Here it is:</p>
<pre class="brush:php; first-line: 1; html-script: false;">
var dataElements = new Object();

dataElements['cmi.core._children'] = 'RO';

dataElements['cmi.core.student_id'] = 'RO';
dataElements['cmi.core.student_name'] = 'RO';

dataElements['cmi.core.lesson_location'] = 'RW';
dataElements['cmi.core.credit'] = 'RO';
dataElements['cmi.core.lesson_status'] = 'RW';
dataElements['cmi.core.entry'] = 'RO';
dataElements['cmi.core.exit'] = 'WO';

dataElements['cmi.core.score._children'] = 'RO';
dataElements['cmi.core.score.raw'] = 'RW';
dataElements['cmi.core.score.max'] = 'RW';
dataElements['cmi.core.score.min'] = 'RW';

dataElements['cmi.core.total_time'] = 'RO';
dataElements['cmi.core.session_time'] = 'WO';

dataElements['cmi.suspend_data'] = 'RW';
dataElements['cmi.launch_data'] = 'RO';

dataElements['cmi.comments'] = 'RW';
dataElements['cmi.comments_from_lms'] = 'RO';
</pre>
<p>This is nothing more than a list of the supported elements with their read/write status.</p>
<p>Then, to make life a little neater when I come to plug this into the actual code, I&#8217;m going to define a simple little function:</p>
<pre class="brush:php; first-line: 1; html-script: false;">
function isSupported(dataElementName) {

  // flags
  dataElementSupported = false;
  dataElementRead = false;
  dataElementWrite = false;

  // if the data element is in the list of supported elements
  if (dataElementName in dataElements) {

    rights = dataElements[dataElementName];
    dataElementSupported = true;

    if ( (rights == 'RW') || (rights == 'RO') ) { dataElementRead = true; }
    if ( (rights == 'RW') || (rights == 'WO') ) { dataElementWrite = true; }

  }

  return dataElementSupported;

}
</pre>
<p>This function simply sets three flags that are available to the LMSSetValue and LMSGetValue functions so that they can test the SCO-supplied input, and generate appropriate error codes.</p>
<p>Next, I&#8217;m going to add this to the LMSSetValue and LMSGetValue functions.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2011/09/06/step-60-supported-data-elements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 59 &#8211; LMSGetLastError, LMSGetErrorString and LMSGetDiagnostic</title>
		<link>http://www.vsscorm.net/2011/09/02/step-59-lmsgetlasterror-lmsgeterrorstring-and-lmsgetdiagnostic/</link>
		<comments>http://www.vsscorm.net/2011/09/02/step-59-lmsgetlasterror-lmsgeterrorstring-and-lmsgetdiagnostic/#comments</comments>
		<pubDate>Fri, 02 Sep 2011 23:54:51 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1652</guid>
		<description><![CDATA[The three API functions that return information to the SCO can now be connected to the error code variable that I implemented in Step 58, and to the error messages that I set up in Step 57. Here they are: &#8230; <a href="http://www.vsscorm.net/2011/09/02/step-59-lmsgetlasterror-lmsgeterrorstring-and-lmsgetdiagnostic/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The three API functions that return information to the SCO can now be connected to the error code variable that I implemented in <a href="http://www.vsscorm.net/2011/09/02/step-58-setting-and-storing-the-error-code/" title="Step 58 – Setting and Storing the Error Code">Step 58</a>, and to the error messages that I set up in <a href="http://www.vsscorm.net/2011/09/02/step-57-error-codes/" title="Step 57 – Error Codes">Step 57</a>.</p>
<p><span id="more-1652"></span></p>
<p>Here they are:</p>
<pre class="brush:php; first-line: 1; html-script: false;">
function LMSGetLastError() {
  return errorCode;
}

function LMSGetErrorString(thisErrorCode) {
  return errorMessages[thisErrorCode];
}

function LMSGetDiagnostic(thisErrorCode) {
  return errorMessages[thisErrorCode];
}
</pre>
<p>Pretty simple so far. Next step &#8211; testing whether variables are supported and, if so, are they readable and/or writeable.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2011/09/02/step-59-lmsgetlasterror-lmsgeterrorstring-and-lmsgetdiagnostic/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Step 58 &#8211; Setting and Storing the Error Code</title>
		<link>http://www.vsscorm.net/2011/09/02/step-58-setting-and-storing-the-error-code/</link>
		<comments>http://www.vsscorm.net/2011/09/02/step-58-setting-and-storing-the-error-code/#comments</comments>
		<pubDate>Fri, 02 Sep 2011 23:44:43 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1641</guid>
		<description><![CDATA[OK &#8211; an easy step here. I want a place to store the error code, so I introduce a new variable called &#8216;errorCode&#8217; into api.php. // ------------------------------------------ // Status Flags // ------------------------------------------ var flagFinished = false; var flagInitialized = false; &#8230; <a href="http://www.vsscorm.net/2011/09/02/step-58-setting-and-storing-the-error-code/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>OK &#8211; an easy step here. I want a place to store the error code, so I introduce a new variable called &#8216;errorCode&#8217; into api.php.</p>
<p><span id="more-1641"></span></p>
<pre class="brush:php; first-line: 1; html-script: false;">
// ------------------------------------------
//   Status Flags
// ------------------------------------------
var flagFinished = false;
var flagInitialized = false;
var errorCode = '0';
</pre>
<p>Pretty simple. This variable is accessible to all of the functions that I&#8217;ve defined in api.php. So setting an error code is as simple as this (using LMSGetValue as an example):</p>
<pre class="brush:php; first-line: 1; html-script: false;">
function LMSGetValue(varname) {

  // not initialized or already finished
  if ((! flagInitialized) || (flagFinished)) {
    errorCode = '301';
    return '';
  }

  // otherwise, return the requested data
  errorCode = '0';
  return cache[varname];

}
</pre>
<p>You&#8217;ll see that I set &#8217;301&#8242; if (for some reason) the API hasn&#8217;t been initialized, and &#8217;0&#8242; if the call is successful. Obviously, there are a lot more tests and checks that I need to implement &#8211; for example, is the data element readable or not? And is it even supported by the API? I&#8217;ll get on to that later.</p>
<p>Next &#8211; setting up the API calls to handle the error code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2011/09/02/step-58-setting-and-storing-the-error-code/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Step 57 &#8211; Error Codes</title>
		<link>http://www.vsscorm.net/2011/09/02/step-57-error-codes/</link>
		<comments>http://www.vsscorm.net/2011/09/02/step-57-error-codes/#comments</comments>
		<pubDate>Fri, 02 Sep 2011 19:47:56 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1627</guid>
		<description><![CDATA[The SCORM 1.2 Runtime Environment (RTE) uses a system of error codes that are set by the API, and which can be read by the SCO using three API functions: LMSGetLastError() LMSGetErrorString() LMSGetDiagnostic() I&#8217;ve already implemented &#8220;stubs&#8221; for these functions &#8230; <a href="http://www.vsscorm.net/2011/09/02/step-57-error-codes/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The SCORM 1.2 Runtime Environment (RTE) uses a system of error codes that are set by the API, and which can be read by the SCO using three API functions:</p>
<ul>
<li>LMSGetLastError()</li>
<li>LMSGetErrorString()</li>
<li>LMSGetDiagnostic()</li>
</ul>
<p>I&#8217;ve already implemented &#8220;stubs&#8221; for these functions in my api.php code as noted in <a href="http://www.vsscorm.net/2009/06/19/other-scorm-api-functions/">Step 10 &#8211; Other SCORM API Fuctions</a>. But, before I make these functions active, I need to set up the error codes and related messages in the API code. </p>
<p><span id="more-1627"></span></p>
<p>The error codes are all detailed in the <a href="http://www.vsscorm.net/docs/SCORM_1.2_RunTimeEnv.pdf" target="_blank">SCORM 1.2 Runtime Environment specification</a> &#8211; section 3.3.3. So, I&#8217;m going to set up a JavaScript object (which,having been brought up on perl and PHP, I tend to think of as an &#8216;associative array&#8217;) in the api.php code:</p>
<pre class="brush:php; first-line: 1; html-script: false;">
var errorMessages = new Object();
errorMessages['0'] = 'No Error';
errorMessages['101'] = 'General Exception';
errorMessages['201'] = 'Invalid Argument';
errorMessages['202'] = 'Element Cannot Have Children';
errorMessages['203'] = 'Element Not an Array - Cannot Have Children';
errorMessages['301'] = 'API Not Initialized';
errorMessages['401'] = 'Data Model Element Not Implemented';
errorMessages['402'] = 'Invalid Set Value - Element is a Keyword';
errorMessages['403'] = 'Invalid Set Value - Element is Read Only';
errorMessages['404'] = 'Invalid Get Value - Element is Write Only';
errorMessages['405'] = 'Invalid Set Value - Incorrect Data Type';
</pre>
<p>Why am I using strings e.g. &#8217;201&#8242; rather than numbers as indices? Because it&#8217;s one of the (many) idiosyncrasies of the SCORM standard!</p>
<p>Next time, setting and storing the error code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2011/09/02/step-57-error-codes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Step 56 &#8211; mysql_escape_string</title>
		<link>http://www.vsscorm.net/2010/07/19/step-56-mysql_escape_string/</link>
		<comments>http://www.vsscorm.net/2010/07/19/step-56-mysql_escape_string/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 14:05:55 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1514</guid>
		<description><![CDATA[I don&#8217;t refer to the PHP manual very much for commonly used functions, so I almost missed this one. The &#8216;mysql_escape_string&#8217; function that&#8217;s used in subs.php to prepare data for insertion into the database is deprecated as of PHP 5.3 &#8230; <a href="http://www.vsscorm.net/2010/07/19/step-56-mysql_escape_string/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t refer to the PHP manual very much for commonly used functions, so I almost missed this one. The &#8216;mysql_escape_string&#8217; function that&#8217;s used in subs.php to prepare data for insertion into the database is deprecated as of PHP 5.3 and should be replaced with &#8216;mysql_real_escape_string&#8217;. </p>
<p><span id="more-1514"></span></p>
<p>From the PHP manual:</p>
<blockquote><p>This function [<a href="http://www.php.net/manual/en/function.mysql-escape-string.php" target="_blank">mysql_escape_string()</a>] is identical to <a href="http://www.php.net/manual/en/function.mysql-real-escape-string.php" target="_blank">mysql_real_escape_string()</a> except that mysql_real_escape_string() takes a connection handler and escapes the string according to the current character set. mysql_escape_string() does not take a connection argument and does not respect the current charset setting.</p></blockquote>
<p>The new function &#8211; mysql_real_escape_string &#8211; has been available since PHP 4.3 and, quite frankly, you really shouldn&#8217;t be running on anything older than that! So, at the next release of the RTE, I&#8217;ll be changing the database functions in subs.php to reflect this change.</p>
<p>On a final note, it&#8217;s still my intention to convert the code to run on a database abstraction layer, but I just haven&#8217;t had the time to do that yet!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/07/19/step-56-mysql_escape_string/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Step 55 &#8211; Delaying Loading of the SCO</title>
		<link>http://www.vsscorm.net/2010/07/16/step-55-delaying-loading-of-the-sco/</link>
		<comments>http://www.vsscorm.net/2010/07/16/step-55-delaying-loading-of-the-sco/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 13:45:07 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1554</guid>
		<description><![CDATA[In the past, I&#8217;ve had some intermittent problems with a SCO loading but showing a Javascript error. Although I couldn&#8217;t pin it down conclusively, it seemed to result from an incomplete download of some kind. Since forcing a reload with &#8230; <a href="http://www.vsscorm.net/2010/07/16/step-55-delaying-loading-of-the-sco/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In the past, I&#8217;ve had some intermittent problems with a SCO loading but showing a Javascript error. Although I couldn&#8217;t pin it down conclusively, it seemed to result from an incomplete download of some kind. Since forcing a reload with CTRL-R or CTRL-F5 usually solved the problem, I just put it down to something that I had to live with because SCORM forces us to use Javascript which can be very fickle.</p>
<p>But, recently, reader &#8216;deighvan&#8217; reported <a href="http://www.vsscorm.net/2010/04/30/download-vs-scorm-1-2-rte-rev-2-1/comment-page-1/#comment-62">a similar problem</a> and, even better, came up with a simple solution. So I&#8217;ve incorporated a slightly modified form of this solution in a new version of the rte.php file. </p>
<p><span id="more-1554"></span></p>
<p>Here it is:</p>
<pre class="brush:php; first-line: 1; html-script: false;">&lt;?php 

/*

VS SCORM 1.2 RTE - rte.php
Rev XXXXXXXXXXX was 2009-11-30-01
Copyright (C) 2010, Addison Robson LLC

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA  02110-1301, USA.

*/

// read SCOInstanceID from the GET parameters
$SCOInstanceID = $_GET['SCOInstanceID'] * 1;

?>
&lt;html>
&lt;head>
  &lt;title>VS SCORM&lt;/title>
  &lt;script language="javascript">

    var started = false;

    function loadSCO() {
      if (! started) {
        SCO.location.href = '... location of the SCO ...';
      }
      started = true;
    }

    function unloadSCO() {
      setTimeout('API.LMSFinish("");',2000);
    }

  &lt;/script>
&lt;/head>
&lt;frameset frameborder="0" framespacing="0" border="0" rows="50,*" cols="*" onbeforeunload="unloadSCO();" onunload="unloadSCO();">
  &lt;frame src="api.php?SCOInstanceID=&lt;?php print $SCOInstanceID; ?>" name="API" id="API" noresize onload="loadSCO();">
  &lt;frame src="blank.html" name="SCO" id="SCO">
&lt;/frameset>
&lt;/html></pre>
<p>And here are the changes &#8230; line-by-line:</p>
<ul>
<li><strong>Line 35</strong> &#8211; I define a Javascript variable called &#8216;started&#8217; and set it to false. This will be used to prevent the SCO being started twice.<br />&nbsp;
<li><strong>Lines 37 to 42</strong> &#8211; I&#8217;ve added a new Javascript function that, when called, will load the SCO into the &#8216;SCO&#8217; frame.<br />&nbsp;
<li><strong>Line 51</strong> &#8211; I&#8217;ve added an &#8216;onload&#8217; action. When the api.php code has completely loaded into the frame, this will call loadSCO() which will start the SCO.<br />&nbsp;
<li><strong>Line 52</strong> &#8211; When the frameset starts, I&#8217;m going to load a blank document into the &#8216;SCO&#8217; frame. Why not just start with an empty frame (i.e. src=&#8221;)? Because, if I&#8217;m going to be running over an SSL connection, Internet Explorer considers an empty frame to be an insecure document and will pop up a warning message that&#8217;s annoying, and also worrying to many students.<br />&nbsp;
</ul>
<p>So I try it out, and it seems to work much more smoothly than before. Once again, thanks to reader &#8216;deighvan&#8217; for the suggestion.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/07/16/step-55-delaying-loading-of-the-sco/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Step 54 &#8211; Error Handling?</title>
		<link>http://www.vsscorm.net/2010/07/13/step-54-error-handling/</link>
		<comments>http://www.vsscorm.net/2010/07/13/step-54-error-handling/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 14:52:31 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1507</guid>
		<description><![CDATA[The problem SCO described in Step 52 is now working correctly, so why do I need to look any further? There&#8217;s a more subtle problem. The &#8216;datamodel.element._children&#8217; mechanism described in the SCORM RTE specification seems to have been developed so &#8230; <a href="http://www.vsscorm.net/2010/07/13/step-54-error-handling/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The problem SCO described in <a href="http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/">Step 52</a> is now working correctly, so why do I need to look any further? There&#8217;s a more subtle problem.</p>
<p>The &#8216;datamodel.element._children&#8217; mechanism described in the SCORM RTE specification seems to have been developed so that there&#8217;s a way for a SCO to determine which data elements are supported. </p>
<p><span id="more-1507"></span></p>
<p><a href="http://www.vsscorm.net/wp-content/uploads/2010/07/children.jpg"><img src="http://www.vsscorm.net/wp-content/uploads/2010/07/children.jpg" alt="" title="_children" width="697" height="189" class="aligncenter size-full wp-image-1572" /></a></p>
<p><center><a href="/docs/SCORM_1.2_RunTimeEnv.pdf" target="_blank">SCORM 1.2 RTE Specification</a> &#8211; Page 3-9</center></p>
<p>For example, if the SCO was to do this:</p>
<pre class="brush:javascript; first-line: 1">var supported = LMSGetValue('cmi.core._children');</pre>
<p>the variable &#8216;supported&#8217; would be set to &#8216;student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,exit,session_time&#8217; which is a list of the data elements in the <b>cmi.core</b> group that the LMS supports. This allows a SCO to determine whether or not it can use a particular data element before it tries to do so. And this is all well and good except &#8230;</p>
<p>&#8230; it doesn&#8217;t cover all of the optional data elements. The data element that the problem SCO was trying to use &#8211; <b>cmi.comments</b> &#8211; is not part of the <b>cmi.core</b> group of data elements, so looking at the value of <b>cmi.core._children</b> wouldn&#8217;t have helped. In fact, <b>cmi.comments</b> isn&#8217;t part of any group at all.</p>
<p>Now, the SCORM 1.2 RTE says that:</p>
<ul>
<li>If an element IS supported but contains no child elements, <b>an empty string is returned</b>.
<li>If an element IS NOT supported, <b>an empty string is returned</b>.
</ul>
<p>So there would be no way to use &#8216;_children&#8217; to determine if <b>cmi.comments</b> was supported since:</p>
<pre class="brush:javascript; first-line: 1">var supported = LMSGetValue('cmi.comments._children');</pre>
<p>would always return an empty string. Instead, according to the specification, one has to look at the error codes:</p>
<p><a href="http://www.vsscorm.net/wp-content/uploads/2010/07/children2.jpg"><img src="http://www.vsscorm.net/wp-content/uploads/2010/07/children2.jpg" alt="" title="_children2" width="840" height="329" class="aligncenter size-full wp-image-1573" /></a></p>
<p><center><a href="/docs/SCORM_1.2_RunTimeEnv.pdf" target="_blank">SCORM 1.2 RTE Specification</a> &#8211; Page 3-9</center></p>
<p>So, if I execute the following:</p>
<pre class="brush:javascript; first-line: 1">var supported = LMSGetValue('cmi.comments._children');
var lasterror = LMSGetLastError();</pre>
<p>then variable &#8216;lasterror&#8217; is set to 401, and I know that the <b>cmi.comments</b> element is NOT supported.</p>
<p>OK &#8211; it seems pretty odd to me that a system would be designed to cover some, but not all, of the optional data elements. But there it is &#8211; we&#8217;re going to have to live with it.</p>
<p>And it highlights a more fundamental issue that I need to fix &#8211; I&#8217;ve been very lax with my handling of the error codes so far &#8211; that has to change!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/07/13/step-54-error-handling/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Step 53 &#8211; Delaying the Closing Sequence</title>
		<link>http://www.vsscorm.net/2010/07/11/step-53-delaying-the-closing-sequence/</link>
		<comments>http://www.vsscorm.net/2010/07/11/step-53-delaying-the-closing-sequence/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 21:21:38 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1505</guid>
		<description><![CDATA[I&#8217;m still trying to fix the problem that my reader&#8217;s SCO highlighted (described in this post). I&#8217;ve implemented the optional data element that it&#8217;s trying to use &#8211; cmi.comments &#8211; but that hasn&#8217;t fixed the problem. So I need to &#8230; <a href="http://www.vsscorm.net/2010/07/11/step-53-delaying-the-closing-sequence/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m still trying to fix the problem that my reader&#8217;s SCO highlighted (described in <a href="http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/">this post</a>). I&#8217;ve implemented the optional data element that it&#8217;s trying to use &#8211; <b>cmi.comments</b> &#8211; but that hasn&#8217;t fixed the problem. So I need to look elsewhere.</p>
<p>The SCO is trying to save the user&#8217;s comments to the LMS database when the SCO is closed. So, perhaps, the API code isn&#8217;t being given enough time to commit all of the data values to the database before everything shuts down.</p>
<p><span id="more-1505"></span></p>
<p>To try to fix this, I&#8217;m going to add a delay to the closing sequence. As a reminder, here&#8217;s what my rte.php looks like right now.</p>
<pre class="brush:php; first-line: 1; html-script: false;">&lt;?php 

/*

VS SCORM 1.2 RTE - rte.php
Rev 2009-11-30-01
Copyright (C) 2009, Addison Robson LLC

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA	02110-1301, USA.

*/

// read SCOInstanceID from the GET parameters
$SCOInstanceID = $_GET['SCOInstanceID'] * 1;

?>
&lt;html>
&lt;head>
	&lt;title>VS SCORM&lt;/title>
&lt;/head>
&lt;frameset
  frameborder="0"
  framespacing="0"
  border="0"
  rows="100,*"
  cols="*"
  onbeforeunload="API.LMSFinish('');"
  onunload="API.LMSFinish('');">
	&lt;frame src="api.php?SCOInstanceID=&lt;?php print $SCOInstanceID; ?>" name="API">
	&lt;frame src="... location of the course ..." name="course">
&lt;/frameset>
&lt;/html></pre>
<p>In lines 40 and 41 of the listing above, you&#8217;ll see that I&#8217;ve arranged for the LMSFinish() function to be called directly when the frameset tries to close down. I&#8217;m now going to change this by making the frameset call a Javascript function called unloadSCO() which, in turn, calls LMSFinish() after a delay. I&#8217;ve also taken the opportunity to re-name the frame from &#8216;course&#8217; to &#8216;SCO&#8217; to make the SCORM purists happy!</p>
<pre class="brush:php; first-line: 1; html-script: false;">&lt;?php 

/*

VS SCORM 1.2 RTE - rte.php
Rev XXXXXXXXXXX was 2009-11-30-01
Copyright (C) 2010, Addison Robson LLC

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA	02110-1301, USA.

*/

// read SCOInstanceID from the GET parameters
$SCOInstanceID = $_GET['SCOInstanceID'] * 1;

?>
&lt;html>
&lt;head>
	&lt;title>VS SCORM&lt;/title>
	&lt;script language="javascript">
		function unloadSCO() {
			setTimeout('API.LMSFinish("");',2000);
		}
	&lt;/script>
&lt;/head>
&lt;frameset
  frameborder="0"
  framespacing="0"
  border="0"
  rows="50,*"
  cols="*"
  onbeforeunload="unloadSCO();"
  onunload="unloadSCO();">
	&lt;frame src="api.php?SCOInstanceID=&lt;?php print $SCOInstanceID; ?>" name="API" id="API" noresize">
	&lt;frame src="... location of the course ..." name="SCO" id="SCO">
&lt;/frameset>
&lt;/html></pre>
<p>I now try it again, and it works! The students can write notes and they&#8217;re successfully saved to the database when the course closes. </p>
<p>But that&#8217;s not the end of things &#8230; </p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/07/11/step-53-delaying-the-closing-sequence/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Step 52 &#8211; cmi.comments and cmi.comments_from_lms</title>
		<link>http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/</link>
		<comments>http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/#comments</comments>
		<pubDate>Sat, 10 Jul 2010 00:33:24 +0000</pubDate>
		<dc:creator>Steve Addison</dc:creator>
				<category><![CDATA[Run Time Environment]]></category>

		<guid isPermaLink="false">http://www.vsscorm.net/?p=1500</guid>
		<description><![CDATA[A reader recently contacted me with a problem that raised some interesting issues. Hopefully, we&#8217;ve now resolved the problem but, since the issues might well occur with other SCOs, what I&#8217;d like to do is to walk through the process &#8230; <a href="http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A reader recently contacted me with a problem that raised some interesting issues. Hopefully, we&#8217;ve now resolved the problem but, since the issues might well occur with other SCOs, what I&#8217;d like to do is to walk through the process and show how the VSSCORM RTE has to be modified to deal with this situation.</p>
<p>Here&#8217;s what was happening. The SCO in question was a technical training course &#8211; the subject is unimportant &#8211; and it ran OK except for one problem. The SCO author(s) had very helpfully provided a small text area on the SCO screens where a student could write notes and have them saved between sessions &#8211; in effect, online &#8216;PostIt&#8217; notes. The problem was that the notes weren&#8217;t being saved to the database when the SCO was closed.</p>
<p><span id="more-1500"></span></p>
<p>After digging around in the code, it became obvious that the SCO was storing all of the notes on the client side while the SCO was running &#8211; probably in a cookie, or maybe in a Javascript variable &#8211; until the SCO window was closed at which point it attempted to save them to the LMS database. Here&#8217;s the Javascript from the SCO (not the RTE) that seems to be failing.</p>
<pre class="brush:javascript; first-line: 1">function getCommentsData() {
  return scormGetValue("cmi.comments");
}

function setCommentsData(sSuspend) {
  scormSetValue("cmi.comments", sSuspend+"");
}</pre>
<p>The first thing that to note is that the SCO is using the (optional) <b>cmi.comments</b> data element rather than the (mandatory) <b>cmi.suspend_data</b> element. And, to be fair, that&#8217;s what the <b>cmi.comments</b> data element is provided for.</p>
<p><a href="http://www.vsscorm.net/wp-content/uploads/2010/07/cmi_comments.jpg"><img src="http://www.vsscorm.net/wp-content/uploads/2010/07/cmi_comments.jpg" alt="" title="cmi_comments" width="555" height="219" class="aligncenter size-full wp-image-1521" /></a></p>
<p><center><a href="/docs/SCORM_1.2_RunTimeEnv.pdf" target="_blank">SCORM 1.2 RTE Specification</a> &#8211; Page 3-35</center></p>
<p>So, as the first step in trying to fix the problem, I&#8217;m going to add the optional element <b>cmi.comments</b> and, while I&#8217;m at it, the related data element <b>cmi.comments_from_lms</b>.</p>
<p><a href="http://www.vsscorm.net/wp-content/uploads/2010/07/cmi_comments_from_lms.jpg"><img src="http://www.vsscorm.net/wp-content/uploads/2010/07/cmi_comments_from_lms.jpg" alt="" title="cmi_comments_from_lms" width="554" height="207" class="aligncenter size-full wp-image-1528" /></a></p>
<p><center><a href="/docs/SCORM_1.2_RunTimeEnv.pdf" target="_blank">SCORM 1.2 RTE Specification</a> &#8211; Page 3-36</center></p>
<p>I&#8217;m going to start with the LMSSetValue() function in the api.php file where I have to declare the <b>cmi.comments</b> data element as writeable (line 14):</p>
<pre class="brush:javascript; first-line: 1">function LMSSetValue(varname,varvalue) {

  // not initialized or already finished
  if ((! flagInitialized) || (flagFinished)) { return "false"; }

  // is this a writeable data element?
  if (
    (varname=='cmi.core.lesson_location') ||
    (varname=='cmi.core.lesson_status') ||
    (varname=='cmi.core.exit') ||
    (varname=='cmi.core.session_time') ||
    (varname=='cmi.core.score.raw') ||
    (varname=='cmi.core.suspend_data') ||
    (varname=='cmi.comments')
  ) {

    // set the requested data, and return success value
    cache[varname] = varvalue;
    return "true";

  }

  // not a writeable data element
  else {

    // return failure value
    return "false";

  }

}</pre>
<p>Note that I don&#8217;t have to do anything with the <b>cmi.comments_from_lms</b> data element since it&#8217;s read-only. Now, in the LMSCommit() function, I make a corresponding change to add <b>cmi.comments</b> to the data being transferred to the LMS (line 24):</p>
<pre class="brush:javascript; first-line: 1">function LMSCommit(dummyString) {

  // not initialized or already finished
  if ((! flagInitialized) || (flagFinished)) { return "false"; }

  // create request object
  var req = createRequest();

  // code to prevent caching
  var d = new Date();

  // set up request parameters - uses POST method
  req.open('POST','commit.php',false);

  // create a POST-formatted list of cached data elements
  // include only SCO-writeable data elements
  var params = 'SCOInstanceID=<?php print $SCOInstanceID; ?>&#038;code='+d.getTime();
  params += "&#038;data[cmi.core.lesson_location]="+urlencode(cache['cmi.core.lesson_location']);
  params += "&#038;data[cmi.core.lesson_status]="+urlencode(cache['cmi.core.lesson_status']);
  params += "&#038;data[cmi.core.exit]="+urlencode(cache['cmi.core.exit']);
  params += "&#038;data[cmi.core.session_time]="+urlencode(cache['cmi.core.session_time']);
  params += "&#038;data[cmi.core.score.raw]="+urlencode(cache['cmi.core.score.raw']);
  params += "&#038;data[cmi.suspend_data]="+urlencode(cache['cmi.suspend_data']);
  params += "&#038;data[cmi.comments]="+urlencode(cache['cmi.comments']);

  // request headers
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  req.setRequestHeader("Content-length", params.length);
  req.setRequestHeader("Connection", "close");

  // submit to the server for processing
  req.send(params);

  // process returned data - error condition
  if (req.status != 200) {
    alert('Problem with AJAX Request in LMSCommit()');
    return "false";
  }

  // process returned data - OK
  else {
    return "true";
  }

}</pre>
<p>Now to look at subs.php where I need to add both of these elements to the list so that they&#8217;re initialized when the SCO first starts. Pretty simple &#8211; I add the following lines to the initializeSCO() function (omitting most of the other lines for clarity):</p>
<pre class="brush:php; first-line: 1; html-script: false">function initializeSCO() {

  ...
  ...

  // comments
  initializeElement('cmi.comments','');
  initializeElement('cmi.comments_from_lms',getFromLMS('cmi.comments_from_lms'));

  ...
  ...

}</pre>
<p><b>cmi.comments</b> starts out as an empty string, but the <b>cmi.comments_from_lms</b> data element needs to be initialized with a value from the LMS. So my final task is to change the getFromLMS() function:</p>
<pre class="brush:php; first-line: 1">function getFromLMS($varname) {

  switch ($varname) {

    ...
    ...

    case 'cmi.comments_from_lms':
      $varvalue = "";
      break;

    ...
    ...

  }

  return $varvalue;

}</pre>
<p>Now, I&#8217;ve added the new data elements and I run the SCO again. No good &#8211; the problem is still there. There must be another problem that I haven&#8217;t spotted.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vsscorm.net/2010/07/09/step-52-cmi-comments-and-cmi-comments_from_lms/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

