The EnterPage 17-01
April 29, 2014

In this issue:

Platte Canyon's First Windows Store Application: Music Genius™

Mobile and Application Store Partnering Opportunities

Please consider voting for Tracker.Net™, Exam Engine™, and Training Studio® in Best of Elearning! 2014 Ballot

New ToolBook LinkedIn Group

New Tracker.Net and Exam Engine/Training Studio LinkedIn Groups

Tribute to My Dad

Programming for e-Learning Developers Segment

Expert Information from Learning & Mastering ToolBook

OpenScript Tip from Learning & Mastering ToolBook

Web Hint from Learning & Mastering ToolBook

JavaScript Tip


Welcome to the first EnterPage Newsletter of the year. We've been heads-down for many months working on our first Windows Store application as covered in our first article. Look for iOS (Apple) and Android versions later this year. We also have information on new LinkedIn groups, a tribute to Jeff's Dad, and the normal ration of Programming for e-Learning Developers tips on ToolBook and JavaScript.

Platte Canyon's First Windows Store Application: Music Genius™

We are excited to announce Platte Canyon's first Windows Store application: Music Genius™ (Trivia Powered By Exam Engine™). This FREE application gives you a random set of 20 questions per category, which include years (1950's - 2010's), type of music (American Rock, Country, Pop, etc.), and specific groups (Beatles, Eagles, etc.). You can optionally store your information in order to compare your scores to others. There are over 3,500 questions and counting, so keep trying over and over. You are allowed 20 seconds per question.

Music Genius is current available only on the Windows 8 Store, but look for versions for Windows Mobile, iOS (iPhone and iPad), and Android in the future.

Information and Download

Mobile and Application Store Partnering Opportunities

We would like to leverage the technology of Music Genius™ and create similar testing applications that would prepare professionals for all types of certifications and exams. If you have a database of questions that you would like to make into a mobile and store application, please email us so we can talk about working together.

Email Us

Music Genius™ Information and Download

Please consider voting for Tracker.Net™, Exam Engine™, and Training Studio® in Best of Elearning! 2014 Ballot


With your help last year, Exam Engine™ received a "Best of Elearning! Award of Excellence. Please consider voting for our products again for the Best of Elearning! 2014 ballot. Here is the link:!_Awards_2014.html

For each, the Company is Platte Canyon Multimedia Software Corporation.

Our entries are:

2. Best Learning Management System (Enterprise-based, behind the firewall): Tracker.Net

12. Best E-Learning Development Tool: Training Studio. If you don't use Training Studio and use ToolBook, please give it some love instead.

17. Best Testing & Assessment Tool: Exam Engine

Thanks for your help!!

New ToolBook LinkedIn Group

Due to problems with the hosting company's server, we had to move the ToolBook List from a Listserv to an iMail List. This made us lose our archives. In addition, the new server has had various issues being blocked by Yahoo and AT&T. We'd thus like to move the independent community of ToolBook developers to a LinkedIn Group. We have named it "Learning & Mastering ToolBook" as we have the trademark on that name, but it is open to all ToolBook developers for any topic. We will keep the current list open as long as possible, but the hosting company could cease operations at any time. PG Software Development also has a ToolBook forum that is a good place to visit. We have included links for both groups below.

Learning & Mastering ToolBook Support Group

PG Software Tools ToolBook Forum

New Tracker.Net and Exam Engine/Training Studio LinkedIn Groups

While we were creating LinkedIn Groups, we added one for Tracker.Net and a combined one for Exam Engine and Training Studio developers. If you use these products, we encourage you to join.

Tracker.Net Support Group

Exam Engine & Training Studio Support Group

Tribute to My Dad

By Jeff Rhodes, Platte Canyon Multimedia Software Corporation

I don't normally include personal items in this newsletter, but I'll make an exception for my Dad, Brigadier General (retired) James M. Rhodes, Jr. Dad passed away on December 8, 2013 after a struggle with cancer. His funeral with full military honors was at the Air Force Academy here in Colorado Springs this past Friday (April 25, 2014). The local paper (The Gazette) and a local television station (KRDO) did outstanding tributes to him. I have included links below.

Gazette Article

KRDO Video

We will miss you Dad!

Programming for e-Learning Developers Segment

This feature is a short segment from Jeff's Programming for e-Learning Developers book.

Creating an Interactive "Rollover" Screen

