Day 3 of my #100DaysOfCode
Tags: 100daysofcode, learning, xapi
Published: 2023-01-19 20:40:29

Day 1 of posting here, but Day 3 of my own little #100DaysOfCode challenges.

I realized a couple of days ago that it was 108 days until my birthday, which seemed like a great deadline to do something. While I haven't ever been a developer professionally, I have tinkered here and there, and even done some light Javascript work as it related to Learning and Development, but I always love it when I do get to open up the IDE and hack around in some code until I learn what I was hoping to learn. That's my learning style - hands on. Break it, try to fix it. Want to know if something is possible? Give it a shot and see if you can do it!

So I'm bringing that spirit to these next 100ish days. Now, I'm not going to do a basic #100DaysOfCode - I'm not really going to hone in on any one thing in particular, but I'm going to be attempting a number of experiments and refreshers  that will help me learn to create better and more interactive learning materials!

To recap what I've done in these first two undocumented days, Day 1 I brought an old Node/React project back to life using StackBlitz. I was curious about an online IDE that could compile and launch a whole Node project and I was thoroughly impressed with it. It's a great way to test a github project as you can import it directly from github and it will automatically grab all your modules. Code and view demo in the same browser window. I'm not even joking, you can do the whole thing in minutes. Wild.

Day 2 (yesterday) - I got myself a test LRS set up with SCORM Cloud. If you're not familiar with SCORM Cloud and you work in eLearning, you really should get familiar. Rustici Software makes some really great tools for testing, tracking, and even dispatching eLearning content to outside sources. These tools are available for free for most of the levels you would be testing at, so they're a really user-friendly intro to some really vital concepts. Their LRS is available immediately upon signing up, so I was able to quickly grab an xAPI prototype (a Tetris game that logs high scores), upload it to SCORM Cloud, and capture data like when the game started, who the player was, what levels they reached, and their final score!

Day 2 was fairly simple, but incredibly meaningful. This means we now know that the SCORM Cloud LRS is capably receiving the statements from trusted xAPI content! So if you make content in Storyline or some other authoring tool that can export xAPI projects, all you would need to do is upload that content into SCORM Cloud, and you're good to go.

That brings us to today - Day 3 - and needless to say, the journey's over sooner than expected! 

KIDDING.

Today the goal is to create a site outside of the LMS (SCORM Cloud in this case) that can also send xAPI statements to our LRS, without needing the content to be uploaded to an LMS at all. This would mean that we could begin collecting data on a user before, after, or even during (but still outside of) a course. For the sake of my mad scientist experiment, I'm going to create a page that will send a statement to the LRS when the user presses a button. If it sounds kind of basic, it is - but it's a great starting point to open up your mind on what exactly can be fed into an LRS outside of your old SCORM package. Talk about basic!

Let's get coding! 

Fire up your IDE of choice, and start a project. We're going to first pull in two really key files that you can get from the [xAPI Wrapper on github](https://github.com/adlnet/xAPIWrapper):

- From the /dist folder, grab the file named "xapiwrapper.min.js" and move it into your project folder.


- From the /lib folder, grab the file name "cryptojs_v3.1.2.js" and move it into your project folder as well

If you're doing more than a simple test, or if you just love organizing your files, like me, go ahead and make a js folder for your project and put both of these files into it.

We don't kneed to know a lot about these files for what we're doing so we're not even going to look through them. The "crypto" file is for encrypting your auth, and the "xapiwrapper" file establishes all the behind the scenes stuff we need in order to transmit these statements in the approved xapi format.

Once you have these files in your project, create an html file, give it a name, and save it.

Copy and paste the following code into your page:

