text: (function($, JSON) {
      'use strict';
  
      var XBlock;
  
      function initializeBlockLikes(blockClass, initializer, element, requestToken) {
          var selector;
          requestToken = requestToken || $(element).data('request-token');
          if (requestToken) {
              selector = '.' + blockClass + '[data-request-token="' + requestToken + '"]';
          } else {
              selector = '.' + blockClass;
          }
          // After an element is initialized, a class is added to it. To avoid repeat initialization, no
          // elements with that class should be selected.
          selector += ':not(.xblock-initialized)';
          return $(element).immediateDescendents(selector).map(function(idx, elem) {
              return initializer(elem, requestToken);
          }).toArray();
      }
  
      function elementRuntime(element) {
          var $element = $(element),
              runtime = $element.data('runtime-class'),
              version = $element.data('runtime-version'),
              initFnName = $element.data('init');
  
          if (runtime && version && initFnName) {
              return new window[runtime]['v' + version]();
          } else {
              if (runtime || version || initFnName) {
                  console.log(
                      'Block ' + $element.outerHTML + ' is missing data-runtime, data-runtime-version or data-init, ' +
                      'and can\'t be initialized'
                  );
              } // else this XBlock doesn't have a JS init function.
              return null;
          }
      }
  
      function initArgs(element) {
          var initargs = $(element).children('.xblock-json-init-args').remove().text();
          return initargs ? JSON.parse(initargs) : {};
      }
  
      /**
       * Construct an XBlock family object from an element. The constructor
       * function is loaded from the 'data-init' attribute of the element.
       * The constructor is called with the arguments 'runtime', 'element',
       * and then all of 'block_args'.
       */
      function constructBlock(element, blockArgs) {
          var block;
          var $element = $(element);
          var runtime = elementRuntime(element);
  
          blockArgs.unshift(element);
          blockArgs.unshift(runtime);
  
          if (runtime) {
              block = (function() {
                  var initFn = window[$element.data('init')];
  
                  // This create a new constructor that can then apply() the block_args
                  // to the initFn.
                  function Block() {
                      return initFn.apply(this, blockArgs);
                  }
                  Block.prototype = initFn.prototype;
  
                  return new Block();
              }());
              block.runtime = runtime;
          } else {
              block = {};
          }
          block.element = element;
          block.name = $element.data('name');
          block.type = $element.data('block-type');
          $element.trigger('xblock-initialized');
          $element.data('initialized', true);
          $element.addClass('xblock-initialized');
          return block;
      }
  
      XBlock = {
          Runtime: {},
  
          /**
           * Initialize the javascript for a single xblock element, and for all of it's
           * xblock children that match requestToken. If requestToken is omitted, use the
           * data-request-token attribute from element, or use the request-tokens specified on
           * the children themselves.
           */
          initializeBlock: function(element, requestToken) {
              var $element = $(element),
                  children, asides;
  
              requestToken = requestToken || $element.data('request-token');
              children = XBlock.initializeXBlocks($element, requestToken);
              asides = XBlock.initializeXBlockAsides($element, requestToken);
              if (asides) {
                  children = children.concat(asides);
              }
              $element.prop('xblock_children', children);
  
              return constructBlock(element, [initArgs(element)]);
          },
  
          /**
           * Initialize the javascript for a single xblock aside element that matches requestToken.
           * If requestToken is omitted, use the data-request-token attribute from element, or use
           * the request-tokens specified on the children themselves.
           */
          initializeAside: function(element) {
              var blockUsageId = $(element).data('block-id');
              var blockElement = $(element).siblings('[data-usage-id="' + blockUsageId + '"]')[0];
  
              return constructBlock(element, [blockElement, initArgs(element)]);
          },
  
          /**
           * Initialize all XBlocks inside element that were rendered with requestToken.
           * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
           * If neither is available, then use the request tokens of the immediateDescendent xblocks.
           */
          initializeXBlocks: function(element, requestToken) {
              return initializeBlockLikes('xblock', XBlock.initializeBlock, element, requestToken);
          },
  
          /**
           * Initialize all XBlockAsides inside element that were rendered with requestToken.
           * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
           * If neither is available, then use the request tokens of the immediateDescendent xblocks.
           */
          initializeXBlockAsides: function(element, requestToken) {
              return initializeBlockLikes('xblock_asides-v1', XBlock.initializeAside, element, requestToken);
          },
  
          /**
           * Initialize all XBlock-family blocks inside element that were rendered with requestToken.
           * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
           * If neither is available, then use the request tokens of the immediateDescendent xblocks.
           */
          initializeBlocks: function(element, requestToken) {
              var asides = XBlock.initializeXBlockAsides(element, requestToken);
              var xblocks = XBlock.initializeXBlocks(element, requestToken);
              if (asides) {
                  xblocks = xblocks.concat(asides);
              }
              return xblocks;
          }
      };
  
      this.XBlock = XBlock;
  }).call(this, $, JSON);
  