DevLearn 2009 Recap

(Okay, I admit it… this post is WAY overdue.)

Let me begin by saying this is not a rant, but rather an honest account of my impressions regarding this year’s DevLearn.

Nearly two months have passed, and when I think of DevLearn I think of two things: Social media gone wild, and hallway conversations.

Social Media Gone Wild

DevLearn 2009 was absolutely wonderful if you’re into incorporating social media into e-learning. Or should I say “using social media for learning,” without the “e.”

Unfortunately for me, I’m not really interested in using social media for learning. I mean, I learn via social media all the time — Twitter and RSS feeds are a raging river of information flooding my head with ideas every day. But when it comes to creating e-learning projects at work, we’re not ready for social media. It doesn’t really have a place in our plans yet, and we’re A-OK with that.

So upon attending DevLearn, you can guess how dismayed I was about the lack of breadth regarding session topics… it seemed as though every other session was about social media. Perhaps the conference should have been named SoMeLearn.

I believe this was my fourth DevLearn conference — I live nearby so it’s not difficult to attend — and I’d have to say this one felt the lightest when it came to the Dev part of DevLearn. There were so few hands-on technical sessions that I had a hard time finding them. I know I’m not the only person who felt this way, as a number of folks confided similar sentiments. Chad Udell, one of this year’s presenters (probably the best technical session I attended) had [link no longer available]:

[T]he conference wasn’t all rainbows and unicorns for me. There are some real underlying problems I have with the conference’s overwhelming love affair with Social Media or Web 2.0 or whatever you may want to call it. […] Do we really need 5-6 sessions about “Leveraging Twitter in your Learning Organization”? […] Given that Mark Oehlert so masterfully managed the Social Learning Jam as a dedicated area for discussion about using Social Media for learning in the eneterprise, it seems a tad silly to have so many concurrent session on the topic.

I may be cast out by talking so candidly about this, but here’s the crux of it for me: If the conference really is called “DevLearn” shouldn’t their (sic) be more “Dev” in the schedule?

I wholeheartedly agree, Chad. I have nothing against social media and finding its place in learning, but did it have to steal so much focus from other areas? Despite my MA in education, I consider myself a developer first and foremost. I like to get my hands dirty. I want more “developy”-type sessions, especially considering the price of the conference. This is meant to be constructive criticism… hopefully next year DevLearn will have a more rounded/balanced session lineup.

Hallway Conversations

Returning to the positives, it was wonderful to meet so many people in person. I’ve “known” many people via Twitter and the blogosphere for quite some time, but it’s a real trip to meet these folks in person. Janet Clarey had a nice post about it (great to meet you, fellow introvert!). In fact, if there was anything about Devlearn 2009 that really stood out for me, it was how great the hallway conversations (and after-parties) were.

Gary Hegenbart said it nicely in his DevLearn recap:

Almost everyone I met included their Twitter name as part of the introductions. […] Twitter accelerated the conversation because if you just met someone you follow or who follows you, then you already knew a lot about the person.  It felt like a reunion and conversation flowed easily and freely.

It was absolutely awesome to finally meet The Beard (aka Aaron Silvers) in person, even if we never really found much time to chat. (Does this guy command a crowd or what? I should start calling him “The Mayor.”) And it goes without saying that if Brian Dusablon and Steve Howard are in the house, we have to hit a pub for a beer and a chat! In my case a Coke since I had to commute an hour by car. Sad, I know.

I learned firsthand that (Mark Oehlert + Kris Rockwell + Koreen Olbrish) === instant mischief. This time it was zombie mischief. LETSI’s Avron Barr was there, and I had the pleasure of driving Mike Rustici to the airport (sorry if I scared you with my crazy driving!). I could go on and on. I’m something of an introvert, so I may not have seemed very excited, but trust me, it was fun.

Following BJ Schone’s footsteps, here’s a list of tweeps I chatted with (apologies if I left you off the list, it wasn’t intentional):

The pipwerks forum is dead, long live the new eLearning Technology and Development Google Group!

A year ago this week, I launched the not-for-profit and ad-free pipwerks E-Learning Development Forum. It was mostly intended to be a way for me to answer questions about some of my projects, such as the SCORM API wrapper, SCORM ActionScript classes, and my many Captivate hacks. The forum wasn’t a vanity project so much as an attempt to avoid email… I’d rather post answers online where everyone can see them than reply to individual emails. I had also hoped other people in the e-learning community would get involved and ask/answer questions beyond the scope of my pipwerks projects.