Let's make an interactive screen where the names of Beatles albums are listed down the left side. When the user rolls her mouse over the names, they change color and a graphic of the album cover is displayed on the right side of the screen. We'll also include a track list from . Album names that have been "rolled over" will be shown in a third color so that the user can tell which ones she has already completed. Finally, we will display a message when all of the rollovers have been completed. This is a pretty realistic interactive training screen and will introduce us to a number of important concepts.

ToolBook – OpenScript
I assembled the graphics as .png files and created fields along the left with the titles of the albums. The names of these fields are "album 1" through "album 5." You might be wondering why I put a space between the base (album) and the number. Unlike some of the other environments, ToolBook allows this. The advantage comes when it is time to "parse" the number from the name. With OpenScript, we can use syntax like this: word 2 of name of target. The space between the base and the number is what separates word 1 from word 2. This keeps us from running into problems when we get to album 11. In environments that don't allow spaces in object names, I'll put an _ instead and use some kind of split method for the same reason. You will see that in later examples.

I imported the graphics as resources and gave them matching names. Finally, I went to and grabbed the track listing for each album and put them in fields named "field 1" through "field 5." I hid these fields as we are going to read their text (technically their richText so that we preserve any formatting) and show them in a common "display field." I like this technique because it avoids the need to reposition all the fields if we show and hide them in turn. Our design is then that we'll show the album cover in a button and set this display field to be the track listing in response to the mouseEnter event, which is what ToolBook calls a rollover.

We are now ready to do some programming. Let's start with the mouseEnter script shown below. We put this script at the page level so that we can write one mouseEnter handler for all five album name fields.

to handle mouseEnter
	system lastFieldId
	system stack completedInteractionList
	system dword numInteractions
	local string tarName
	local string tarNum
	local field fieldId
	tarName = name of target
	if word 1 of tarName = "album"
		tarNum = word 2 of tarName
		fieldId = field "display field"
		richText of fieldId = richText of field ("field " & tarNum)
		normalGraphic of button "albumImage" = bitmap ("album " & tarNum)
		strokeColor of target = blue
		sysCursor = 19 -- pen
		if lastFieldId <> null
			strokeColor of lastFieldId = 120,25.125,100 -- dark green
		end if
		lastFieldId = target
		-- check for completion
		if ASYM_ItemInList(tarNum, completedInteractionList) = False 
			push tarNum onto completedInteractionList
		end if
		if itemCount(completedInteractionList) >= numInteractions
			richText of fieldId = "COMPLETED: " & richText of fieldId
		end if
	end if
end mouseEnter

We have lots of good programming concepts to discuss in this script. The first is a global variable, which we might define as some data that needs to survive beyond the life of the current handler or function. In OpenScript, we declare a global variable with the word system in front of it. In most cases, we want to declare a type as well. We do this so that the environment will help us if we do something dumb like try to assign "Joe" to a variable that is supposed to be a number. So the line system dword numInteractions means a global variable of type dword (positive integer) of the name numInteractions. In the mouseEnter script, we need three global variables:

1. A reference to the "previous" field that we entered. To understand this, we need to think through the set of events. The user will move his mouse into "Rubber Soul." At that point, we want to turn it blue. He then moves the mouse into "Help." We then turn "Help" blue to denote that it is the current item. We want to turn "Rubber Soul" green to show that we have already visited it. To do that, we need to remember which field we were in last. That is why we have lastFieldId. We don't declare a datatype in this case because OpenScript is flexible enough to make it a field reference when we are using it but then allow us to set it to null when entering the page. If we type the variable, ToolBook would give us an error when we try to set it to null.

2. In addition to knowing the most recent field that the user entered, we need to keep track of all the fields in order to determine when the user has completed all of them. There are a number of ways we could approach this, but one of the simplest is to have a comma-delimited list of completed interactions (1,3,5 for example). This is a stack data type that we store in the completedInteractionList variable. It again needs to be global since we need to build up this stack interaction by interaction.

3. Finally, we need to know how many interactions there are in order to figure out if we are finished. This doesn't strictly need to be a global variable but we end up using this value in two different handlers (mouseEnter and enterPage). The advantage of a global variable here is that we only have to change the value once if we change the number of interactions.

