/*
 * This script is provided for inclusion in HTML activities that wish to access
 * VLE features such as parameters, attachments, and server-side data.
 *
 * This is a stub. If running on the VLE, the actual version of these functions
 * will automatically be applied using a script from the server that overwrites
 * the definitions here.
 *
 * For new projects, the current version of this file is available on the VLE
 * as /mod/oucontent/api/vleapi.1.js (this file is not actually used by the VLE).
 * We will try to ensure that old versions of this file keep working.
 */
var VLE = {
  /**
   * API version of this file (integer changed only when API has
   * non-compatible change).
   */
  apiversion: 1,
  /**
   * Point version of this file. Changed for information when there is an
   * update to the file version that does not break API, such as adding a new
   * function.
   */
  pointversion: 13,
  /**
   * Marked true if sent from server.
   */
  serverversion: false,
  /**
   * Text strings used in display. You can modify these strings if you want
   * your activity to be in a foreign language.
   */
  strings: {
	label_group: 'Group',
	option_choose: 'Choose...'
  },
  /**
   * Obtains value of a named parameter or attachment. For attachments, this
   * will return the URL of the attachment. If you want to retrieve the
   * content of the attachment, use get_attachment function.
   *
   * Parameter names are restricted to these characters: [A-Za-z0-9_-.] and
   * can only be up to 20 characters long.
   *
   * Because parameters are provided in the URL to index.html, this function
   * will not work if the user has clicked a link to a different file within
   * your activity, unless you previously ensured that all parameters were
   * included in the link.
   *
   * When not running in the VLE, this code still works to retrieve parameter
   * values from the URL.
   *
   * The following special parameter names are available when running in the
   * VLE. They have short names to avoid taking up too much space in the URL.
   *
   * _c : Course id (number); not set for previews
   * _i : Document item id (text; from id= on Item; not set for previews
   *      or if document item id does not match character restriction)
   * _p : Preview id (number); only set for previews
   * _a : Activity id (text; from id= on MediaContent); may or may not be set
   * _s : Moodle session key for user (text)
   * _u : Moodle user id (number)
   *
   * @param name Parameter name
   * @return Value of parameter or null if not set
   */
  get_param: function (name) {
	// Check valid param name
	this.check_key(name, 'Invalid param name: ' + name);
	// Find in query
	var search = String(location.search);
	var matches = new RegExp('[?&]' + name + '=([^&]+)').exec(search);
	if (matches && matches[1]) {
	  return decodeURIComponent(matches[1].replace(/\+/g, ' '));
	} else {
	  return null;
	}
  },
  /**
   * Gets the content of an attachment. (If you only want to retrieve the
   * URL, use get_param function.) The attachment must be an XML or text
   * file. For XML support, the filename must end in '.xml'.
   *
   * You must pass two functions as parameters. Here is an example:
   * VLE.get_attachment('frog', function(text, xmldocument) { ... },
   *   function(message) {...});
   *
   * In this example the xmldocument parameter is a DOM document object
   * containing the XML file result (if any), and the text parameter is a
   * string containing the result as plain text. The error parameter
   * is a string.
   *
   * When not running in the VLE, this function may still work but should
   * be used for testing purposes only. Specifically, it only works fully
   * on Firefox (tested on Firefox 12) and while testing, the attachment must
   * be placed in the same folder as the HTML file. It doesn't work in Chrome
   * due to browser security restrictions (Chromium issue 47416) and works
   * only partially on IE9.
   *
   * @param name Attachment name
   * @param ok Function that is called if the attachment is retrieved OK.
   * @param error Function that is called if there is an error.
   */
  get_attachment: function (name, ok, error) {
	var url = this.get_param(name);
	if (!url) {
	  error('Attachment not found: ' + name);
	  return;
	}
	var xml = url.match(/\.xml$/);
	this.ajax_get(url, function (req) {
	  ok(req.responseText, xml ? req.responseXML : null);
	}, error);
  },
  /**
   * Return array of objects that give path and url properties
   * of all files in the zipped Folder specified (pass name attribute value).
   *
   * You must pass two functions as parameters. Here is an example:
   * VLE.get_folder('frog', function(contents) { ... },
   *   function(message) {...});
   *
   * In this example contents would be an array with one element for every
   * file in the folder's zip file. Each element is an object containing
   * 'path' (e.g. 'frog.jpg' or 'frog/frog.jpg' if within a folder) and 'url'
   * (the url of the file, either absolute or relative to the HTML activity's index.html).
   *
   * When not running in the VLE, this function will still work but should
   * have a supporting folder.js file in a directory named after the specified folder
   * e.g. frog/frog.folder.js. The js file should return the list of folder info, as
   * specified above, in javascript to VLE.get_folder_callback.(this is a jsonp approach)
   *
   * @param string name Folder name as specified in src attribute.
   * @param object ok Function that is called if the attachment is retrieved OK.
   * @param object error Function that is called if there is an error (VLE api only).
   * @param object t value of this
   */
  get_folder: function (name, ok, error, t) {
	// Specify this for callbacks.
	if (t === undefined) {
	  t = this;
	}
	VLE.get_folder_callback = function (data) {
	  ok.call(t, data);
	};
	var script = document.createElement('script');
	script.async = true;
	script.src = name + '/' + name + '.folder.js';
	document.getElementsByTagName('head')[0].appendChild(script);
  },
  /**
   * Gets data that was stored on the server.
   *
   * Note that you should not normally use the last three parameters.
   * These are for special cases where you want to access the same
   * data across different activities.
   *
   * You can retrieve data either for the current user (each user has
   * independent data), for all users (so that all users access the same
   * data), or for a specific group (all users accessing that group access
   * the same data). If you specify a specific group, it must be one to
   * which the current user has access. Use Boolean true for the current user,
   * false for global data, or the string 'g1234' for group id 1234.
   *
   * You must pass two functions as parameters. Here is an example:
   * VLE.get_server_data(true, ['frog'], function(values) { ... },
   *   function(message) { ...});
   *
   * In this example the 'values' parameter is a JavaScript object containing
   * fields with the same names as you passed (so in this case, values.frog
   * would be the value of the data named 'frog' for this user, or an empty
   * string '' if  no such data had been set). The 'message' parameter is
   * an error message string.
   *
   * When not running in the VLE, always calls the 'error' function with the
   * message set to null.
   *
   * @param userorgroup User, global, or group identifier
   * @param names Array of names
   * @param ok Function that is called if the data is retrieved OK.
   * @param error Function that is called if there is an error.
   * @param activityid Activity id (Optional: omit to use current activity)
   * @param itemid Document item id (Optional; omit to use current document)
   * @param courseid Course numeric id (Optional; omit to use current course)
   */
  get_server_data: function (userorgroup, names, ok, error, activityid, itemid, courseid) {
	window.setTimeout(function () {
	  error(null);
	}, 0);
  },
  /**
   * Stores data on the server for the current user.
   *
   * Note that you should not normally use the last three parameters.
   * These are for special cases where you want to access the same
   * data across different activities.
   *
   * You can set data either for the current user (each user has
   * independent data), for all users (so that all users access the same
   * data), or for a specific group (all users accessing that group access
   * the same data). If you specify a specific group, it must be one to
   * which the current user has access. Use Boolean true for the current user,
   * false for global data, or the string 'g1234' for group id 1234.
   *
   * The value of each key-value pair is limited to 64,000 bytes (not
   * characters) but can contain any Unicode. Keys may be up to 20 characters
   * and must contain only [A-Za-z0-9_-.]. Activity IDs and item IDs have the
   * same restriction. (Item IDs are only restricted in this way when you
   * set an activity ID for an HTML activity.)
   *
   * Setting a value to empty string has the effect of deleting that value
   * from our database and saving space, so we recommend doing that when
   * appropriate.
   *
   * You must pass two functions as parameters. Here is an example which sets
   * the value of the data item 'frog' to 'Kermit':
   * VLE.set_server_data(true, {'frog' : 'Kermit'}, function() { ... },
   *   function(message) { ... });
   *
   * In this example the 'message' parameter on the second function is an
   * error message string. The first function, with no parameters, is called
   * if the update succeeds.
   *
   * When not running in the VLE, always calls the 'error' function with the
   * message set to null.
   *
   * Especially when storing data for all users, you may wish to consider
   * race conditions. For example, if you are storing a count value, you may
   * use a pattern where based on a user action, you retrieve the current
   * value (say, 4) and then set a new one (say, 5). If two users do this at
   * a similar time, you will end up setting it to 5 twice. To avoid this
   * possibility, you can use the optional previousvalues and retry
   * parameters. If you specify previousvalues, this should be the object
   * containing the old values of the data, as retrieved by get_server_data.
   * The system will only apply the update if the data is the same as this.
   * If it is different, then the retry function will be called, passing the
   * actual current server data as its single parameter.
   *
   * Here is an example where we try to set a number to 5 but only if the
   * current value is 4. If the current number is not 4 then the last
   * function will be called with an object including the 'num' field with
   * the actual value.
   * VLE.set_server_data(true, {'num' : 5}, function() { ... },
   *   function(message) { ... }, {'num' : 4}, function(actualvalues) { ... });
   *
   * @param userorgroup User, global, or group identifier
   * @param values JavaScript object containing the key/value pairs to set
   * @param ok Function that is called if the data is set OK.
   * @param error Function that is called if there is an error.
   * @param previousvalues Previous values (optional)
   * @param retry Function that is called if previous values changed (optional)
   * @param activityid Activity id (optional: omit to use current activity)
   * @param itemid Document item id (optional; omit to use current document)
   * @param courseid Course numeric id (optional; omit to use current course)
   */
  set_server_data: function (userorgroup, values, ok, error, previousvalues, retry,
							 activityid, itemid, courseid) {
	window.setTimeout(function () {
	  error(null);
	}, 0);
  },
  /**
   * Sets exported response data on the server for the current user.
   *
   * The exported data is set as arbitrary HTML which will be included if
   * the student uses the 'Export responses' option.
   *
   * If you want to clear the value (as if the user had not saved one), then
   * set html to an empty string.
   *
   * HTML should be plain HTML with no styling (no CSS and no HTML attributes
   * that control styling). It should appear completely plain. (This is because
   * it needs to work with the RTF converter.)
   *
   * Note that you should not normally use the last three parameters.
   * These are for special cases where you want to access the same
   * data across different activities.
   *
   * You must pass two functions as parameters. Here is an example which sets
   * the value of the data item 'frog' to 'Kermit':
   * VLE.set_server_data(true, {'frog' : 'Kermit'}, function() { ... },
   *   function(message) { ... });
   *
   * In this example the 'message' parameter on the second function is an
   * error message string. The first function, with no parameters, is called
   * if the update succeeds.
   *
   * When not running in the VLE (e.g. in a EPUB3 document) it always calls
   * the 'error' function with the message set to null.
   *
   * @param html String containing HTML code for use if exported
   * @param ok Function that is called if the data is set OK.
   * @param error Function that is called if there is an error.
   * @param activityid Activity id (optional: omit to use current activity)
   * @param itemid Document item id (optional; omit to use current document)
   * @param courseid Course numeric id (optional; omit to use current course)
   */
  set_exported_response: function (html, ok, error, activityid, itemid, courseid) {
	window.setTimeout(function () {
	  error(null);
	}, 0);
  },
  /**
   * Gets a list of all groups that the current user can access.
   *
   * This method will make an AJAX request the first time it is called on the
   * page.
   *
   * If it succeeds, the 'ok' function will be called with an array of
   * grouping objects with fields id, name, and groups; the groups field is
   * an array of group objects with fields id, name, and member (boolean).
   *
   * A special 'all groups' grouping has the name set to '' and id to 0.
   *
   * If there is an error in AJAX processing, the 'error' function will be
   * called with an error message string. The error message will be null if
   * this function is used offline.
   *
   * Staff (sometimes including tutors) have access to groups to which they
   * don't belong. This function will return all groups, but you can use the
   * 'member' flag if you really want to include only groups they actively
   * belong to.
   *
   * @param ok Function that is called with the array of groupings
   * @param error Function called if AJAX request fails
   * @param t Optional; value to use as 'this' for callback functions
   */
  get_all_groups: function (ok, error, t) {
	if (t === undefined) {
	  t = this;
	}
	window.setTimeout(function () {
	  error.call(t, null);
	}, 0);
  },
  /**
   * Gets a list of tutor groups that the current user can access.
   *
   * This method will make an AJAX request the first time it is called on the
   * page.
   *
   * If it succeeds, the 'ok' function will be called with one parameter.
   * This is an array of group objects (representing tutor groups) with
   * fields id, name, and member (boolean).
   *
   * The array will be empty if the user cannot access any tutor groups,
   * or if there are no tutor groups on the website.
   *
   * If there is an error in AJAX processing, the 'error' function will be
   * called with an error message string. The error message will be null if
   * this function is used offline.
   *
   * Websites with multiple variants will have multiple sets of tutor groups
   * (one per variant). This function returns all groups the user can access
   * from any of these, combined into the single array.
   *
   * Staff (sometimes including tutors) have access to groups to which they
   * don't belong. This function will return all groups, but you can use the
   * 'member' flag if you really want to include only groups they actively
   * belong to.
   *
   * @param ok Function that is called with the array of groups
   * @param error Function called if AJAX request fails
   * @param t Optional; value to use as 'this' for callback functions
   */
  get_tutor_groups: function (ok, error, t) {
	if (t === undefined) {
	  t = this;
	}
	window.setTimeout(function () {
	  error.call(t, null);
	}, 0);
  },
  /**
   * Gets a list of regional groups that the current user can access.
   *
   * This method will make an AJAX request the first time it is called on the
   * page.
   *
   * If it succeeds, the 'ok' function will be called with one parameter.
   * This is an array of group objects (representing regional groups) with
   * fields id, name, and member (boolean).
   *
   * The array will be empty if the user cannot access any regional groups,
   * or if there are no regional groups on the website.
   *
   * If there is an error in AJAX processing, the 'error' function will be
   * called with an error message string. The error message will be null if
   * this function is used offline.
   *
   * Websites with multiple variants will have multiple sets of regional
   * groups (one per variant). This function returns all groups the user can
   * access from any of these, combined into the single array.
   *
   * Staff (sometimes including tutors) have access to groups to which they
   * don't belong. This function will return all groups, but you can use the
   * 'member' flag if you really want to include only groups they actively
   * belong to.
   *
   * @param ok Function that is called with the array of groups
   * @param error Function called if AJAX request fails
   * @param t Optional; value to use as 'this' for callback functions
   */
  get_regional_groups: function (ok, error, t) {
	if (t === undefined) {
	  t = this;
	}
	window.setTimeout(function () {
	  error.call(t, null);
	}, 0);
  },
  /**
   * Returns a new <div> containing controls that can be used to select a
   * group from a list.
   *
   * The onchange function will be called when the user selects a group, or
   * if one is selected automatically. The function has two parameters;
   * first the group object that is selected, and then true (meaning the user
   * selected it manually) or false (meaning it's the first one we picked
   * for them).
   *
   * Special behaviour:
   * 1. If there are no groups, an empty div (display:none) is returned and
   *    the onchange function is called with parameter null.
   * 2. If there is only one group, an empty div (display:none) is returned
   *    and the onchange function is called with that group.
   *
   * The returned div has class="groupselector", so you can style it in CSS.
   * Please be aware that the precise HTML contents of the returned div may
   * change between VLE releases if we find bugs or make improvements..
   *
   * You can specify groups in one of three ways:
   * 1. An array of groups e.g. returned by VLE.get_tutor_groups(), or from
   *    within a grouping in VLE.get_all_groups().
   * 2. The keywords (strings) 'tutor' or 'regional'.
   * 3. A string beginning with 'grouping:' and followed by a regular
   *    expression, such as 'grouping:^Tutor groups'; this will automatically
   *    include all groups from groupings where the name matches the expresison
   *
   * In all cases, this function returns immediately with a div containing the
   * control. In the latter two cases, the control will be hidden (display:none)
   * while an AJAX request takes place.
   *
   * The autoselect option, if enabled, means the system will automatically
   * pick the first group in the list (if there are more than one). When
   * false, 'Choose...' text will show and onchange will not be called until
   * the user selects something.
   *
   * The offline version of this function behaves as if the user does not
   * have any groups (calls onchange with parameter null).
   *
   * @param groups Array of groups, keyword, or grouping regex
   * @param onchange Function to call on change and initial group selection
   * @param autoselect True if autoselect is enabled, false to choose if multi
   * @param error Function to call if AJAX request fails
   * @param t Optional; value to use as 'this' for callback functions
   * @return HTML div containing control
   */
  make_group_chooser: function (groups, onchange, autoselect, error, t) {
	var div = document.createElement('div');
	div.style.display = 'none';
	if (t === undefined) {
	  t = this;
	}
	window.setTimeout(function () {
	  onchange.call(t, null, false);
	}, 0);
	return div;
  },
  /**
   * (Internal function, not recommended for other use.)
   * Makes an AJAX GET request and calls the ok function if it succeeds or the
   * error function if it fails.
   */
  ajax_get: function (url, ok, error) {
	// Get the XMLHttpRequest object. On IE we prefer the ActiveX version
	// even though it now supports the standard way too, because the ActiveX
	// one can access files if run locally.
	var req;
	if (window.ActiveXObject) {
	  req = new ActiveXObject("Microsoft.XMLHTTP");
	} else {
	  req = new XMLHttpRequest();
	}
	req.open('GET', url, true);
	req.onreadystatechange = function (e) {
	  if (req.readyState == 4) {
		// Status 0 is for local files (testing use only).
		if (req.status == 200 || req.status == 0) {
		  ok(req);
		} else {
		  error('Error ' + req.status + ' loading ' + url);
		}
	  }
	};
	req.send(null);
  },
  /**
   * Internal use only: Various keys are restricted to a certain regular
   * expression. This checks it and throws exception if it doesn't match.
   * @param key Key to test
   * @param message Message to throw if it fails test
   */
  check_key: function (key, message) {
	if (key === null || !key.match(/^[A-Za-z0-9._-]{1,20}$/)) {
	  throw message;
	}
  },
  /**
   * Obtains information about the context where this activity has been
   * embedded. The information is returned as a JavaScript object which
   * includes the following fields (more fields may be added later).
   *
   * Fields that correspond directly to CSS values:
   * - backgroundColor (of surrounding area, e.g. '#ffffff')
   * - fontSize (of main body text, e.g. '0.875em')
   * - color (of main body text, e.g. '#1a1a1a')
   * - fontFamily (of main body text, e.g. 'Arial, sans-serif')
   * - lineHeight (of main body text, e.g. '1.4')
   * - marginBottom (of paragraphs in main body text, e.g. '10px')
   *
   * Extra fields:
   * - variant (alternate text colour for certain headings or
   *   highlights, depending on selected VLE theme)
   */
  get_embed_context: function () {
	return {
	  backgroundColor: '#ffffff',
	  fontSize: '0.875em',
	  color: '#1a1a1a',
	  fontFamily: 'Arial, sans-serif',
	  lineHeight: '1.4',
	  marginBottom: '0.5em',
	  variant: '#e80074'
	};
  },
  /**
   * Reports a user accessing this experiment, for the analytics system.
   *
   * If using the analytics system, you must call this function before any
   * of the other report_ functions. This function should usually be called
   * on each page load. (The system counts a 'visit' only once per user
   * session, so repeated visit reports within the same session will be
   * safely ignored.)
   *
   * You can optionally pass an 'error' function with one parameter (error
   * message). If you don't supply this value, errors will be ignored.
   *
   * When not running in the VLE, always calls the 'error' function (if
   * provided) with the message set to null.
   *
   * @param error Function that is called if there is an error (Optional)
   * @param activityid Activity id (Optional: omit to use current activity)
   * @param itemid Document item id (Optional; omit to use current document)
   * @param courseid Course numeric id (Optional; omit to use current course)
   */
  report_visit: function (error, activityid, itemid, courseid) {
	if (typeof error !== undefined) {
	  error(null);
	}
  },
  /**
   * Reports a counted event for analytics.
   *
   * Example: In an activity about examining rock samples, you want to
   * provide information about how many rock samples the user examined. To
   * achieve this, call report_count each time the user examines a rock
   * sample.
   *
   * The short name and display name identify the event. The short name is
   * subject to the same restrictions as other identifiers (20 characters).
   * The display name can be any text up to 40 characters and will be used
   * to display to user when showing statistics. Although the display name is
   * supplied with each function call, it is actually only stored once; if
   * you change the display name, that will change the display name for all
   * previous events that used the same short name.
   *
   * You can optionally pass an 'error' function with one parameter (error
   * message). If you don't supply this value, errors will be ignored.
   *
   * When not running in the VLE, always calls the 'error' function (if
   * provided) with the message set to null.
   *
   * @param shortname Short name of event (Optional; see above)
   * @param displayname Display name of event (Optional; see above)
   * @param error Function that is called if there is an error (Optional)
   * @param activityid Activity id (Optional: omit to use current activity)
   * @param itemid Document item id (Optional; omit to use current document)
   * @param courseid Course numeric id (Optional; omit to use current course)
   */
  report_count: function (shortname, displayname, error, activityid, itemid, courseid) {
	if (typeof error !== undefined) {
	  error(null);
	}
  },
  /**
   * Starts a timer which will report a quantity of elapsed time for
   * analytics.
   *
   * Example: You want to track the total time users spend with an activity.
   * To track this, you call this function as soon as they click a 'Start
   * activity' button. You then call the returned 'stop' function whenever
   * they finish the activity.
   *
   * This function is designed only for reporting *cumulative* time, such
   * as the total time using an activity, or the total time using a particular
   * tab. At present there is no facility to report individual timed events.
   *
   * If you don't call the stop function, the system will automatically report
   * time once per minute until the page containing the activity is closed.
   *
   * The short name and display name identify the event. The short name is
   * subject to the same restrictions as other identifiers (20 characters).
   * The display name can be any text up to 40 characters and will be used
   * to display to user when showing statistics. Although the display name is
   * supplied with each function call, it is actually only stored once; if
   * you change the display name, that will change the display name for all
   * previous events that used the same short name.
   *
   * You can optionally pass an 'error' function with one parameter (error
   * message). If you don't supply this value, errors will be ignored.
   *
   * When not running in the VLE, always calls the 'error' function (if
   * provided) with the message set to null; the returned 'stop' function
   * does nothing.
   *
   * @param shortname Short name of event (Optional; see above)
   * @param displayname Display name of event (Optional; see above)
   * @param error Function that is called if there is an error (Optional)
   * @param activityid Activity id (Optional: omit to use current activity)
   * @param itemid Document item id (Optional; omit to use current document)
   * @param courseid Course numeric id (Optional; omit to use current course)
   * @return Function which you can call when the elapsed time completes
   */
  report_start_timer: function (shortname, displayname, error, activityid, itemid, courseid) {
	if (typeof error !== undefined) {
	  error(null);
	}
	return function () {
	};
  },
  /**
   * Resets caches, such as the groups cache. Should not be needed in normal
   * situations.
   */
  reset_caches: function () {
  },
  /**
   * Sends a web service request and passes the result to the given callback.
   *
   * This function is currently only available when using HTML activity
   * module. You must have configured a named web service in that module
   * (i.e. the 'service' parameter here is an identifier which maps to a
   * service URL defined in the module settings).
   *
   * The 'input' parameter should be an object containing name/value pairs.
   * The values must be either numbers or strings. Names must follow normal
   * key rules and must not start with an underline.
   *
   * If successful, the 'ok' function will be called with a single parameter
   * which is a JavaScript object that contains arbitrary data returned by
   * the service.
   *
   * If unsuccessful, the 'error' function will be called with a single
   * parameter that is an error message.
   *
   * When not running in the VLE, always calls the 'error' function (if
   * provided) with message set to null.
   *
   * @param service Unique identifier for service within this activity
   * @param input Input data as an object with name/value pairs
   * @param ok Function called after success, with result from service
   * @param error Function called if an error occurs (Optional)
   * @param t Optional; value to use as 'this' for callback functions
   */
  send_service_request: function (service, input, ok, error, t) {
	if (typeof(error) !== undefined) {
	  window.setTimeout(function () {
		error.call(t, null);
	  }, 0);
	}
  },
  /**
   * Gets the URL corresponding to an olink on the course.
   *
   * If successful, the 'ok' function will be called with a single parameter
   * which is the URL.
   *
   * If unsuccessful, the 'error' function will be called with a single
   * parameter that is an error message. This can occur if there is a
   * connection problem (no network, session lost, etc.) and also if the
   * olink cannot be found.
   *
   * When not running in the VLE, always calls the 'error' function (if
   * provided) with message set to null.
   *
   * @param targetdoc Target document name
   * @param targetptr Specific location in target document (normally blank)
   * @param ok Function called after success, with URL
   * @param error Function called if an error occurs (Optional)
   * @param courseid Course numeric id (Optional; omit to use current course)
   * @param t Optional; value to use as 'this' for callback functions
   */
  get_olink_url: function (targetdoc, targetptr, ok, error, courseid, t) {
	if (t === undefined) {
	  t = this;
	}
	if (typeof(errror) !== undefined) {
	  window.setTimeout(function () {
		error.call(t, null);
	  }, 0);
	}
  },
  /**
   * Dynamically resizes the iframe that contains this activity so that it
   * matches its content.
   *
   * The width will not be altered - only the height will be changed. It can
   * become larger or smaller.
   *
   * If you want to use this facility you need to call this function every
   * time you do something that might affect the size of the iframe.
   */
  resize_iframe: function () {
	// Find iframe in parent window.
	var iframes = window.top.document.getElementsByTagName('iframe');
	var iframe = null;
	for (var i = 0; i<iframes.length; i++) {
	  var poss = iframes[i];
	  var doc = poss.contentDocument || poss.contentWindow.document;
	  if (doc == document) {
		iframe = poss;
		break;
	  }
	}
	// If we can't find it, put a message in the console and abort.
	if (!iframe) {
	  if (window.console) {
		console.log('VLE.resize_iframe: Unable to find parent iframe');
	  }
	  return;
	}
	// Calculate body height including margins.
	var html = document.getElementsByTagName('html')[0];
	var styles = getComputedStyle(html);
	var totalHeight = parseFloat(styles['marginTop']) +
		parseFloat(styles['marginBottom']) + html.offsetHeight;
	// Set the height.
	iframe.height = totalHeight;
  }
};