Now that a year has passed, I decided to step back and evaluate the success of the forum. The numbers aren’t bad: over 200 members, over 550 posts. Of course, it isn’t about the numbers, but about helping people; I’d like to think that most of those 200 people found the answers they were looking for. This is great, and makes me happy. If I helped even one person, the forum can be considered a success.

However, I also noticed a considerable lack of participation from others. Aside from a few helpful folks, I wound up answering most of the questions myself. This means it wasn’t so much a forum as an “Ask Philip” column. Not exactly what I had in mind.

When combined with the effort it takes to maintain a website (security patches, compatibility issues, styling, etc.), the forum started to feel more like a weight on my shoulders than anything else. So, as of today, I have closed down the forum and moved over to a Google Group: the eLearning Technology and Development group.

I’ve been using Google Groups for over a year with the SWFObject Google Group and Aaron Silvers’ Flash For Learning Google Group (no longer online). It isn’t a perfect system, but I’ve learned to enjoy its simplicity. It’s also free and relieves me of administrative hassles such as applying updates and backing up data. Sweet. Plus you can use Google Groups via email, which means you never even need to visit the site. Bonus.

I’d like to say thank you to all the people who posted in the pipwerks forum, and invite you to join me in the new eLearning Technology and Development group.

I’d also like to ask anyone and everyone who develops e-learning to drop by and sign up for the eLearning Technology and Development group. Ask questions — lots of questions — and let’s see if we can get a good community going!

PS: If you’re wondering why I bothered creating a new group considering there are many other discussions groups/forums out there, the answer is simple: no product favoritism and no advertising. Product forums by vendors such as Adobe and Articulate are focused solely on their products, while bulletin boards by organizations such as the eLearning Guild tend to have a ton of ads and a focus on their events and sponsors. I’d like less clutter in my life, and a simple Google Group (even with the AdSense ads) is a nice clean way to handle discussions. Hope you agree!

IFrames and cross-domain security, part 2

Update 10/2010: A new working example with cleaned up code is available.

About six weeks ago, I wrote a post about some issues I was encountering with iframes and cross-domain security. I promised I would write about whatever workaround I decided to use; this post details that workaround. Warning: it feels more complicated than it is, and may take a while to get your head around. Once you get the gist of it, it’s actually a pretty straightforward system.

The problem

Recap of the issue

  1. I have a JavaScript-powered HTML course interface residing in our learning management system at domain A. For the purposes of this post, let’s call this domain myLMS.com.
  2. The course interface loads content stored on a website at domain B, which is a completely unrelated website and not a subdomain of domain A. Let’s call this site content.org.
  3. The interface loads the external content into an iframe; this content includes course activities that must send a completion notice to the interface.
  4. Since the content is from an external domain, JavaScript communication between the iframe and the parent frame is explicitly forbidden, meaning the content can never send the completion notice to the parent frame.

Illustration of iframe communication with parent frame

Example scenario

  1. The interface at myLMS.com loads a JavaScript-powered quiz question from content.org into the iframe.
  2. The user is not supposed to be allowed to move forward until the question is answered; this means the interface must disallow forward progress until it gets a completion notice (via JavaScript) from the quiz question.
  3. Since the quiz question is loaded into an iframe and is not from the same domain as the parent frame, it is not allowed to interact with the parent frame and can’t use JavaScript to communicate with the course interface. This means the completion notice can’t be sent to the course interface, and the learner can’t move forward.

The hack

What’s a boy to do? Make a hack, of course. 😉

After searching high and low for answers, I decided to use a nested-iframe hack. From what i can tell, it’s a fairly common workaround. Here’s how it works:

  1. Parent frame is from domain A.
  2. Content in child frame (iframe) is from domain B.
  3. Child frame loads a hidden iframe which is served from domain A. Since this nested iframe is served from domain A, it has unrestricted access to the JavaScript in the parent frame.

Iframe workaround: Nested iframe inside content iframe.

Ok, ok, it’s starting to make your head spin, right? Well, what makes it even more complicated is that the nested frame can’t communicate with the child frame, either! In fact, it all seems like a pointless exercise until you add in one crucial ingredient: a querystring in the nested iframe’s URL.

The querystring