```
<!doctype html>
<head>
   <!-- Includes for ADL's xAPI Wrapper -->
   <!-- Download the files from: -->
   <!-- https://github.com/adlnet/xAPIWrapper -->
   <script type="text/javascript" src="./js/cryptojs_v3.1.2.js"></script>
    <script type="text/javascript" src="./js/xapiwrapper.min.js"></script>
    <!------------------------------------->    
    
    <script>
    function send_statement(){
        var conf = {
             "endpoint" : "<endpoint link>",
             "auth" : "Basic " + toBase64("key:secret")
             };

        ADL.XAPIWrapper.changeConfig(conf);
         
        //define the xapi statement being sent
        var statement = {
            "actor": {
                "mbox": "mailto:Tester@example.com",
                "name": "Your Name Here",
                "objectType": "Agent"
            },
            "verb": {
                "id": "http://example.com/xapi/interacted",
                "display": {"en-US": "interacted"}
            },
            "object": {
                "id": "http://example.com/button_example",
                "definition": {
                    "name": {"en-US": "Button example"},
                    "description": {"en-US": "Example xAPI Button"}
                },
                "objectType": "Activity"
            }
        }; //end statement definition
 
        // Dispatch the statement to the LRS
        var result = ADL.XAPIWrapper.sendStatement(statement);
        }
    </script>

</head>

<body>
    <button type="button" onclick="send_statement()">Send Statements</button>
</body>
</html>
```

If you're familiar with HTML/JS, it's a pretty simple page to break down. We start off by making sure the files we downloaded are included:

```
   <!-- Includes for ADL's xAPI Wrapper -->
   <!-- Download the files from: -->
   <!-- https://github.com/adlnet/xAPIWrapper -->
   <script type="text/javascript" src="./js/cryptojs_v3.1.2.js"></script>
    <script type="text/javascript" src="./js/xapiwrapper.min.js"></script>
```

Then we create the sendStatement function, which means we need to tell the function where to send the statements - remember, this isn't being called from the LMS, so this page has no inherent connection to our LMS/LRS unless we create it.

```
        var conf = {
             "endpoint" : "**<endpoint link>**",
             "auth" : "Basic " + toBase64("**key**:**secret**")
             };
```

<endpoint link> should be entirely replaced with just the link to your LRS endpoint, so that line would look like: 

```
"endpoint" : "https://yourendpointlink here",
```

After that, you need to replace the "key" with your Key and "secret" with your secret. These are the terms SCORM Cloud uses for your auth, so if you're using another LRS, this step may be slightly different, but your LRS should provide you with the auth credentials needed here.

If you update these three pieces of information, save your file, and open it up in the browser, you will see a button. Pretty amazing, right?

Click the button, then check your LRS. If you did everything correctly, you should get a statement saying "Your Name Here interacted with 'Button example'" - or - the full statement, which would look like: 

```
{
    "id": "8050cd2d-6762-478a-a8d4-36cc64e91d07",
    "actor": {
        "objectType": "Agent",
        "name": "Your Name Here",
        "mbox": "mailto:Tester@example.com"
    },
    "verb": {
        "id": "http://example.com/xapi/interacted",
        "display": {
            "en-US": "interacted"
        }
    },
    "timestamp": "2023-01-19T16:21:20.341Z",
    "stored": "2023-01-19T16:21:20.341Z",
    "authority": {
        "objectType": "Agent",
        "name": "Unnamed Account",
        "account": {
            "name": "<yourauthkey/username>",
            "homePage": "http://cloud.scorm.com"
        }
    },
    "version": "1.0.0",
    "object": {
        "id": "http://example.com/button_example",
        "definition": {
            "name": {
                "en-US": "Button example"
            },
            "description": {
                "en-US": "Example xAPI Button"
            }
        },
        "objectType": "Activity"
    }
}
```

Check out all that data! With one click of the button, we received a time-stamped entry into our LRS with info on who did what and where. This is now stored in the LRS, and this data can even be retrieved later, meaning we can query our LRS for statements that we need to influence other, separate courses/learning experiences.

For the purposes of my experimenting, I'm going to be using this first page as a way to create the user's permanent learning identifier within our materials, and I know I'm for sure going to want to know their name in other interactions outside of the LMS without them having to enter it each time, so Day 4 is going to be me starting to build the learner profile by setting up a User Registration/Login function which will then set the actor/mbox for future statements. At that point, we will have the ability to log users in from an independent website and create the same user credentials as they would by starting an xAPI course through an LMS.

Questions? Reach out!