Showing posts with label remote-learner. Show all posts
Showing posts with label remote-learner. Show all posts

Friday, May 19, 2017

Things I learned upgrading to Moodle 3.3

As the Moodle 3.3 launch approached, I decided to check on a few of my plugins and ensure they were ready for 3.3.

The good news is that having had everything pretty much up to 3.2 standards, the effort to reach 3.3 was minimal. In fact, with the two plugins I worked on for the coveted "Early bird 3.3" award, questionnaire module and oembed filter, I could have submitted them as is and they would have passed fine. But, that's not my way, and besides, it would have made this post even shorter than it is.

For the questionnaire module, I first installed the 3.2 version on a new Moodle 3.3 test site, and ran the unit tests and Behat tests. Having automated testing is a great way to manage upgrading, as these tests will hopefully uncover any problems introduced by the Moodle upgrade or by any changes made to the plugin for the new version. In the questionnaire case, I had made a number of improvements to the code, continuing my efforts of paying down "technical debt" and making the code easier to maintain going forward.

The unit tests ran fine, but the Behat tests failed. Additionally, there were messages being kicked out by the developer level debugging.

There were two issues in Behat  I needed to fix. The first is a change to the Behat tests in Moodle 3.3. Where previously a step would say:
'And I follow "Course 1"' 
For 3.3, they need to say:
'And I am on "Course 1" course homepage'
This is due to the new course dashboard introduced in 3.3 that replaces some of the navigation in 3.2.

The other issue I needed to change was places that would say:
'I navigate to "Questions" node in "Questionnaire administration"'
Now need to say:
'I navigate to "Questions" in current page administration'
This was actually a change in 3.2 that didn't affect me until 3.3. I believe I was supposed to have made the change in 3.2, but now it is mandatory.

Making those changes fixed the Behat errors.

The debugging warning I was getting was:
pix_url is deprecated. Use image_url for images and pix_icon for icons.
    line 267 of /lib/outputrenderers.php: call to debugging()
    line 182 of /mod/questionnaire/classes/questions_form.php: call to renderer_base->pix_url()
    line 204 of /lib/formslib.php: call to mod_questionnaire_questions_form->definition()
    line 32 of /mod/questionnaire/classes/questions_form.php: call to moodleform->__construct()
    line 153 of /mod/questionnaire/questions.php: call to mod_questionnaire_questions_form->__construct()
This is telling me that places I am using the function pix_url will eventually (in some future release) fail. And they should be replaced with either pix_icon or image_url. For my case, image_url is the easiest and correct fix. The previous function, pix_url, returned an URL to be used in the output. The new function, image_url, likewise returns an URL. The new function pix_icon returns the entire line of code including the image tags. Using it would require a significant amount or re-coding, and in reality, I am not using icons.

Once I have completed those changes, everything seems fine with questionnaire.

For the Oembed filter, I ran into Behat issues caused by the HTML that is output with 3.3. There has been changes made to some of the core editing features, that changed the xpath layout for the Oembed editing page. As such, I was getting an error like:
001 Scenario: Admin user carries out various provider management tasks. # /Users/mikechurchward/www/moodlehq.git/filter/oembed/tests/behat/management.feature:26
      And the provider "Vimeo" is disabled                              # /Users/mikechurchward/www/moodlehq.git/filter/oembed/tests/behat/management.feature:36
        The "//td/a[text()='Vimeo']/parent::td/div/a[contains(@class,'filter-oembed-visibility')]/i[@title='Show']" element does not exist and should exist (Behat\Mink\Exception\ExpectationException)
The Behat tests for the filter had a custom test called "the_provider_is_disabled" which depended on a specific xpath output that was now no longer happening. This required me to rewrite the Behat function to change the xpath definition to reflect the new output. Manual testing of the function proved that the actual functionality had not been broken, and once the new xpath definition was in place, the Behat tests passed as well.

And that was it. Both plugins were ready for 3.3 and made it in time to get the early bird award. As I continue with other plugins, I will document any new changes required by 3.3 I find in new posts.

Friday, April 21, 2017

Add mobile support to your Moodle plugin - part four

Part Four - Adding More Services

In the previous part of this series, I modified my mobile addon so that clicking on a plugin instance loaded and displayed a "Hello World!" screen. Now, I will add some services so that it will retrieve the number of responses made to the particular questionnaire and display them, when a user clicks on an instance. I'm also going to add a link handler, that will handle the questionnaire when it is selected by a link in other site content.

First, I'm going to add the link function. In all of the other addons I've looked at, a handler was defined for links. In the moodle.org forum, I asked about this, and learned that it was so the mobile plugin was handled properly if it was reached from a link other than the course instance.

Adding the link function is apparently very easy now. The latest release of the mobile app has a simplified handler function that manages the links for me. I really just have to add one line to my main.js file and one line to my services/handlers.js file, as follows:

main.js:
.config(function($mmCourseDelegateProvider, $mmContentLinksDelegateProvider) {    $mmCourseDelegateProvider.registerContentHandler( 'mmaModQuestionnaire', 'questionnaire', '$mmaModQuestionnaireHandlers.courseContent');    $mmContentLinksDelegateProvider.registerLinkHandler( 'mmaModQuestionnaire', '$mmaModQuestionnaireHandlers.linksHandler');
services/handlers.js:
self.linksHandler = $mmContentLinksHelper.createModuleIndexLinkHandler( 'mmaModQuestionnaire', 'questionnaire', $mmaModQuestionnaire);
Now, when I create a link in my course that goes to a questionnaire instance, instead of launching in the browser, it uses the questionnaire mobile plugin.

In the last iteration, I left the isPluginEnabled function in a state where it always returned true. Now, I need to make it do something that actually checks with the site to see if the plugin really is enabled. This will require changing this function in the mobile plugin, and adding a web service to the questionnaire module.

Both the certificate and feedback call the 'mod_[pluginname]_get_[pluginname]_by_courses' web service, so I'll start there. Note that feedback also calls mod_feedback_get_feedback service, but I'll look at that later.

Starting with the mobile plugin, I'll update the services/questionnaire.js::isPluginEnabled function as follows:
self.isPluginEnabled = function(siteId) {
    siteId = siteId || $mmSite.getId();
 
    return $mmSitesManager.getSite(siteId).then(function(site) {
        return site.wsAvailable( 'mod_questionnaire_get_questionnaires_by_courses');
    });
};
What this code does, is verify that the questionnaire module is enabled on the Moodle site by checking for the availability of the web service, mod_quesrionnaire_get_questionnaire_by_courses, on the Moodle site. This means I will need to create that web service in the main questionnaire activity plugin. For this one, I am going to copy from the certificate module, but simplify it down for now to only provide the basic module information and only check for 'view' capabilities.

To add the web service to my module, I do the following:

Add the necessary external services to the classes/external.php file:

This requires creating the file with the external class extending the core external_api class in the mod_questionnaire namespace. In that class, I need to add the function for get_questionnaires_by_courses as well as two other helper functions, get_questionnaires_by_courses_parameters and get_questionnaires_by_courses_returns. These three functions are required to fully define the web service as described in the web services developer documentation.

It is the job of this function to return result information for all questionnaire instances in the identified courses. You can see the full code for this here.

Add the db/services.php file to define the services available by web services:

Web services need to be described in this file. When a plugin is installed or upgraded, the Moodle system uses this file to add the services described in this file to its known, available services. This is more fully described here. Once the Moodle site knows about them, it can allow them to be used by external systems.

Since I already have the questionnaire module installed on my Moodle site, I will need to bump up the version number in my version.php file, to trigger a module upgrade, and get the Moodle site to load my new web service. Once I have done this, I should be able to see that my new service has been installed by going to my site's admin/webservice/service_functions.php screen and looking for the web service there. I upgrade my site with new version and check for the service on the admin screen. Successfully, I see the following:


Since I'm writing web services, I might as well create one that provides some meaningful information from the Moodle site that I can display in my mobile plugin.

Currently, when I click on a questionnaire in the mobile app, I just get the "Hello World!" screen. I am going to modify it so that it tells me how many responses I have made to that instance. To do that, I will need a web service in the Moodle plugin to provide that information back to the mobile plugin.

Back at my db/services.php file, I define a new service called 'mod_questionnaire_get_user_responses' and define it as a service that returns 'a count of the current user responses'.

Then, I code the new service in my classes/external.php file. Its a simple function, that simply returns the count of responses for the user / questionnaire instance in question.

Lastly, I perform a version bump to force an upgrade and verify that the service has been added to the Moodle site:


Now, I need to modify the mobile plugin to use this new service and display the information appropriately. Starting with templates/index.html file, I modify so that it will display a count of the user's responses:
<ion-view>
    <ion-nav-title>{{ title }}</ion-nav-title>
    <ion-content padding="true" mm-state-class>
        <mm-course-mod-description description="description"></mm-course-mod-description>
        {{mymessage}}<br />
        You have {{responses}} responses.
    </ion-content>
</ion-view>
The template will look for a value in the {{responses}} tag, which means I need to add code to the controllers/index.js file to populate that. The code includes a function that uses the promise mechanism to add the response count to the template scope variable, and a helper function to call the plugin service function, $mmaModQuestionnaire.getUserResponses located in services/questionnaire.js.

In the services/questionnaire.js file, I add the code that will call the new web service I created in the Moodle plugin. This is the part that will actually call the site service and extract the response information. The actual call to the web service is in this line:
return $mmSite.read('mod_questionnaire_get_user_responses', params, preSets).then(function(response) {
This should be all I need to change the behaviour of the questionnaire module in the mobile app, so that it will also show me the number of responses.

With my new code added to the mobile plugin, and the new services added to the Moodle module, I need to verify that I can still access the questionnaire in the mobile app, and that I can see the number of responses.

I ramp up my mobile app, click the questionnaire instance, and achieve success:


I still have a lot of work ahead of me to make my questionnaire plugin functional in the mobile app, but I at least now have a good working understanding of what needs to be done, how to use web services, and how to make them useful in the mobile plugin. I will get back to this (eventually), and document my learnings in future posts.

Wednesday, June 3, 2015

UK Moodlemoot 2015 - Thoughts on Community and Openness

Two weeks ago, I attended the UK Moodlemoot in Dublin. This was around the twelfth Moodlemoot I have participated in, most of which I have actively presented in as well as attended. I always find the Moots’ spirit of community so energizing, and this one was no exception.

Attending a Moodlemoot gets me back in the community and its sub-communities - developers, educators, users and partners. It reminds me why I do what I do, and makes me happy to be part of the engine that makes Moodle go. A Moot is a reunion of sorts, where I connect with people who I see “virtually” every week, but only physically meet with in geographically far-off places every couple of years. And as a reunion, it makes me review my history.

I began my Moodle connection in 2003, with my first “moodle.org” post on November 27, 2003 contributing my ideas for “Moodle groups” that was being worked on for Moodle 1.1. That same discussion included three colleagues who went on to start their own Moodle Partner businesses - Sean Keogh, Bryan Williams and Tom Murdock. Eventually, Sean, Bryan and I merged our three Moodle Partner companies into one. Tom Murdock co-founded Moodlerooms, which just recently acquired our UK division. Sean and I were both there at the recent Moot.

In February 2004, I released my first module - questionnaire. Questionnaire remains one of the top plugin downloads in the Moodle plugin database, usually sitting in second or third spot.

in June of 2005, I attended my first MoodleMoot at what was then the Governor Dummer Academy near Boston. There I met Martin Dougiamas for the first time in person, as well as Michelle Moore, who I would later work with as well. Both were there at the Moot.

Over the next decade, I continued Moodle development, formed my own Moodle Partner company, attended and presented many more Moots, attended various developer conferences and hackfests, wrote a book on Moodle plugin development and I believe contributed to Moodle’s success. Some of the developers I’ve attended the developer gatherings with were there as well: Dan Poltawski, David Mudrak, Davo Smith, Bas Brands among others.

Now, arriving at Dublin for the 2015 UK Moot, I still found myself amazed by the spirit of collaboration this experiment of Martin Dougiamas has created. I was there to present our latest releases of plug-ins designed to help Office365 users integrate with Moodle, and front a workshop to help learn how to setup and use these plugins. The workshop was attended by new faces as well as known collaborators. When I ran into trouble, someone in the room was there to help me out. I received valuable feedback that will go back into the plugin development.

Likewise the various sessions demonstrated the Moodle community energy. No presenter felt alone, and I think all left with as many new ideas as they provided. You just know, more good ideas will end up available to us all as a result. I personally, have already contacted a couple of the presenters to see if I can get more involved in their projects.

And of course the impromptu meetups in the social times generated many great discussions on Moodle, learning and the industry in general. Many of these went well into the night and well into the Guinness kegs. My personal discussions involved educators, Moodle users and administrators, developers and other partners. I found all of these talks led to positive ideas of how we can improve Moodle, learning and our “product”.

My hats off to Gavin Henrick, another colleague and past co-worker, for organizing a successful Moot that so celebrated and promoted the spirit of openness the Moodle community brings. I love being a part of this community and its innovative energy. Looking forward to the next one.

Tuesday, April 7, 2015

Office 365 Moodle Integration Project - New and Improved

Since we released the O365 integration plug-ins back in January, there has been a lot of community pick-up and feedback. We have responded with a number of improvements. This article will focus on the most noticeable surrounding the O365 single-sign-on and account connection.

The original release of the O365 plug-ins required users who wanted to use the O365 OneDrive and Outlook Calendar Moodle integrations to change their Moodle account authentication scheme to the OpenID Connect using Office 365’s AAD system. Any new Moodle account had to be created and managed from the Office 365 AAD system as well. To login, a user had to use the separate “OpenID Connect” login button on the Moodle login page.

This system worked well for new Moodle installations, where the user management system had not been established, and was therefore easy to select the OpenID Connect/AAD authentication system for their user system. But for established Moodle sites, where other user management and authentication systems were well established, this proved to be a barrier to using the O365 integrations.

Further, some Moodle sites that did want to use the OpenID Connect/AAD system for Moodle authentication, didn’t want their users to look for a separate login button on the Moodle login page, but to continue to use the standard Moodle login form.

I’ll deal with the second problem first.

As originally released, to login via O365, you had to use a separate button on the login page, like below:


However, Moodle is built such that authentication plug-ins can use the standard login form, if they choose to do so. For this case, we built in the ability for Moodle to pass the entered username and password to the OpenID Connect provider, and log the user in to both O365/AAD and Moodle at the same time, in the background. In order to facilitate this, we provided an extra configuration option:


As shown, the second radio button turns off the need to use the separate OpenID Connect login button, and allows the standard Moodle login form to function with OpenID Connect. If you select the first radio button, the login will work as it did before, and require the user to login using the external provider.

One other addition we added was the ability to select an icon for use on the login button, or upload a custom icon for the same use. This allows the OpenID Connect login button to have an icon more suited to the organization, if they choose not to show the Microsoft Office icon.

For the account connection problem, we approached it in a unique way. As the account connection mechanism existed, sites that wanted their users to take advantage of the O365 integrations required that the Moodle logins be managed from O365/AAD as well. The plug-ins provided an easy mechanism to connect existing Moodle accounts to existing O365 accounts, and then switch those users to the O365/AAD login, but that was a permanent change. And sites with many users, already have well-established user management and login systems that they use with Moodle.

To solve that problem, we provided a mechanism that allows users to either switch to using the O365 login (as before), or connect their current Moodle account to an O365 account and continue to login to Moodle as they did before. This mechanism is contained in the user profile plug-ins accessed from a user's Moodle profile page, as so:


In this shot, you can see two Office365 links: 
  • Office365 Connection: You are not connected to Office 365. Connect to Office 365
  • Office365: You are not using Office365 to log in. Start using Office365 to log in.
Either of these links takes you to the new O365 management page, which provides links to each function as so:


The first function on this page, "Start using Office365 to log into Moodle", works the same as the first release. If you click that link, you will be redirected to your Office365 login page to login to O365/AAD. If you login with a valid AAD account that has not already been connected to a Moodle account, your Moodle account will then be reconfigured to use AAD as the authentication scheme. Once that has been done, you will always need to login to Moodle using the AAD account information.

The second function in this page, "Connect to Office365", is the new function. If you click that link, you will be likewise redirected to your Office365 login page. If you login with a valid AAD account that has not already been connected to a Moodle account, your Moodle account will be configured to be connected to that O365 account. What that means, is that you will continue to login to Moodle in the same way you always have, but when you access any of the O365 Moodle integrations, your O365 account will automatically be used. You won't need to login twice once the connection has been made.

This second feature was one that was most asked for. This feature allows Moodle sites that cannot change their Moodle authentication schemes to still take advantage of the full O365 integrations.

One feature that has also remained is the automatic account creation. If a user that does not exist yet in Moodle, logs into a Moodle site that has the OpenID Connect O365/AAD authentication plug-in enabled, and the account information they use is a valid AAD account, they will be logged in and a new Moodle account created for them.

We have a number of other improvements and new features coming in future releases. Look to future blog posts describing these.

Monday, January 19, 2015

Office 365 Moodle Integration Project - Released!

This will be a short post, just to let everyone know that our first release of the Office 365 plug-ins are now available to the community.

Earlier today, Jean Paoli, president of MS Open Tech announced the official release of the code at the BETT show in London. This announcement coincided with the opening of the Githib repositories to the public and the submissions to the Moodle Plugins database.

I have posted an announcement in the Moodle "General plugins" forum, and more discussion can happen there. There will also be tracker items set up in the Moodle tracker to get feature and improvement requests, and deal with bugs.

You can get the plugins from the Moodle plugins database as follows:

The current work for each has been gathered in one Github repository called "o365-moodle", but each plug-in has a current release repository of its own. The "readme" file in the "o365-moodle" repository has references for each release repository.

Start playing!

If you want any more information on how you can benefit from these developments, contact Remote-Learner at moodleo365@remote-learner.net.

Thursday, January 8, 2015

Office 365 Moodle Integration Project - OneDrive

Our initial work with Microsoft Open Technologies has progressed, and we now have an integration with OneDrive for Business. In this post, I will describe and provide brief demos of how Moodle and OneDrive for Business can work together.

At its basic level, the OneDrive for Business integration is a repository plug-in. It is built to work closely with the OpenID Connect authentication plug-in that provides the Office 365 account connection. It provides two levels of repositories to every user. It provides access to each user's private files area, and it provides access to a course shared area for every course a user is enrolled in.

I'll start by looking at the personal space. Below is a screen capture of the Moodle file picker using the Office 365 OneDrive repository.


What I can see here are two folders in OneDrive. The "My Files" folder is my personal space in the OneDrive for Business application. The "Courses" folder contains subfolders for each of the Moodle courses I have access to. "My Files" displays all of the files and directories I have in my OneDrive for Business folder. The image below shows the contents in the Moodle file picker.


Looking at my OneDrive interface, I see a similar structure as below.


Note that the folder structure and contents mirrors what I saw in Moodle. If I add or change the contents of my OneDrive folder, it will likewise  be reflected in the Moodle file picker. This is what we expect from a Moodle repository plug-in. :)

If I add files to my OneDrive, I will see them when I look at "My Files" in the Moodle Office 365 OneDrive "My Files" area. Likewise, if I upload a file from Moodle into the "My Files" area, I will see it in my OneDrive folder. In the Moodle file picker image of "My Files" above, note the "Upload New File" control. Using that, I can select a file from my local machine, and upload it directly into my OneDrive folder via Moodle, where it will be available to both OneDrive and my Moodle files.

The "Courses" folder also uses my Office 365 account. It provides course-level shared access to files for all of the Moodle courses on the site that I have access to. A separate folder is created for each course, using the Moodle course names. To do this, Office 365 for Business uses Sharepoint, and specifically, Sharepoint sites. Below are two images showing the same course level directory on Moodle and on Sharepoint (OneDrive).



The integration uses Moodle capabilities to control access to the files in both Moodle and Sharepoint/OneDrive. By default, the teacher roles in a course are given read and write access to the course folder, while students are given read only. Moodle synchronizes these access permissions to Sharepoint to control it in the Office 365 realm as well.

Showing the path through Office 365 to the Moodle course files is difficult with screen snaps, so instead, below I have included a small video showing the path through to the course files.


We're very close to releasing all of this work to the community at large. And we're very excited to find out how its received. In future posts, I will discuss the technical solutions underneath the hood in more detail.

If you want any more information on how you can benefit from these developments, contact Remote-Learner at moodleo365@remote-learner.net.

Wednesday, December 17, 2014

Office 365 Moodle Integration Project - Progress

Along with the OneNote integration, discussed in my last post, the work with Microsoft Open Technologies has also produced two integrations with Office 365. The first is an integration with Outlook calendars and the second is a OneDrive for Business integration. In this post, I will describe and provide brief demos of the Outlook calendar integration.

The Outlook calendar synchronization allows Moodle calendar events to be synchronized back to your Outlook calendar. If you are someone who uses an Outlook calendar as a key tool, I think you will find this very useful.

This particular functionality has been built to use Office 365 for Business, meaning that it expects everyone on the site to have an Office 365 for Business account. Users without these accounts will not be able to synchronize to their Outlook calendars.

The function will allow Moodle users to connect their personal Moodle calendar, and any course calendars they have access to. To set up the calendars to connect, a local plug-in has been created. As well, a user profile field plug-in has been provided that can be added to each user's profile, providing access to the calendar sync configuration page.

Once I have logged into Moodle with my Office 365 AzureAD account, I will be able to access these functions. Looking at my profile, I will see two Office 365 functions: "AzureAD" and "Office365 Connection". The next image shows this screen:


Clicking through the "Manage" function for the "Office365 Connection", I get to the "Outlook Calendar Sync" page. This is where I can select the specific Moodle event types I want to synchronize back to Outlook:


Once I have selected my calendars, any changes to those Moodle event types will be reflected in my Outlook calendar as well. In this case, I will see any personal Moodle events and any Moodle events from the "Moodle Integration Project" course.


In the above image, there are two events in my course Moodle calendar. On the 14th, there is a personal event, and on the 16th a course event. We can see the details of the course event in the image. When I look over at my Outlook calendar, I see the same two events:


In my next post, I will discuss the OneDrive for Business integration. It takes advantage of Sharepoint to allow shared course directories as well.

If you want any more information on how you can benefit from these developments, contact Remote-Learner at moodleo365@remote-learner.net.

Friday, December 5, 2014

OneNote Moodle Integration Project - Progress



In my last post, I started talking about the work we are doing with Microsoft Open Technologies to create integrations with Moodle and a number of Microsoft technologies and applications. That work has progressed quickly, and we are now testing our first efforts. In this post, I will describe where we are with the OneNote / Moodle integration.

The work so far is focused on providing access to OneNote's notebook pages as repository selections and as assignment plug-ins. The current work has been done for the free, OneNote for Consumer application. In future phases, the commercial OneNote plug-in will also be added.

For the assignment plug-in, the key goal is to allow Moodle assignments to be created in OneNote, using any and all of OneNote's content features. Then, once the student feels their assignment is done, they simply need to click the Moodle assignment's "submit" button, and the student's Moodle assignment submission will be automatically associated with the OneNote page they worked on in OneNote. No downloading and uploading required. No conversion into Moodle compatible content required.

An additional feature developed allows the instructor to provide feedback to the provided submission using OneNote.

To get these features working correctly, a number of problems had to solved:
  • Establish a defined, secure connection between the OneNote application and the Moodle site.
  • Establish a defined, secure connection between each user's Moodle account and their OneNote account.
  • Connect a specific OneNote page in a user's OneNote account with a specific Moodle assignment submission.
  • Connect a specific OneNote page in an instructor's OneNote account with a specific Moodle assignment submission's feedback response.
  • Ensure that a specific submission can be "frozen" at the time of submittal, so that any changes that occur afterward can be prevented or allowed but visible.

I'll describe the approach taken for each problem.

A Moodle local plug-in establishes a secure connection between the specific Moodle site's instance of the Microsoft plug-ins and the Microsoft API's for OneNote. The plug-in works with Microsoft's "Live App management site" (https://account.live.com/developers/applications) to establish unique identifier and secret codes that ensure communication between the Moodle site and the OneNote API's are for the intended purpose. The connections are managed using OAuth 2.


This is set up by a Moodle administrator and configured into the plug-in as above.

A Moodle user can establish a connection to their OneNote account in several ways. In each case, the connection is live for the duration of the Moodle session, but is lost when the Moodle session is complete. Each time a user logs back into the Moodle site, the user will need to login to the OneNote account as well.

The OneNote account connection can be established by accessing the repository plug-in, by using the OneNote block or by using the sign-in button on the assignment plug-in. Using any of these options logs the user in for all OneNote plug-ins for that Moodle session.



The assignment submission plug-in allows the specific assignment to connect to a OneNote page for each user's submission. Once a user has logged into their Microsoft account, the assignment will offer a "Work on this" in OneNote button. Clicking this button will open the OneNote web application in a new browser tab, logged into the user's account.



If the OneNote page has not already been created (if this is the first time the user has opened this assignment), a new page will be created in a section for the Moodle course in a notebook for the Moodle site. Each of these will be created as necessary. Each book/section/page is given a name according to the Moodle site, course name, assignment name, user name and action (submission, feedback). These names are important, but data references are also kept in Moodle to keep the associations.



A user can then work on their OneNote assignment in any of the OneNote applications - web based, desktop application or mobile. When the user is happy with the assignment, in Moodle, they simply need to click the "Save changes" for their OneNote assignment submission. Doing this, records the submission in Moodle, provides a direct link to the OneNote page for the user and the instructors and uploads a zipped submission of the page in HTML format to the Moodle course assignment. This upload provides a snapshot in time of when the assignment was submitted, helping to control what was submitted with any changes made to the page after submittal.



On the instructor side of things, the student's submission is available to be reviewed in OneNote, reviewed as submitted zipped HTML pages and for feedback in OneNote. When the instructor opens the students OneNote submission in OneNote, that page is copied into the instructor's course section in their site notebook with a name identifying the assignment and the student. If the instructor elects to offer feedback using OneNote, a new page will be created in the instructor's notebook containing the content of the submission, allowing the instructor to provide feedback inline in the content. That feedback page will likewise be available to the student, by copying it into the student's notebook when the access it.



We are currently running this work through closed beta-testing, and it will available for more general beta testing in the new year. I think this add-on will be a very useful addition to the Moodle landscape, and look forward to seeing what people can do with it.

If you want any more information on how you can benefit from these developments, contact Remote-Learner at moodleo365@remote-learner.net.

Monday, October 27, 2014

OneNote, the Surface and Moodle

I recently (through my company, Remote-Learner) became involved in a partnership project with Microsoft Open Technologies. This project has the ambitious goal of providing tighter integration of a variety of new Microsoft products with Moodle. I'm very excited about this.

The products we are focusing on initially include OneDrive, OneNote, Outlook Calendar and the various pieces these integrations will support, such as the Office 365 applications and Azure Active Directory.

For me, this meant getting myself reacquainted with Microsoft technology and systems. I chose to buy a new Surface Pro 3 running Windows 8.

The Surface is an interesting device. From my perspective, it’s a tablet that tries to be a laptop when you want it to be. But in my experience so far, I like it far better as a tablet. And for me, the killer app is OneNote on the Surface.

If you are not familiar with OneNote (I wasn't), it has been around for a lot longer than you think - since at least 2003. If you're familiar with Evernote, its a very similar application. To put it simply, it is your collection of notebooks, available to you on all your devices. You organize each notebook into sections, and add pages to the sections. Pages can include your created notes, media, clipped information from the web and photos you take on the device. Kind of a notebook / scrapbook hybrid.

OneNote is integrated pretty tightly with the Surface. It comes pre-installed as a Surface app, meaning it works well with the tablet interface of Windows 8 and the Surface stylus. The stylus allows you to call up OneNote with a click of the button on the end (like clicking a ballpoint pen), and then write your note using handwriting, on the open page. For myself, I have really gravitated to using the stylus and OneNote to take quick notes, in the same way I used to use a pen and a pad of paper. And if you upgrade to OneNote 2013, you can use the "Ink-to-text" feature to turn your handwriting into a digital text document.

Marking up existing documents in OneNote is a great feature. For example, you can import a PowerPoint slide into a note, and then mark it up with your comments and drawings (if you use the stylus). Likewise with a clipped web page. And add-ons like Office Lens, let you use your device camera as a scanner, capturing notes on paper or whiteboards directly into your OneNote notebook. And you can then mark them up as needed. In fact (I haven't tried this yet), I believe you could even capture audio markup and place it in the page (I will try this and confirm in a later post).

You can share your notebooks with other collaborators, via email addresses. People you share with don't even need the OneNote app; they can use OneNote on the web as a web-based application. The OneNote notebooks and their content are all stored in the OneDrive cloud, making them available to any connected device.

Prior to using OneNote with my Surface, I was unsure what an integration of OneNote with Moodle would be good for, or how it would be useful. Now I really want to make this happen.

From a learning system standpoint, consider the markup and collaboration. As a Moodle assignment, OneNote could be submitted for grading. If the OneNote interface was used by all participants, teachers could mark up the submission directly on the pages. And, as a collaborative assignment, multiple users could work on the submission contributing and marking up existing content before submitting.

And that is where we have our focus right now. In the works are integrations to allow OneNote to become an assignment type. To be fair, OneNote can be used to create assignment documents to be submitted by upload to Moodle right now. OneNote allows the exporting of its notes as PDF's, Word docs or as single web pages. But we want to make it work without that extra step.

So, for the next little while, we will be working with the Microsoft Open Technologies group to build out the necessary Moodle pieces. As a start, these will include:

  • SSO with Azure Active Directory - necessary to make the account access between Moodle and the cloud seamless for the user.
  • OneNote and OneDrive repository plugins - give easy access to document in OneDrive and specific parts of OneNote.
  • OneNote assignment plugins.
I will post regular updates to our progress along with my thoughts and experiences with the technologies and how they can be further used with Moodle and the learning environment.

Watch this space for more information on what's coming and how you can be involved.

Friday, April 11, 2014

Chromecast - What have we got here?

Starting out

I'll be honest, I wanted to try the Chromecast out primarily to see how it would work as an entertainment piece at home, but I am curious to see if it has other potential applications for presentation in business and education. I already have a 1st gen AppleTV that has been jailbroken so it can run XBMC, and a Raspberry Pi that can run XBMC but this little dongle for $39 piqued my curiosity. Can it replace all of that and provide a highly accessible streaming point for any media source? If it can, and is as portable as it appears, it could be a device that sits in the classroom and any place where collaborative presentation can happen.

Setting up

To start, I can see that Google has taken a page from Apple's book and created attractive, fun-to-open packaging. The box is much heavier than expected, but I now see the weight is primarily the box; the device and adapter are as light as I expected.


The instructions were simple; there are three of them detailed on the inner box lid:

  1. Plug into TV & power.
  2. Switch TV input.
  3. Set it up at chromecast.com/setup.

And, it really was that simple. I plugged the dongle into the side HDMI port on my TV, plugged the power into the wall (turns out I could actually just plug the USB end of the power into the available USB port on my TV; I'll do that later), switched the TV to HDMI4, and I'm looking at a Chromecast setup screen:


The website link takes you to a download link to get the app you need to set it up. You can also download this app on any Android and iOS device. The only thing this app is needed for is to set it up and configure it later.

I used the app on my Nexus 7 Android tablet. The app found the new Chromecast device right away, and I had to enter the code it displayed on the TV to verify the connection. The only other things I had to do were change the name of the device if I wanted to (I did), and give it my WiFi password. After that, everything was automatic. A couple of automatic updates and a reboot later and it was up and running. I don't think it could be much easier.

Time to play:

I had the advantage of a room full of people when I first started it up. We had several devices and systems, Android and iOS. Each of us looked at our Youtube apps, and there was a new icon. This icon was similar to the Airplay icon on iOS devices, and selecting it allowed us to choose the new Chromeplayer device as output. Again, this was available on an Android phone and tablet, as well as an iOS phone and tablet, without doing anything to those devices first. The one exception was an iPhone in the group that had not been regularly updated. But, a quick App Store update to the Youtube app, and it too could use Chromecast.

Sticking with Youtube, we each were able to target a video play to the Chromecast. It is interesting to note that the way this works with Chromecast is not what I originally thought. When you play, you are not streaming the content from your device to the Chromecast. Instead, you are telling the Chromecast Youtube app to play the content you requested. In that sense, each of us is using a remote control. It also means that any device can request the play and then carry on doing anything else (I didn't check if I could power down, but I suspect not).

Testing other apps, all of the devices could similarly use Netflix, Vevo and Songza. The Android devices could also use Google Play Music and Google Play Movie. I believe the Google Play apps may allow streaming from the device but I have not verified that. The native music player on the iOS devices could not select the Chromeplayer however.

While playing with the Youtube app, we all discovered that the app on our device would show us what was playing on the Chromecast device, regardless of whether we were the ones who played it or not. We then realized that there was an "add to queue" option instead of "play". This allowed each of us to add a video to the playlist and not stop the one that was already playing. The queue was similarly visible to all of us. We quickly set the ground rules that no video (music only) could be aborted or removed from the queue without two thirds vote. And we each began to plan the music.

The queueing feature seemed to be Youtube specific, and did not exist on the Vevo app. I think this feature would be one that would be copied by many other Chromecast apps. It would be really interesting if it could become a standard part of the Chromecast itself, allowing all types of play requests to be queued.

Observations

We were all pretty excited about being able to queue up videos on the Youtube app, but we also would have liked to be able to send anything we had - music, videos and photos. It would also be good to have a "mirroring" option like with Airplay. These might exist, or might be in development. I still need to do a lot more looking and playing.

The fact that the basic functions were simply "there" for everyone without having to do anything was huge. Since the device is so portable, this makes it something that can be carried with you to other locations and easily used. All you need is an HDMI device, WiFi and power.

Looking ahead

The entertainment value of the device was very obvious. But to be true to my subject, could this be used for any kind of learning environment?

I think, this could be huge if it can just fill in the gaps. It has the ability to be a collaborative presentation tool replacing projectors, cameras, laptops, etc. Every person has a controller, a recorder, a camera and a media library. And they can all present to the common screen.

Why this can be huge, and some other things that are needed...

  1. Be completely cross platform. Out of the box, its pretty close. If it could allow direct streaming from all platforms as well, this would be a slam dunk. Cross platform would also make this a far better option than Airplay on Apple TV.
  2. The price point is amazing. $39 in Canada. This falls into just about everyone's budget. The more people who buy this and play with it, the more clever people will come up with great applications.
  3. It needs to be able to mirror the device screen. Airplay on iPhones and iPads can do this. Consider the power of using your device as a live camera in a walk around the room way. Consider the power of demonstrating your work.
  4. The collaborative queueing feature in Youtube gives a hint as to how this could be used in an active, exciting way. Imagine collaborative groups getting their items into the play queue, and then have feedback/voting actions on the queue. Queueing and queue control at the device level would be very interesting.
The best part of this is that any of these outstanding needs could be filled by the community of app creators. I think I need to go learn app development.


I'll post again about this when I see or learn more.

Saturday, March 16, 2013

Setting up a Moodle Development Environment on a Mac

Having been an Ubuntu user for years, I am switching my main computer to a new Macbook Pro. This means that I now need to change the way I do things, and learn how to set up a Mac to be a developer station. So, here I go...

To begin with, I consulted with my colleagues +Justin Filip and +Amy Groshek, both Moodle developers and both power Mac users. They both pointed me to MacPorts as a starting point. Amy further advised me that although OSX comes preinstalled with PHP and Apache, I probably want to replace them both with MacPorts versions of the software. An opinion shared by a blog post Amy shared with me on setting PHP up using MacPorts. I'm going to use that blog post, and the MacPorts installation page to start my setup.

Now, one thing I need to be careful with is that this blog post is for up to version Lion. I'm running version Mountain Lion; so there may be some differences.

...and the first thing I run into is those differences...

The blog post tells me to turn off Apache:
"go to System Preferences, type Apache in it’s spotlight. It will highlight Sharing, but you just need to press return. Just make sure Web Sharing is disabled."
Unfortunately, "Apache" turns up nothing. And accessing "Sharing" direct doesn't offer "Web Sharing". I do a search for "Mountain Lion" and "Apache", and turn up several articles describing how to enable Apache in the absence of the "Web Sharing" option. It turns out that Apache is disabled by default with OS-X Mountain Lion. I'm guessing, I can skip this step.

The next thing I am asked to do is to install Xcode. This should be available in the Mac App Store, so I'm going to check there first. Searching for 'xcode' in the App Store I immediately find it. It defines itself as "everything developers need to create great applications for Mac...". Checking the "Installing MacPorts" page on the MacPorts site, the "Xcode" requirement is confirmed. So, I install it from the App Store.

Next, the MacPorts site is telling me I need to have the Command Line Developer Tools. The instructions say they can be installed from within Xcode 4, which I just installed. I find Xcode in my Applications folder and run it. It takes me through more installation steps, and then allows me to start it. According to the information on that page, simply running and accepting the license should be enough. But I find another page that points me to the "Preferences -> Downloads" section where I need to install the "Command Line Tools".

Next, both sites tell me to install MacPorts by downloading the dmg from the site. I think I'll follow that advice. The download runs me through a standard installation process, and I choose the standard method. It all seems to install just fine.

Having done that, I move on to installing MySQL. The blog post I'm reading recommends installing the MySQL server installation using MacPorts. After reading others, I decide to do just that. The recommended commands are:
sudo port install mysql5-server -- installs all necessary software
sudo port load mysql5-server -- configures MySQL to start at bootup
sudo -u _mysql mysql_install_db5 -- sets up necessary database tables
/opt/local/lib/mysql5/bin/mysqladmin -u root password 'new-password' -- sets a root password 
Next, I will install PHP, Apache and some required libraries.
sudo port install php5 +apache2 +pear +fastcgi php5-mysql +mysqlnd -- installs all necessary software
sudo port load apache2 -- configures PHP to start at bootup 
Then I will configure PHP with development settings:
cd /opt/local/etc/php5/
sudo cp php.ini-development php.ini
 
And enable it in Apache:
cd /opt/local/apache2/modules
sudo /opt/local/apache2/bin/apxs -a -e -n "php5" libphp5.so 
Next, I can change where my Apache sites will run from. By default, they are in "/opt/local/apache2/htdocs", but I want them to be in subdirectory off my home. To do this, I edit the "/opt/local/apache2/conf/httpd.conf", and change the two lines below as follows:
DocumentRoot "/opt/local/apache2/htdocs"
to
DocumentRoot "/Users/mikechurchward/www"
and
<Directory  "/opt/local/apache2/htdocs">
and
<Directory "/Users/mikechurchward/www">
This allows me too store my web, and PHP files in my home directory. Some other changes in that file:
<IfModule dir_module>    DirectoryIndex index.html index.php</IfModule>
AddType application/x-httpd-php .phpAddType application/x-httpd-php-source .phps
This should give me everything to run web and PHP.

Now, I reboot my computer and try to access a web page on my machine. It works.

Next, I need git. This looks like an easy task for MacPorts. A quick search concludes that "git-core" is what I should need, so I issue the command:
sudo port install git-core +bash_completion
This installs git-core as well as a variant known as bash_completion, which will allow the "tab" key to help complete git commands.

Now I use git to checkout a Moodle installation, and it works!

So, I will now navigate to my new Moodle codebase, and:
Moodle requires the iconv PHP extension. Please install or enable the iconv extension.
Okay. So I need to add more PHP extensions. Luckily, Moodle documents what I need.

To add the iconv extension, I enter:
sudo port install php5-iconv
then restart Apache:
sudo /opt/local/apache2/bin/apachectl restart
Once more to the site and I actually move on the installation page!

To make my life easier, I think I will add phpMyAdmin before moving on.
sudo port install phpmyadmin
Then, since I have moved my webroot, I move it:
sudo mv /opt/local/www/phpmyadmin ~/www/
Then reconfigure it with:
cd /opt/local/www/phpmyadmin/sudo
cp config.sample.inc.php config.inc.php
 
$cfg['Servers'][$i]['auth_type']     = 'config';    // Authentication method (config, http or cookie based)?
$cfg['Servers'][$i]['user']          = 'root';      // MySQL user
$cfg['Servers'][$i]['password']      = '';          // MySQL password (only needed with 'config' auth_type)
When I try to run it, I get an error about socket connections not working. After a bit of research, I come up with this:
Create /opt/local/etc/mysql5/my.cnf, add the following to it and save    [mysqld_safe] socket = /tmp/mysql.sock
...and...
Also to remain compatible with other programs that may have been coded to look for the socket file in its original location then add this symbolic link:
    sudo ln -s /opt/local/var/run/mysql5/mysqld.sock /tmp/mysql.sock
That gets phpMyAdmin running. Now onto install Moodle.

I step through the initial steps of Moodle until I hit the "Server checks" page. This page tells me exactly what other PHP extensions I'm missing.
sudo port install php5-curl
sudo port install php5-openssl
sudo port install php5-xmlrpc
sudo port install php5-soap
sudo port install php5-intl
And reload the page. Success. The installation continues, and runs successfully.

I now have most everything I need... But I still need an IDE.

I've been an Eclipse IDE user for a very long time, but both +Amy Groshek and +Justin Filip are telling me that Sublime Text 2 is the way to go, so I'm going to see what its like. Now, to install and use it, I'm just going to use Stuart Herbert's page. No need to recreate that here.

So, at this point, I have a fully working development environment for Moodle working on my Macbook Pro. I'm sure I'll need more as I go along, but this is a good starting point.

Friday, November 9, 2012

Adding Moodle 1.9 Block Restore to Moodle 2.3 - Part 6

In my last post, I had managed to get a working system that would successfully convert blocks in a 1.9 backup file to a Moodle 2.3 restore. I need to do a bit more testing, and then look for a solution for blocks that have specific backup/restore needs.

Testing uncovered that trying to restore a 1.9 course that had multiple versions of the same block installed within it (such as multiple HTML blocks) would cause an error, indicating that a file already existed. Referring back to the new code, this is likely due to the new process_block() function. In that function, a new XML file is created using the name of the block. This means that if more than one of the same block is converted, the code would try and create more than one file with the same name. I need to change that code to make sure it creates a unique file name in this situation.

I change the code:
$this->open_xml_writer("course/blocks/{$data['name']}/block.xml");
...
$this->open_xml_writer("course/blocks/{$data['name']}/inforef.xml");
...
$this->open_xml_writer("course/blocks/{$data['name']}/roles.xml");
to:
$this->open_xml_writer("course/blocks/{$data['name']}_{$instanceid}/block.xml");
...
$this->open_xml_writer("course/blocks/{$data['name']}_{$instanceid}/inforef.xml");
...
$this->open_xml_writer("course/blocks/{$data['name']}_{$instanceid}/roles.xml");
By adding $instanceid to the file path, I guarantee that each XML file will have a unique name. A quick test proves that this is now working.

The next issue to tackle is what to do with blocks that have their own backup/restore needs. The one Moodle 2 block that seems to have this requirement is the block rss_client. It will need its own backup converter.

In the tracker Paul Nicholls started to tackle this by creating a new "blocks/rss_client/backup/moodle1/lib.php" file with an extended class. When he tested the first version, a bug was discovered in my moodle1_handlers_factory::get_plugin_handlers() function changes. If a block does have its own class extended, the file containing it is not included, meaning that the handler class is unknown and an error occurs during the conversion process. Paul has also provided a fix for this error using his own git repository. To fix my copy, I will use the power of git collaboration.

First, I need to be able to pull code from Paul's repository into my local one. I have already made this possible by adding his repository as a remote named "pauln" to my local one. The commit that fixes the code is identified, so I cherry-pick it into my repository with:
git fetch pauln
git cherry-pick 630756fe1063e96cc7a6057bd512aa4afa53bc61

This modifies the code from:
if ($type != "block") {
    if (!file_exists($handlerfile)) {
        continue;
    }
    require_once($handlerfile);
} else {
    if (!file_exists($handlerfile)) {
        $handlerclass = "moodle1_block_generic_handler";
    }
}
to:
if (file_exists($handlerfile)) {
    require_once($handlerfile);
} elseif ($type == 'block') {
    $handlerclass = "moodle1_block_generic_handler";
} else {
    continue;
}
Paul has also provided a new version of the rss_client block with the new handlers. Again, I cherry-pick using:
git cherry-pick d89ade28060ae858356ff4a42cf946a4c99878c0
This provides me with a working copy of the conversion code that will correctly add the extra functionality that the Moodle 2.3 rss_client block requires.

For the record, here is the code for the rss_client conversion handler:
class moodle1_block_rss_client_handler extends moodle1_block_handler {
    public function process_block(array $data) {
        parent::process_block($data);
        $instanceid = $data['id'];
        $contextid = $this->converter->get_contextid(CONTEXT_BLOCK, $data['id']);

        // Moodle 1.9 backups do not include sufficient data to restore feeds, so we need an empty shell rss_client.xml
        // for the restore process to find
        $this->open_xml_writer("course/blocks/{$data['name']}_{$instanceid}/rss_client.xml");
        $this->xmlwriter->begin_tag('block', array('id' => $instanceid, 'contextid' => $contextid, 'blockname' => 'rss_client'));
        $this->xmlwriter->begin_tag('rss_client', array('id' => $instanceid));
        $this->xmlwriter->full_tag('feeds', '');
        $this->xmlwriter->end_tag('rss_client');
        $this->xmlwriter->end_tag('block');
        $this->close_xml_writer();

        return $data;
    }
}
I don't think that this handler will be typical of 1.9 blocks that need to restore their own data though. As it turns out, although the rss_client block does store its own data (feed definitions) in its own table, the 1.9 code never backed that data up. So all 1.9 backups contain only the standard block information for these blocks. But, in Moodle 2.3, the restore operation expects that the feed definition data will be there, and if its not included (even empty) then it causes an error. To work around this, the conversion handler creates an empty version of the expected feed definition XML file for all 1.9 conversions. I will do an extra post later to show how a block that really has extra data would provide the correct conversion code.

There are no other core Moodle blocks that require any specific restore conversion code, so I am essentially done the coding that is required by the tracker issue. Next, I'm going to ready the code for use by the HQ integrators and complete the tracker data so that they can consider it for inclusion into core.

First things I need to do is make sure my git repo is in a good state. To start with, I will make sure that the main branch of Moodle my development branch was based off of is up to date with the latest upstream Moodle code:
git checkout MOODLE_23_STABLE
git fetch upstream
git pull upstream
git push origin MOODLE_23_STABLE
This part isn't necessary, but I want to make my development branch's name a little more manageable, so I rename my MOODLE_23_STABLE_MDL-32880 branch to MDL-32880_2.3. This is purely for optics.

Now, I want to compress all of the work I have done on this issue into one commit. This makes for easier documentation and understanding, since several of my commits were code tests that were later undone. The "rebase" function of git allows me to do this. From the branch MDL-32880_2.3, I issue the command:
git rebase -i MOODLE_23_STABLE
This command will merge all of my commits with the base branch specified, keeping them in my branch, but allowing me to compress some things. The "-i" portion stands for "interactive" and brings up an editor screen that allows me to change what happens:
pick 00cab4e MDL-32880 - Playing with ideas.
pick c7849a8 MDL-32880 - Playing with more ideas.
pick 5036ed8 MDL-32880: moodle1 backup converter: add basic block handler
pick b346f7e MDL-32880 - Adding generic block conversion handlers.
pick 6a3045e MDL-32880 - Named block XML file with instance, and corrected use of currentmod to currentblock.
pick 7b9e3ec MDL-32880: moodle1 backup converter: Include custom block handers if present
pick 6fbf1fb MDL-32880: Add moodle1 backup converter for rss_client block.
pick 1012e75 MDL-32880 - Trying to use convert API in specific block instance.
pick 0b86f82 Revert "MDL-32880 - Trying to use convert API in specific block instance."

# Rebase ce44bf4..2bf7777 onto ce44bf4
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
This screen shows all of my commits in my development branch with "pick" and their information next to them. I want to compress all of these changes into one commit, so I change all but the first "pick" to "squash", and save the edits. Once I do this, I have told git to combine and merge all of the commits into one diff commit. The next thing git does is allow me to create a new commit message for the new combined commit, which I simplify to:
"MDL-32880 - Adding 1.9 block conversion to M2 restore."

Now my MDL-32880_2.3 development branch is up to date with the main Moodle code, and contains just one committed change containing all of the necessary changes for the block restore conversion. This will make it easier for others to review and include in their testing.

The last things that need to be done in order to have this considered for inclusion into core is to complete the rest of the tracker information. Refer to the tacker item MDL-32880 once again to see the results. In this case, Paul has completed all of the necessary information which includes:
  • Testing instructions: Specific step-by-step instructions on how to verify that the code will do what it says. Paul has also attached a 1.9 backup file containing all core blocks.
  • Pull from Repository: Git repository containing the new code.
  • Pull X.X Branch: The name of the branch in the repository containing the code for the specified "X.X" version. For mine, it would be "MDL-32880_2.3".
  • Pull X.X Diff URL: A link to the repository that specifies a "diff" between the codebase and the changes, so that reviewer can see a compare view. This is made easy in github, using the "branches" tab and selecting your base branch from the drop-down, and the selecting the specific branch to compare against. For mine, it produces this link: https://github.com/mchurchward/moodle/compare/MOODLE_23_STABLE...MDL-32880_2.3
 I will continue this series next by providing an example of a 1.9 block that does convert its own data.