The HTML page loaded into the nested iframe is a dedicated proxy (helper) file; it only contains JavaScript, and includes a JavaScript-based querystring parser that examines the string and executes a function based on the content of the querystring.

Here’s how the final sequence of events would look:

  1. myLMS.com loads quiz question from content.org into an iframe.
  2. When quiz question is completed, it uses JavaScript to dynamically create a nested iframe.
  3. Before loading the nested iframe, a querystring is added to the URL, such as proxy.html<strong>?result=passed</strong>.
  4. The JavaScript in the proxy HTML examines the querystring and acts accordingly. In this example, it sees that the variable “result” has a value of “passed”, so it sends a completion notice directly to the JavaScript contained in the parent frame.

The scripts

Parent frame (myLMS.com)

For this example, we’re going to assume the parent frame contains a JavaScript function named interactionCompleted.

function interactionCompleted(result){
   //Do something with result
}

Content iframe (content.org)

The content iframe, which is loaded from the external domain content.org, contains a function that creates the nested iframe element, then loads the proxy.html file with the proper querystring. You can invoke the proxy whenever you need it. In this example, it gets invoked via the setCompletion function.

function setCompletion(result){

    //The name of the frame
    var id = "proxyframe";

    //Look for existing frame with name "proxyframe"
    var proxy = frames[id];

    //Set URL and querystring
    var url = "http://myLMS.com/proxy.html?result=" +result;

    //If the proxy iframe has already been created
    if(proxy){

        //Redirect to the new URL
        proxy.location.href = url;

    } else {

        //Create the proxy iframe element.
        var iframe = document.createElement("iframe");
        iframe.id = id;
        iframe.name = id;
        iframe.src = url;
        iframe.style.display = "none";
        document.body.appendChild(iframe);

    }

}

Nested “proxy” iframe (myLMS.com)

When the content iframe creates the nested proxy frame, it appends a querystring. The proxy frame therefore needs to examine the proxy’s window.location parameter for a querystring, then act on the value of the querystring.

window.onload = function (){

    var result, pairs;
    var querystring = window.location.href.split("?")[1] || false;

    //Ensure querystring exists and has valid result identifier
    if(!querystring || querystring.indexOf("result=") === -1){ return false; }

    //Ensure all ampersands are single (not entities) so we can split using "&"
    querystring = querystring.replace(/&/g, "&");    

    //Create an array of value pairs. This gives us flexibility
    //to add more items to the querystring later.
    pairs = querystring.split("&");

    //Loop through the pairs and act on each one.
    for(var i = 0; i < pairs.length; i++){

        //We're currently only looking for the 'result' value
        //We can add more if needed by adding more 'if' and 'switch' statements

        //Find 'result' variable
        if(pairs[i].indexOf("result=")){

            //Extract the value from the string by replacing the
            //identifier/assignment portion of the string with nothing ""
            result = pairs[i].replace("result=", "");

        }

    }

    //Only act on valid values.
    //DO NOT try to use eval() here.  Big no-no.
    switch(result){

        //Must specify "top." before the function invocation so that
        //the browser knows to send the JS to the topmost parent frame

        case "passed" : top.interactionCompleted("passed"); break;
        case "failed" : top.interactionCompleted("failed"); break;

    }

};

If you remove the comments and extra line breaks, this is a very short script that weighs in at 16 lines. Also, as I mentioned in the comments, please don’t try to use eval() on the querystring; it would be very unwise and would cause major security vulnerabilities, much like an SQL injection.

Thoughts and observations

Now that I’ve covered the basics, here are some general thoughts and observations on the topic.

Does this hack work in all browsers?

I can’t guarantee anything, but in my personal tests it worked in the following browsers: IE6 (XP), IE7 (Vista), Firefox 3 (XP, Vista, OS X, Ubuntu 8.10), Safari 3.1 (XP, Vista, OS X), and Opera 9.5 (XP, Vista, OS X).

Where is the proxy.html file stored?

In my example, the proxy.html file (used for the nested iframe) must be stored on the same domain as the parent file (the course interface); the key to this workaround is that the proxy.html file has unrestricted access to the topmost parent file, which it can only have when being served from the same domain.

Do the nested iframes screw up the back button?

Yes and no. I didn’t document what happens in which browser, but I know some browsers’ back buttons are unaffected by the nested iframe, while others will require one extra ‘back’ click. I don’t know about you, but I can live with one extra back button click.