After the global variables, we have three local variables. This means that they survive only until the end of the handler or function. The tarName variable allows us to avoid having to keep referring to name of target. Similarly, we end up grabbing the interaction number and putting it in the tarNum variable. Finally, we end up referring to our display field several times. It is a good practice to put this object reference in a variable, which we call fieldId. This is a bit more efficient for the program if it doesn't need to keep "resolving" the object reference and gives us a little less code to write.

Let's now look at the logic. We use an if statement to limit our logic only to targets that have as their first word "album." We need to do this since every object on the page will generate the mouseEnter event. Next, we populate our tarNum variable with word 2 of the name (1, 2, etc.). We build our fieldId reference to the display field and then start on the cooler stuff. We set the richText property of the display field to the richText of the corresponding (hidden) field that holds the album information. We use richText instead of text since the former keeps all the formatting such as font size, bold, and italics. After that we set the normalGraphic property of our "albumImage" button to the corresponding bitmap resource. The "normal" comes from the different button states (invert, checked, etc.) that can each have a graphic associated with it. Notice how we use "dynamic object referencing" to move from the name of the object to the field or bitmap object itself. The next line sets the strokeColor (the color of the text) to blue. We then set the sysCursor property to one of its defined values, which corresponds to a graphic that looks like a pen. I like to change the cursor for a mouseEnter interaction as another visual clue to the user that something is happening.