What if I have some files that aren’t on a different domain?

Sometimes you’ll have some files that are on a different domain, and some that aren’t. If you have files on the same domain, you certainly wouldn’t want to use the iframe hack — it would be completely unnecessary. In my system, I expanded on the previous example by adding a domain-matching check before invoking the proxy. It requires specifying the parent’s domain in the querystring for the content iframe. The JavaScript in the content iframe looks like this:

//Get the querystring
var querystring = window.location.href.split("?")[1] || false;

//Create boolean indicating whether domains match.
//If domains match, no need for proxy workaround.
var isSameDomain = (querystring && querystring.contains("domain=" +document.domain));

function setCompletion(result){

    if(isSameDomain && parent){
        top.interactionCompleted(result);
    } else {
        //do what's in the previous example
    }
}

document.domain can be used to find out what the current domain is for security purposes. A simple string search will tell you whether the content frame’s domain is found inside the querystring that was passed from the parent.

What if I have multiple actions I’d like to perform using the proxy?

Simple: Just add it to your querystring and build the logic into your proxy.html file’s JavaScript. You can make it as simple or complicated as you like!

Disclaimer: I have no affiliation with any real sites that may be located at mylms.com or content.org; these addresses were picked at random and only used for demonstration purposes.

Adobe E-Learning Products “Sneak Peeks”

Today’s Adobe Summit had a session named “Sneak Peeks.” It was (unofficially I think) mentioned that the Adobe E-Learning Suite is coming, and will include Captivate 4, Flash, Photoshop, Acrobat Professional, Device Central, and more.

Here’s a quick list of topics covered.

Versions of Dreamweaver and Flash in E-Learning Suite will NOT be same as those in CS4 suites, and will include e-learning specific bits.

No date for E-Learning Suite given; will only say 2009.

Captivate 4 will include:

  • Automatic panning that follow your screen actions.
  • Previewing in Device Central
    • Allows you to preview on an actual mobile device
    • Allows you to preview with fake screen reflections
  • Inline text editing for captions (no more dialog boxes)
  • Basic drawing tools (shapes)
  • Integration with Adobe Bridge
  • Import > Photoshop files (PSD)
    • Can flatten layers or choose to have them import to separate layers
    • Converts each layer to hi-res PNG
    • Allow syou to animate layers individually on a single slide
  • Support for custom variables, such as using a person’s first name throughout the course
    • Uses $$variablename$$ syntax
    • Means you can use custom static variables throughout a course
    • You can customize an external RDL file to templatize variable use; means you can instruct Captivate to automatically insert variables when recording a demo without having to manually edit the recording afterwards
  • Support for Flash widgets
    • Will work much like components in Flash Professional
    • Captivate 4 will ship with many widgets (including source FLA)
    • Widgets can be customized, and users can create own from scratch
    • Can talk to Captivate (including quizzes) and retrieve variables
    • Example: certificate widget can display person’s name, score for course, date, etc.
    • Example: “perpetual buttons” widget that customizes navigation (forward/back) for movie; hides “back” biutton when on first slide, hide “next” button when on last slide
    • Captivate Exchange on Adobe site will be available for users to post and download custom widgets
  • Support for multiple actions on a single slide
  • Support for ActionScript 3 (can publish to AS2 or AS3 depending on user settings)
  • Can create image slideshow
  • Ability to show/hide toolbar during a course without using customizations
  • Captivate 4 will be on Windows, but work will soon begin on a Mac version
  • Can publish directly to PDF (embeds SWF into new PDF file)
  • Single-SWF output (all files are embedded into single SWF, including nav and full-motion recordings)
  • Auto-generation of Table of Contents (embedded into SWF)
  • SWFs are searchable (text caption content is searchable)
  • “Aggregator” feature allows you to add external Captivate SWFs to project (package multiple SWFs together… is a SWF that loads other SWFs)
  • Supports Flash Player 7, 8, 9 & 10
  • “Reviewer” feature allows users without Captivate to comment on a Captivate SWF
    • Uses Adobe AIR
    • Synchronizes comments form multiple reviewers
  • Supports placeholders to demonstrate where content will be, such as an FLV that isn’t available yet.
    • Helpful when using Reviewer feature so others can know what you have planned
    • Placeholders make it easy to insert content when it becomes available
  • Improved Support for PowerPoint imports
    • Support for dynamic link to PowerPoint presentation — if PowerPoint file is updated, changes wil be reflected in Captivate file
    • Makes PPT file a smart object; you can open and edit PPT file via Captivate (just like how smart vector objects in Photoshop open in Illustrator)