We now use our lastFieldId global variable discussed above. We check to see if it is null (because it won't be defined yet the first time). If not, we set its strokeColor to a dark green. Either way, we set this global variable to the target (e.g., the current field the user is in). That way, we'll set this field to green during the next interaction.

Our last task is to check for completion. We previously defined the completedInteractionList global variable and explained our plan to use it as a comma-delimited list of the interactions the user has completed. One reason to choose this format is that OpenScript has excellent support for "stacks" like this. We first use the built-in
ASYM_ItemInList() method to check if the current tarNum is in our global variable. If not, we push it on the variable, which has the effect of adding both the value and the comma (once there are two or more entries). We then use another built-in method, itemCount, to see if the number of items in the list is greater than or equal to our numInteractions global variable. If so, we update our display field to show "COMPLETED: " at the front. In a real e-Learning application, I would typically change the look of the "Next Page" button or show an animation, but we already have enough complexity in this example! We end by forwarding the mouseEnter message so that higher-level scripts can handle the message if desired.

That script had most of the heavy lifting. The listing below has the "initialization" and "cleanup" scripts.

to handle enterPage
	system lastFieldId
	system dword numInteractions
	system stack completedInteractionList
	numInteractions = 5
	step num from 1 to numInteractions
		strokeColor of field ("album " & num) = 20,30,100 -- dark orange
	end step
	text of field "display field" = ""
	clear normalGraphic of button "albumImage"
	lastFieldId = null
	completedInteractionList = ""
end enterPage

to handle mouseLeave
	local string tarName
	tarName = name of target
	if word 1 of tarName = "album"
		sysCursor = default
	end if
end mouseLeave

The way to look at the enterPage handler is that we want to initialize the page to our desired state. We need to set our global variables so they are defined at the top of the script. We initialize numInteractions and then use our first step loop (a For loop in other programming languages) to set the strokeColor of each of our fields to a dark orange. In a step loop, the variable (num) goes from the initial condition (1) to the final value (numInteractions). The code within the loop runs each time. Notice how many lines of code we save plus get more flexibility to change the number of interactions without adding code by building the name of the field ("album " & num), letting OpenScript build a reference, and setting the color. From there, we clear our display field and "albumImage" button. Finally, we clear our lastFieldId and completedInteractionList variables. It is very important that we forward the enterPage message - lots of other things happen in ToolBook at higher levels in response to this message.

The mouseLeave handler is quite simple. We use the same logic as above to make sure we are only handling the event for our album name fields. If so, we set the sysCursor back to default.

We will cover this example for the ToolBook Actions Editor, Flash, JavaScript, and Silverlight/XAML in future EnterPage editions.

Programming for e-Learning Developers Information

Order Programming for e-Learning Developers ($29.95 with free shipping in the U.S.)

Expert Information from Learning & Mastering ToolBook 

By Tomas Lund, Elearning Specialist

SCORM Completion Status and Success Status

Question: We are running as our LMS and ToolBook. Our courses all have a final quiz that the learner must pass with score of 70%. The LMS tends to mark the course complete even if the learner does not pass the quiz. I am not sure if this is a ToolBook or LMS issue. Anyone have any ideas?

Answer: I've seen this problem before, most often it stems from different LMS implementations and people making assumptions that mix up SCORM completion_status (complete/incomplete) with success_status (Pass/failed). SCORM makes no correlation between completion and passing. In SCORM 2004, it is possible that a course is incomplete and passed, or completed and failed.

SCORM 1.2 only has one field for all values which complicates things a little less.

To fix your problem, you need to set up a scaled passing score in the LMS (i.e., 70%) and then use the Actions Editor to query the LMS for that value. Then based on the score of the user, exit and mark the course as either complete or incomplete as appropriate.

OpenScript Tip from Learning & Mastering ToolBook

By Jeff Rhodes, Platte Canyon Multimedia Software Corporation

Finding Old Hyperlinks

One of the challenges of updating our Learning & Mastering ToolBook product is making sure all the hyperlinks are current. We run the script below via the Command Window. I wrote it to ensure that there were no lingering hyperlinks to the version 9 example files. It uses the getObjectList() function to find any objects with hyperlinks (the _asym_hyperlinks user property not being null) and then checks the appropriate element of the array for the portion of the URL in question. Notice how we start at the current page rather from the beginning of the book to keep from checking pages over and over. Notice also how you need to have a local variable (tempArray in this case) when reading or writing a user property that is an array.
local tempArray[][]
local url

step num from pageNumber of this page to 
	pageCount of this book
	pageId = page num
	objList = getObjectList(pageId, "", 
	while objList <> null
		pop objList into objId
		tempArray = _asym_hyperlinks of objId
		url = tempArray[1][2]
		if url contains "tbcbt9"
			go to pageId
			request objId  && name of objId && "has 
				a hyperlink to tbcbt9"
			break step
		end if
	end while
end step

Web Hint from Learning & Mastering ToolBook

By Peter Jackson,

Preventing the Copying of Text

Question: I have a technical institute using my online courses as "companion" training. That is... the students are still required to complete traditional written assignments. The assignment questions typically start off with the instruction "Explain in your own words..."

The tutors are reporting that the students are simply copying & pasting the text out of my course modules into their assignments, which was predictable I suppose! If I disable a field in properties, it grays out the text. A long shot I suppose, but is there a way around this?

Answer: If you group the field with some other object, even one that is hidden, you can set the property of the group to export as a graphic. Whilst this will absolutely stop the copy/paste, it will not stop the ability to copy (albeit manually) your expert text. BTW you should test the export to ensure that you do not lose quality of the written text in all browsers.

JavaScript Tip

By Jeff Rhodes, Platte Canyon Multimedia Software Corporation

Using JavaScript and jQuery to Configure an Anchor Tag

We recently helped one of our Exam Engine customers with a custom question template. In this template, they wanted to have a smaller version of an image. The user could then click on the smaller image to see a larger version in a popup window. The first task was to add the anchor tag to the HTML as shown below. The new lines are shown in bold.

<a id="questionGraphicLink" target="questionGraphicWindow">
     <img id="questionGraphic" src="" alt="" />

Next, we used the fact that the larger image would match the name of the smaller image except for a _lg at the end of the name. So if the question image were "xyz.png", then the large image would be "xyz_lg.png." We thus added the code below to the function that is called when the page is fully loaded.
// make hyperlink out of questionGraphic
if (questionDictionaryId["QuestionGraphic"] != null) {
    var lgGraphic = questionDictionaryId["QuestionGraphic"].replace(".png", "_lg.png");

    $("#questionGraphicLink").attr("href", ("../media/" + lgGraphic));

The questionDictionaryId JavaScript objects holds all the items for the question. If it has a "QuestionGraphic" item, we put a reference to the large graphic in the lgGraphic local variable. We then use jQuery to find a reference to the questionGraphicLink anchor object. We then set its href attribute to a relative path to that graphic. If the question does not have a graphic, we skip this step and thus avoid any kind of broken links.

The EnterPage is distributed up to four times per year, with occasional special issues. Individuals who have expressed interest in Platte Canyon Multimedia Software Corporation or its products receive The EnterPage. Suggestions for articles or proposals for article submissions are welcome. Send information to Back issues of the EnterPage are available at:

Platte Canyon Multimedia Software Corporation, 8870 Edgefield Drive, Colorado Springs, CO 80920, (719) 548-1110