iframes and cross-domain security

What a pain.

I’m working on an HTML-based course interface that serves up content in an iframe. I had everything working great until I needed to move the content to one domain while hosting the interface on a different domain (kind of a simplified home-brewed CMS approach). BAM! Cross-domain security issues. Course interface dead in the water.

Cross-domain iframe security has been an issue for years and still hasn’t been resolved. Hacks abound, but none are the end-all-be-all solution.

One of the most popular hacks for getting around an iframe’s cross-domain security constraints is the fragment identifier hack. The simple explanation is that you can add data to the end of a page’s URL by using a hash (#, aka pound sign or octothorpe), just like named anchor elements. (Hashes are preferred over querystrings because querystrings would cause the page to reload, while using a hash doesn’t.) You’d then create a JavaScript function that monitors the URL for changes and evaluates whatever new data is in the ‘fragment.’

For example, the iframe myurl.com/index.html could have its URL appended to read myurl.com/index.html#somekindofdata. The parent frame would notice the change and could use conditional code to act on whatever the fragment contains.

The downsides to this approach make it unusable for my e-learning course interface. The biggest downside is that it breaks the browsing history model, rendering the browser’s ‘back’ button practically useless. It also breaks the named anchor functionality, which I use in a number of places. It is limited in scope, requiring all JavaScript to be converted to a string before being added to the URL; this means no native sending/receiving of JavaScript objects, booleans, etc… everything needs to be serialized and deserialized. Which brings me to the last point: this adds to code weight, code complexity, and processing time (especially when using polling to monitor changes to the URL); all three suck are undesirable.

I don’t have a solution I like yet, but I will continue to search and experiment. I was hoping a JavaScript framework like MooTools would have some kind of workaround built-in, but no dice. Other approaches include using Flash hacks and using server-side processing. I can’t use server-side processing since I’m not in control of the primary domain. Flash hacks are a possibility, but I’ve worked hard to ensure this course interface is cross-browser and cross-platform without requiring plugins. *sigh*

Wish me luck, I’ll need it.

Update 11/30/08: I’ve written about the workaround I decided to use; read about the workaround here.

Just say no to corporate drone

I don’t often link to other blogs, but I think Cathy Moore has written a very good overview of a common issue: corporate-speak killing readability.

Quick ways to increase your score and sound like a human being

  • Say "you" and "we."
  • Cut 98% of adjectives and adverbs.
  • Write active sentences that make clear who does what.
  • Use strong verbs instead of wimpy "is."
  • Look for tacked-on clauses ("blah blah, which", " "blah blah, because"). Turn them into standalone sentences.

This is important not just for courses, but for documentation and specifications, too; no one likes to read what Cathy calls “corporate drone.”

Read Cathy’s blog entry “How to get everyone to write like Ernest Hemingway

Target settles accessibility lawsuit for $6 million

Think accessibility isn’t a big deal, and is only one of those issues “the other guy” has to deal with?

So did Target. And now they’ve lost $6,000,000 because of it.

In case you hadn’t heard, Target was sued by the National Federation for the Blind because its website was inaccessible for visually-impaired web surfers. At issue in the suit was whether the same accessibility standards for brick-and-mortar stores applied in cyberspace. The verdict: yes, most definitely. The suit became a class-action lawsuit, and yesterday Target settled the case, agreeing to establish a $6 million fund to pay out settlements.

Any web developer worth their salt will tell you this situation was completely avoidable.  Roger Johansson, Derek Featherstone, and Jeremy Keith (among many, many others) have been advocating progressive enhancement principles that prevent this kind of inaccessibility for a few years now. It’s amazing to me that companies as big as Target have effectively said “so what?” to such a significant number of potential customers.

Accessibility in e-learning

As an e-learning developer, I spend a lot of time wondering how the various learning management systems (LMS) have managed to skate by accessibility requirements. In my experience, almost every LMS I’ve seen uses outdated coding techniques (or over-the-top ajax) that make their system partially, if not completely, inaccessible. I often go through great pains to make my courses as accessible as possible, only to be forced to load them into a completely inaccessible LMS.

If U.S. Federal law (Section 508) requires federally-funded websites to be accessible, doesn’t that include many educational websites and web services such as LMSs and online courseware? Section 508 is ten years old already… why are so many of our LMSs and courses as inaccessible now as they were in 1998?

Probably because developers who code with accessibility in mind are still considered specialists in a small niche, when we should really be at a point where they’re a dime a dozen. Accessibility best practices should be a no-brainer, taught in entry-level web development classes alongside standardized (x)HTML markup and valid CSS.

Accessibility is essentially a non-conversation in e-learning. LMSs rarely use accessibility as a selling point, and e-learning course development tools often completely ignore accessibility (especially the Flash-based tools). This has to change, but as we all know, until there’s strong pressure or some kind of impetus to change, nothing will happen.

  • There are very few technical standards in e-learning besides SCORM, and SCORM doesn’t address accessibility; thus there is no technical enforcement for accessibility standards.
  • The e-learning development industry hasn’t felt pressure in the marketplace, so there’s no financial incentive. (Quite the opposite, actually; the industry has been leaning more and more towards inaccessible Flash-based courseware, hoping that Adobe will save the day by making Flash more accessible.)
  • The Feds haven’t really been enforcing 508 (I bet very few Fed employees even understand accessibility well enough to know what to look for), so there’s not much government pressure.

Eventually a big player in the e-learning field is going to get slapped with a lawsuit just like Target did. If that’s what it takes to wake people up, I’m hoping it’s sooner rather than later!

Adobe Captivate 4 beta coming soon… testers needed!

An FYI for Adobe Captivate users: Adobe is about to release the Captivate 4 beta, and is looking for beta testers (no experience required).

This is a great opportunity to get a sneak peak at Captivate’s latest features and provide feedback about the product before it gets released to the general public.

In their own words: “We want as many of you as possible to actively test and help shape a rock-solid release.”

Sign up at adobe.com [link no longer available].

IMS announces new QTI validation service

The IMS Global Learning Consortium announced a new Question and Test Interoperability (QTI) validation service a few weeks ago:

IMS Global Learning Consortium Announces Question and Test Interoperability Conformance Community
Common Cartridge Alliance will provide community tools for QTI conformance and online product catalog

Download pdf [link no longer available]

Lake Mary, Florida, USA,  10 July 2008. The IMS Global Learning Consortium (IMS GLC) today announced new support that will allow vendors of products that implement the IMS Question and Test Interoperability (QTI) standards, and the users of such products, to validate conformance.  Results of conformance tests to application profiles approved by the IMS GLC will be published in an online catalog on the IMS GLC web site.

The new QTI community will be offered as a component of the Common Cartridge Alliance (see http://www.imsglobal.org/cc/alliance.html ) and will be managed and administered under the policies and procedures for development of and conformance to IMS GLC application profiles.

This sounds great… developers who write scripts for quizzes in e-learning courses can finally validate their work, right? Well, I’m afraid the key phrase in this announcement is “offered as a component of the Common Cartridge Alliance”; that means the QTI validation isn’t a publicly accessible service a la the W3C’s HTML and CSS validators. Membership in the Common Cartridge Alliance isn’t free, and starts at $100.

As I’ve mentioned before, it really gets in my craw that the IMS positions itself as a big player in creating and maintaining e-learning standards, yet keeps their doors closed to the public. How can it be a standard if people can’t get to it? Sheesh.

And hey, IMS (if you’re listening): enough with all the press releases touting IMS’ latest endeavors and successes (real or imagined); it reeks of money-grubbing corporate culture and really doesn’t help anyone… especially if you’re saying “look what we’re making but you can’t have any!” You bill yourself as a global non-profit, so start acting like it.

Link: Opening Up the IMS

Good post from Michael Feldstein at e-Literate:

There’s something fundamentally contradictory about open standards being developed behind closed doors.

Over the past 18 months, I have had the privilege of participating in the IMS work on a regular basis. During that time, I have mostly kept my mouth shut about the openness issue. Out of respect for the staff and the board, I wanted to experience the process from the inside and see how it works today before advocating change. But at the Learning Impact conference last month, I decided to speak out.

At one point I said, “I know plenty of people in the ed tech community-good people, exactly the kind of people that we need to participate-who think that the IMS is some kind of secret society.” I got a fair few “amens” from other participants, both publicly and privately.

Amen, indeed, brother!

Read the entire post at e-Literate