Merge branch 'wip-mdl-32526-m23' of git://github.com/rajeshtaneja/moodle into MOODLE_...
authorDan Poltawski <dan@moodle.com>
Tue, 22 Jan 2013 06:00:42 +0000 (14:00 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 22 Jan 2013 06:00:42 +0000 (14:00 +0800)
83 files changed:
admin/plugins.php
admin/webservice/forms.php
backup/moodle2/restore_stepslib.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/backup_anonymizer_helper.class.php
backup/util/includes/restore_includes.php
comment/comment.js
course/dndupload.js
course/dnduploadlib.php
course/edit_form.php
course/editsection.php
course/editsection_form.php
course/format/renderer.php
course/index.php
course/lib.php
course/modedit.php
course/moodleform_mod.php
course/rest.php
course/tests/externallib_test.php
course/yui/dragdrop/dragdrop.js
course/yui/modchooser/modchooser.js
course/yui/toolboxes/toolboxes.js
enrol/locallib.php
files/renderer.php
grade/report/grader/lib.php
grade/report/grader/styles.css
group/lib.php
install/lang/zh_tw/install.php
lang/en/block.php
lang/en/question.php
lib/blocklib.php
lib/completionlib.php
lib/filelib.php
lib/form/dndupload.js
lib/form/filemanager.js
lib/form/filemanager.php
lib/javascript-static.js
lib/outputcomponents.php
lib/phpunit/bootstrap.php
lib/plagiarismlib.php
lib/tests/weblib_test.php
lib/weblib.php
lib/yui/chooserdialogue/chooserdialogue.js
lib/yui/formautosubmit/formautosubmit.js
login/index.php
login/index_form.html
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/file/locallib.php
mod/assign/lib.php
mod/assign/submission/comments/locallib.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/upgradelib.php
mod/book/tool/importhtml/locallib.php
mod/forum/backup/moodle2/restore_forum_activity_task.class.php
mod/forum/lib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/quiz/backup/moodle2/restore_quiz_stepslib.php
mod/quiz/cronlib.php
mod/quiz/locallib.php
mod/scorm/locallib.php
mod/wiki/lang/en/wiki.php
mod/wiki/lib.php
question/format.php
question/format/xml/format.php
question/format/xml/tests/fixtures/multichoice.xml [new file with mode: 0644]
question/format/xml/tests/fixtures/truefalse.xml [new file with mode: 0644]
question/format/xml/tests/xmlformat_test.php
question/previewlib.php
question/type/edit_question_form.php
question/type/essay/questiontype.php
question/type/questiontypebase.php
report/outline/index.php
repository/flickr_public/lib.php
theme/base/style/core.css
theme/base/style/course.css
user/index.php
user/tests/externallib_test.php
user/view.php
version.php
webservice/rest/locallib.php

index 943f23a..02eeb6d 100644 (file)
@@ -28,8 +28,8 @@ require_once(dirname(dirname(__FILE__)) . '/config.php');
 require_once($CFG->libdir . '/adminlib.php');
 require_once($CFG->libdir . '/pluginlib.php');
 
-require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
 admin_externalpage_setup('pluginsoverview');
+require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
 
 $fetchremote = optional_param('fetchremote', false, PARAM_BOOL);
 
index 13e1c3d..14b8576 100644 (file)
@@ -163,6 +163,7 @@ class external_service_functions_form extends moodleform {
 
         $mform->addElement('searchableselector', 'fids', get_string('name'),
                 $functions, array('multiple'));
+        $mform->addRule('fids', get_string('required'), 'required', null, 'client');
 
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
index 740c202..d2b1c3a 100644 (file)
@@ -843,20 +843,12 @@ class restore_groups_structure_step extends restore_structure_step {
     }
 
     public function process_grouping_group($data) {
-        global $DB;
-
-        $data = (object)$data;
-
-        $data->groupingid = $this->get_new_parentid('grouping'); // Use new parentid
-        $data->groupid    = $this->get_mappingid('group', $data->groupid); // Get from mappings
+        global $CFG;
 
-        $params = array();
-        $params['groupingid'] = $data->groupingid;
-        $params['groupid']    = $data->groupid;
+        require_once($CFG->dirroot.'/group/lib.php');
 
-        if (!$DB->record_exists('groupings_groups', $params)) {
-            $DB->insert_record('groupings_groups', $data);  // No need to set this mapping (no child info nor files)
-        }
+        $data = (object)$data;
+        groups_assign_grouping($this->get_new_parentid('grouping'), $this->get_mappingid('group', $data->groupid), $data->timeadded);
     }
 
     protected function after_execute() {
index e856ead..c4d42d4 100644 (file)
@@ -1148,14 +1148,16 @@ abstract class restore_dbops {
     *
     *  If restoring users from same site backup:
     *      1A - Normal check: If match by id and username and mnethost  => ok, return target user
-    *      1B - Handle users deleted in DB and "alive" in backup file:
+    *      1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a
+    *           match by username only => ok, return target user MDL-31484
+    *      1C - Handle users deleted in DB and "alive" in backup file:
     *           If match by id and mnethost and user is deleted in DB and
     *           (match by username LIKE 'backup_email.%' or by non empty email = md5(username)) => ok, return target user
-    *      1C - Handle users deleted in backup file and "alive" in DB:
+    *      1D - Handle users deleted in backup file and "alive" in DB:
     *           If match by id and mnethost and user is deleted in backup file
     *           and match by email = email_without_time(backup_email) => ok, return target user
-    *      1D - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false
-    *      1E - None of the above, return true => User needs to be created
+    *      1E - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false
+    *      1F - None of the above, return true => User needs to be created
     *
     *  if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination):
     *      2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
@@ -1187,7 +1189,16 @@ abstract class restore_dbops {
                 return $rec; // Matching user found, return it
             }
 
-            // 1B - Handle users deleted in DB and "alive" in backup file
+            // 1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a
+            // match by username only => ok, return target user MDL-31484
+            // This avoids username / id mis-match problems when restoring subsequent anonymized backups.
+            if (backup_anonymizer_helper::is_anonymous_user($user)) {
+                if ($rec = $DB->get_record('user', array('username' => $user->username))) {
+                    return $rec; // Matching anonymous user found - return it
+                }
+            }
+
+            // 1C - Handle users deleted in DB and "alive" in backup file
             // Note: for DB deleted users email is stored in username field, hence we
             //       are looking there for emails. See delete_user()
             // Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
@@ -1210,7 +1221,7 @@ abstract class restore_dbops {
                 return $rec; // Matching user, deleted in DB found, return it
             }
 
-            // 1C - Handle users deleted in backup file and "alive" in DB
+            // 1D - Handle users deleted in backup file and "alive" in DB
             // If match by id and mnethost and user is deleted in backup file
             // and match by email = email_without_time(backup_email) => ok, return target user
             if ($user->deleted) {
@@ -1228,7 +1239,7 @@ abstract class restore_dbops {
                 }
             }
 
-            // 1D - If match by username and mnethost and doesn't match by id => conflict, return false
+            // 1E - If match by username and mnethost and doesn't match by id => conflict, return false
             if ($rec = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) {
                 if ($user->id != $rec->id) {
                     return false; // Conflict, username already exists and belongs to another id
index be56d2c..04a9d2d 100644 (file)
  */
 class backup_anonymizer_helper {
 
+    /**
+     * Determine if the given user is an 'anonymous' user, based on their username, firstname, lastname
+     * and email address.
+     * @param stdClass $user the user record to test
+     * @return bool true if this is an 'anonymous' user
+     */
+    public static function is_anonymous_user($user) {
+        if (preg_match('/^anon\d*$/', $user->username)) {
+            $match = preg_match('/^anonfirstname\d*$/', $user->firstname);
+            $match = $match && preg_match('/^anonlastname\d*$/', $user->lastname);
+            $match = $match && preg_match('/^anon\d*@doesntexist\.com$/', $user->email);
+            if ($match) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public static function process_user_auth($value) {
         return 'manual'; // Set them to manual always
     }
index 8cbe681..ae01911 100644 (file)
@@ -34,6 +34,7 @@ require_once($CFG->dirroot . '/backup/util/interfaces/executable.class.php');
 require_once($CFG->dirroot . '/backup/util/interfaces/processable.class.php');
 require_once($CFG->dirroot . '/backup/backup.class.php');
 require_once($CFG->dirroot . '/backup/util/structure/restore_path_element.class.php');
+require_once($CFG->dirroot . '/backup/util/helper/backup_anonymizer_helper.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/backup_file_manager.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/restore_prechecks_helper.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/restore_moodlexml_parser_processor.class.php');
index 76efcf3..ad8aa52 100644 (file)
@@ -157,8 +157,7 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
                         scope: scope
                     },
                     headers: {
-                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
-                        'User-Agent': 'MoodleComment/3.0'
+                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                     },
                     data: build_querystring(params)
                 };
@@ -472,8 +471,7 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
                             scope: this
                         },
                         headers: {
-                            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
-                            'User-Agent': 'MoodleComment/3.0'
+                            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                         },
                         data: build_querystring(data)
                     };
index 2dcaa13..fda43af 100644 (file)
@@ -728,6 +728,9 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+                            if (!parseInt(result.visible, 10)) {
+                                resel.a.className = 'dimmed';
+                            }
 
                             if (result.groupingname) {
                                 resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
@@ -915,6 +918,9 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+                            if (!parseInt(result.visible, 10)) {
+                                resel.a.className = 'dimmed';
+                            }
 
                             if (result.groupingname) {
                                 resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
index 2aa6b02..10cedba 100644 (file)
@@ -620,12 +620,18 @@ class dndupload_ajax_processor {
             throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name);
         }
 
+        // Note the section visibility
+        $visible = get_fast_modinfo($this->course)->get_section_info($this->section)->visible;
+
         $DB->set_field('course_modules', 'instance', $instanceid, array('id' => $this->cm->id));
 
         $sectionid = add_mod_to_section($this->cm);
         $DB->set_field('course_modules', 'section', $sectionid, array('id' => $this->cm->id));
 
-        set_coursemodule_visible($this->cm->id, true);
+        set_coursemodule_visible($this->cm->id, $visible);
+        if (!$visible) {
+            $DB->set_field('course_modules', 'visibleold', 1, array('id' => $this->cm->id));
+        }
 
         // Rebuild the course cache and retrieve the final info about this module.
         rebuild_course_cache($this->course->id, true);
@@ -636,7 +642,7 @@ class dndupload_ajax_processor {
             delete_course_module($this->cm->id);
             throw new moodle_exception('errorcreatingactivity', 'moodle', '', $this->module->name);
         }
-        $mod = $info->cms[$this->cm->id];
+        $mod = $info->get_cm($this->cm->id);
         $mod->groupmodelink = $this->cm->groupmodelink;
         $mod->groupmode = $this->cm->groupmode;
 
@@ -675,6 +681,7 @@ class dndupload_ajax_processor {
         $resp->elementid = 'module-'.$mod->id;
         $resp->commands = make_editing_buttons($mod, true, true, 0, $mod->sectionnum);
         $resp->onclick = $mod->get_on_click();
+        $resp->visible = $mod->visible;
 
         // if using groupings, then display grouping name
         if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
index bcb237a..7d22c94 100644 (file)
@@ -257,7 +257,7 @@ class course_edit_form extends moodleform {
                 array(0=>get_string('completiondisabled','completion'), 1=>get_string('completionenabled','completion')));
             $mform->setDefault('enablecompletion', $courseconfig->enablecompletion);
 
-            $mform->addElement('checkbox', 'completionstartonenrol', get_string('completionstartonenrol', 'completion'));
+            $mform->addElement('advcheckbox', 'completionstartonenrol', get_string('completionstartonenrol', 'completion'));
             $mform->setDefault('completionstartonenrol', $courseconfig->completionstartonenrol);
             $mform->disabledIf('completionstartonenrol', 'enablecompletion', 'eq', 0);
         } else {
index c307a6d..2ec254c 100644 (file)
@@ -57,7 +57,7 @@ if (!empty($CFG->enableavailability)) {
 }
 
 $mform = new editsection_form($PAGE->url, array('course' => $course, 'editoroptions' => $editoroptions,
-        'cs' => $section, 'showavailability' => $section->showavailability));
+        'cs' => $section));
 $mform->set_data($section); // set current value
 
 $returnurl = course_get_url($course, $sectionreturn);
index 73723af..edd156b 100644 (file)
@@ -54,11 +54,19 @@ class editsection_form extends moodleform {
                 $mform->addHelpButton('groupingid', 'groupingsection', 'group');
             }
 
-            // Date and time conditions
+            // Available from/to defaults to midnight because then the display
+            // will be nicer where it tells users when they can access it (it
+            // shows only the date and not time).
+            $date = usergetdate(time());
+            $midnight = make_timestamp($date['year'], $date['mon'], $date['mday']);
+
+            // Date and time conditions.
             $mform->addElement('date_time_selector', 'availablefrom',
-                    get_string('availablefrom', 'condition'), array('optional' => true));
+                    get_string('availablefrom', 'condition'),
+                    array('optional' => true, 'defaulttime' => $midnight));
             $mform->addElement('date_time_selector', 'availableuntil',
-                    get_string('availableuntil', 'condition'), array('optional' => true));
+                    get_string('availableuntil', 'condition'),
+                    array('optional' => true, 'defaulttime' => $midnight));
 
             // Conditions based on grades
             $gradeoptions = array();
@@ -162,8 +170,6 @@ class editsection_form extends moodleform {
                 CONDITION_STUDENTVIEW_HIDE => get_string('showavailabilitysection_hide', 'condition'));
             $mform->addElement('select', 'showavailability',
                     get_string('showavailabilitysection', 'condition'), $showhide);
-
-            $mform->setDefault('showavailability', $this->_customdata['showavailability']);
         }
 
         $this->add_action_buttons();
@@ -174,10 +180,41 @@ class editsection_form extends moodleform {
         // Conditions: Don't let them set dates which make no sense
         if (array_key_exists('availablefrom', $data) &&
                 $data['availablefrom'] && $data['availableuntil'] &&
-                $data['availablefrom'] > $data['availableuntil']) {
+                $data['availablefrom'] >= $data['availableuntil']) {
             $errors['availablefrom'] = get_string('badavailabledates', 'condition');
         }
 
+        // Conditions: Verify that the grade conditions are numbers, and make sense.
+        if (array_key_exists('conditiongradegroup', $data)) {
+            foreach ($data['conditiongradegroup'] as $i => $gradedata) {
+                if ($gradedata['conditiongrademin'] !== '' &&
+                        !is_numeric(unformat_float($gradedata['conditiongrademin']))) {
+                    $errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
+                    continue;
+                }
+                if ($gradedata['conditiongrademax'] !== '' &&
+                        !is_numeric(unformat_float($gradedata['conditiongrademax']))) {
+                    $errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
+                    continue;
+                }
+                if ($gradedata['conditiongrademin'] !== '' && $gradedata['conditiongrademax'] !== '' &&
+                        unformat_float($gradedata['conditiongrademax']) <= unformat_float($gradedata['conditiongrademin'])) {
+                    $errors["conditiongradegroup[{$i}]"] = get_string('badgradelimits', 'condition');
+                    continue;
+                }
+                if ($gradedata['conditiongrademin'] === '' && $gradedata['conditiongrademax'] === '' &&
+                        $gradedata['conditiongradeitemid']) {
+                    $errors["conditiongradegroup[{$i}]"] = get_string('gradeitembutnolimits', 'condition');
+                    continue;
+                }
+                if (($gradedata['conditiongrademin'] !== '' || $gradedata['conditiongrademax'] !== '') &&
+                        !$gradedata['conditiongradeitemid']) {
+                    $errors["conditiongradegroup[{$i}]"] = get_string('gradelimitsbutnoitem', 'condition');
+                    continue;
+                }
+            }
+        }
+
         return $errors;
     }
 }
index d832388..3fbb59b 100644 (file)
@@ -175,7 +175,8 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         }
         $o.= html_writer::end_tag('div');
 
-        $o .= $this->section_availability_message($section);
+        $o .= $this->section_availability_message($section,
+                has_capability('moodle/course:viewhiddensections', $context));
 
         return $o;
     }
@@ -305,7 +306,9 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o.= html_writer::end_tag('div');
         $o.= $this->section_activity_summary($section, $course, $mods);
 
-        $o.= $this->section_availability_message($section);
+        $context = context_course::instance($course->id);
+        $o .= $this->section_availability_message($section,
+                has_capability('moodle/course:viewhiddensections', $context));
 
         $o .= html_writer::end_tag('div');
         $o .= html_writer::end_tag('li');
@@ -388,22 +391,38 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
     }
 
     /**
-     * If section is not visible to current user, display the message about that
-     * ('Not available until...', that sort of thing). Otherwise, returns blank.
+     * If section is not visible, display the message about that ('Not available
+     * until...', that sort of thing). Otherwise, returns blank.
+     *
+     * For users with the ability to view hidden sections, it shows the
+     * information even though you can view the section and also may include
+     * slightly fuller information (so that teachers can tell when sections
+     * are going to be unavailable etc). This logic is the same as for
+     * activities.
      *
      * @param stdClass $section The course_section entry from DB
+     * @param bool $canviewhidden True if user can view hidden sections
      * @return string HTML to output
      */
-    protected function section_availability_message($section) {
+    protected function section_availability_message($section, $canviewhidden) {
+        global $CFG;
         $o = '';
-        if (!$section->uservisible || $section->availableinfo) {
+        if (!$section->uservisible) {
             $o .= html_writer::start_tag('div', array('class' => 'availabilityinfo'));
-            if (!empty($section->availableinfo)) {
-                $o .= $section->availableinfo;
-            } else {
-                $o .= get_string('notavailable');
-            }
+            // Note: We only get to this function if availableinfo is non-empty,
+            // so there is definitely something to print.
+            $o .= $section->availableinfo;
             $o .= html_writer::end_tag('div');
+        } else if ($canviewhidden && !empty($CFG->enableavailability) && $section->visible) {
+            $ci = new condition_info_section($section);
+            $fullinfo = $ci->get_full_information();
+            if ($fullinfo) {
+                $o .= html_writer::start_tag('div', array('class' => 'availabilityinfo'));
+                $o .= get_string(
+                        ($section->showavailability ? 'userrestriction_visible' : 'userrestriction_hidden'),
+                        'condition', $fullinfo);
+                $o .= html_writer::end_tag('div');
+            }
         }
         return $o;
     }
@@ -677,9 +696,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 $thissection->showavailability = 0;
             }
             // Show the section if the user is permitted to access it, OR if it's not available
-            // but showavailability is turned on
+            // but showavailability is turned on (and there is some available info text).
             $showsection = $thissection->uservisible ||
-                    ($thissection->visible && !$thissection->available && $thissection->showavailability);
+                    ($thissection->visible && !$thissection->available && $thissection->showavailability
+                    && !empty($thissection->availableinfo));
             if (!$showsection) {
                 // Hidden section message is overridden by 'unavailable' control
                 // (showavailability option).
@@ -716,7 +736,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                     continue;
                 }
                 echo $this->stealth_section_header($section);
-                print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, $displaysection);
+                print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, 0);
                 echo $this->stealth_section_footer();
             }
 
index f315d4e..2b4e46b 100644 (file)
@@ -67,12 +67,11 @@ $straction = get_string('action');
 $strfulllistofcourses = get_string('fulllistofcourses');
 
 
-/// Unless it's an editing admin, just print the regular listing of courses/categories
+// Unless it's an editing admin, just print the regular listing of courses/categories.
 if (!$adminediting) {
-
-/// Print form for creating new categories
+    $showaddcoursebutton = true;
+    // Print form for creating new categories.
     $countcategories = $DB->count_records('course_categories');
-
     if ($countcategories > 1 || ($countcategories == 1 && $DB->count_records('course') > 200)) {
         $strcourses = get_string('courses');
         $strcategories = get_string('categories');
@@ -96,14 +95,13 @@ if (!$adminediting) {
         echo $OUTPUT->header();
         echo $OUTPUT->skip_link_target();
         echo $OUTPUT->box_start('courseboxes');
-        print_courses(0);
+        $showaddcoursebutton = print_courses(0);
         echo $OUTPUT->box_end();
     }
 
     echo $OUTPUT->container_start('buttons');
-    if (has_capability('moodle/course:create', $systemcontext)) {
-    /// Print link to create a new course
-    /// Get the 1st available category
+    if (has_capability('moodle/course:create', $systemcontext) && $showaddcoursebutton) {
+        // Print link to create a new course, for the 1st available category.
         $options = array('category' => $CFG->defaultrequestcategory);
         echo $OUTPUT->single_button(new moodle_url('edit.php', $options), get_string('addnewcourse'), 'get');
     }
index 54dfc74..6be968a 100644 (file)
@@ -2457,7 +2457,9 @@ function update_category_button($categoryid = 0) {
 }
 
 /**
- * Category is 0 (for all courses) or an object
+ * Print courses in category. If category is 0 then all courses are printed.
+ * @param int|stdClass $category category object or id.
+ * @return bool true if courses found and printed, else false.
  */
 function print_courses($category) {
     global $CFG, $OUTPUT;
@@ -2505,8 +2507,10 @@ function print_courses($category) {
             echo html_writer::start_tag('div', array('class'=>'addcoursebutton'));
             echo $OUTPUT->single_button(new moodle_url('/course/edit.php', $options), get_string("addnewcourse"));
             echo html_writer::end_tag('div');
+            return false;
         }
     }
+    return true;
 }
 
 /**
@@ -2606,6 +2610,7 @@ function print_course($course, $highlightterms = '') {
     if ($icons = enrol_get_course_info_icons($course)) {
         echo html_writer::start_tag('div', array('class'=>'enrolmenticons'));
         foreach ($icons as $icon) {
+            $icon->attributes["alt"] .= ": ". format_string($coursename, true, array('context'=>$context));
             echo $OUTPUT->render($icon);
         }
         echo html_writer::end_tag('div'); // End of enrolmenticons div
@@ -2874,6 +2879,13 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
         return false;
     }
+
+    // Create events and propagate visibility to associated grade items if the value has changed.
+    // Only do this if it's changed to avoid accidently overwriting manual showing/hiding of student grades.
+    if ($cm->visible == $visible) {
+        return true;
+    }
+
     if (!$modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
         return false;
     }
@@ -2887,7 +2899,7 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
         }
     }
 
-    // hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there
+    // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
     $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
     if ($grade_items) {
         foreach ($grade_items as $grade_item) {
@@ -3144,13 +3156,16 @@ function moveto_module($mod, $section, $beforemod=NULL) {
 
 /// Update module itself if necessary
 
-    if ($mod->section != $section->id) {
-        $mod->section = $section->id;
-        $DB->update_record("course_modules", $mod);
-        // if moving to a hidden section then hide module
-        if (!$section->visible) {
-            set_coursemodule_visible($mod->id, 0);
-        }
+    // If moving to a hidden section then hide module.
+    if (!$section->visible && $mod->visible) {
+        // Set this in the object because it is sent as a response to ajax calls.
+        set_coursemodule_visible($mod->id, 0, true);
+        $mod->visible = 0;
+    }
+    if ($section->visible && !$mod->visible) {
+        set_coursemodule_visible($mod->id, 1, true);
+        // Set this in the object because it is sent as a response to ajax calls.
+        $mod->visible = $mod->visibleold;
     }
 
 /// Add the module into the new section
index 7aa8667..00cc318 100644 (file)
@@ -481,6 +481,7 @@ if ($mform->is_cancelled()) {
         // make sure visibility is set correctly (in particular in calendar)
         // note: allow them to set it even without moodle/course:activityvisibility
         set_coursemodule_visible($fromform->coursemodule, $fromform->visible);
+        $DB->set_field('course_modules', 'visibleold', 1, array('id' => $fromform->coursemodule));
 
         if (isset($fromform->cmidnumber)) { //label
             // set cm idnumber - uniqueness is already verified by form validation
index 292387b..a62cb97 100644 (file)
@@ -332,7 +332,7 @@ abstract class moodleform_mod extends moodleform {
                     continue;
                 }
                 if ($gradedata['conditiongrademin'] !== '' && $gradedata['conditiongrademax'] !== '' &&
-                        unformat_float($gradedata['conditiongrademax']) < unformat_float($gradedata['conditiongrademin'])) {
+                        unformat_float($gradedata['conditiongrademax']) <= unformat_float($gradedata['conditiongrademin'])) {
                     $errors["conditiongradegroup[{$i}]"] = get_string('badgradelimits', 'condition');
                     continue;
                 }
index a7b55c9..11b58aa 100644 (file)
@@ -138,6 +138,7 @@ switch($requestmethod) {
                         }
 
                         moveto_module($cm, $section, $beforemod);
+                        echo json_encode(array('visible' => $cm->visible));
                         break;
                     case 'gettitle':
                         require_capability('moodle/course:manageactivities', $modcontext);
index 984b9ed..bdfc636 100644 (file)
@@ -76,6 +76,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         $createdcats = core_course_external::create_categories($categories);
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $createdcats = external_api::clean_returnvalue(core_course_external::create_categories_returns(), $createdcats);
+
         // Initially confirm that base data was inserted correctly.
         $this->assertEquals($category1->name, $createdcats[0]['name']);
         $this->assertEquals($category2->name, $createdcats[1]['name']);
@@ -93,6 +96,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         $createdsubcats = core_course_external::create_categories($subcategories);
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $createdsubcats = external_api::clean_returnvalue(core_course_external::create_categories_returns(), $createdsubcats);
+
         // Confirm that sub categories were inserted correctly.
         $this->assertEquals($category3->name, $createdsubcats[0]['name']);
 
@@ -197,6 +203,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
             array('key' => 'id', 'value' => $category1->id),
             array('key' => 'visible', 'value' => 1)), 1);
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories);
+
         // Check we retrieve the good total number of categories.
         $this->assertEquals(2, count($categories));
 
@@ -214,6 +223,10 @@ class core_course_external_testcase extends externallib_advanced_testcase {
             array('key' => 'id', 'value' => $category1->id),
             array('key' => 'idnumber', 'value' => $category1->idnumber),
             array('key' => 'visible', 'value' => 1)), 0);
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories);
+
         $this->assertEquals(1, count($categories));
 
         // Retrieve categories from parent.
@@ -223,6 +236,10 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         // Retrieve all categories.
         $categories = core_course_external::get_categories();
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $categories = external_api::clean_returnvalue(core_course_external::get_categories_returns(), $categories);
+
         $this->assertEquals($DB->count_records('course_categories'), count($categories));
 
         // Call without required capability (it will fail cause of the search on idnumber).
@@ -343,6 +360,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         $createdcourses = core_course_external::create_courses($courses);
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $createdcourses = external_api::clean_returnvalue(core_course_external::create_courses_returns(), $createdcourses);
+
         // Check that right number of courses were created.
         $this->assertEquals(2, count($createdcourses));
 
@@ -475,6 +495,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         $courses = core_course_external::get_courses(array('ids' =>
             array($course1->id, $course2->id)));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $courses = external_api::clean_returnvalue(core_course_external::get_courses_returns(), $courses);
+
         // Check we retrieve the good total number of categories.
         $this->assertEquals(2, count($courses));
 
@@ -508,6 +531,10 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         // Get all courses in the DB
         $courses = core_course_external::get_courses(array());
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $courses = external_api::clean_returnvalue(core_course_external::get_courses_returns(), $courses);
+
         $this->assertEquals($DB->count_records('course'), count($courses));
     }
 
@@ -535,6 +562,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         $courses = core_course_external::get_course_contents($course->id, array());
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $courses = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $courses);
+
         // Check that the course has the 3 created modules
         $this->assertEquals(3, count($courses[0]['modules']));
     }
@@ -578,6 +608,9 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         $duplicate = core_course_external::duplicate_course($course->id, $newcourse['fullname'],
                 $newcourse['shortname'], $newcourse['categoryid'], $newcourse['visible'], $newcourse['options']);
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $duplicate = external_api::clean_returnvalue(core_course_external::duplicate_course_returns(), $duplicate);
+
         // Check that the course has been duplicated.
         $this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
     }
index bd35bd9..e741d9c 100644 (file)
@@ -385,6 +385,9 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                         spinner.show();
                     },
                     success: function(tid, response) {
+                        var responsetext = Y.JSON.parse(response.responseText);
+                        var params = {element: dragnode, visible: responsetext.visible};
+                        M.course.coursebase.invoke_function('set_visibility_resource_ui', params);
                         this.unlock_drag_handle(drag, CSS.EDITINGMOVE);
                         window.setTimeout(function(e) {
                             spinner.hide();
index 28b9081..f7ff2c6 100644 (file)
@@ -152,6 +152,9 @@ YUI.add('moodle-course-modchooser', function(Y) {
     {
         NAME : MODCHOOSERNAME,
         ATTRS : {
+            maxheight : {
+                value : 800
+            }
         }
     });
     M.course = M.course || {};
index 2486fba..cdb2020 100644 (file)
@@ -259,15 +259,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
         },
         _setup_for_resource : function(toolboxtarget) {
             toolboxtarget = Y.one(toolboxtarget);
-            // "Disable" show/hide icons (change cursor to not look clickable) if section is hidden
-            var showhide = toolboxtarget.all(CSS.COMMANDSPAN + ' ' + CSS.HIDE);
-            showhide.concat(toolboxtarget.all(CSS.COMMANDSPAN + ' ' + CSS.SHOW));
-            showhide.each(function(node) {
-                var section = node.ancestor(CSS.SECTIONLI);
-                if (section && section.hasClass(CSS.SECTIONHIDDENCLASS)) {
-                    node.setStyle('cursor', 'auto');
-                }
-            });
 
             // Set groupmode attribute for use by this.toggle_groupmode()
             var groups;
@@ -600,6 +591,26 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 }
             }, this);
             listenevents.push(thisevent);
+        },
+        /**
+         * Set the visibility of the current resource (identified by the element)
+         * to match the hidden parameter (this is not a toggle).
+         * Only changes the visibility in the browser (no ajax update).
+         * @param args An object with 'element' being the A node containing the resource
+         *             and 'visible' being the state that the visiblity should be set to.
+         * @return void
+         */
+        set_visibility_resource_ui: function(args) {
+            var element = args.element;
+            var shouldbevisible = args.visible;
+            var buttonnode = element.one(CSS.SHOW);
+            var visible = (buttonnode === null);
+            if (visible) {
+                buttonnode = element.one(CSS.HIDE);
+            }
+            if (visible != shouldbevisible) {
+                this.toggle_hide_resource_ui(buttonnode);
+            }
         }
     }, {
         NAME : 'course-resource-toolbox',
@@ -707,12 +718,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 if (Y.Array.indexOf(response.resourcestotoggle, activityid) != -1) {
                     this.toggle_hide_resource_ui(button);
                 }
-
-                if (value == 0) {
-                    button.setStyle('cursor', 'auto');
-                } else {
-                    button.setStyle('cursor', 'pointer');
-                }
             }, this);
         },
         toggle_highlight : function(e) {
index e923c2e..1577265 100644 (file)
@@ -792,7 +792,9 @@ class course_enrolment_manager {
                         break;
                 }
             }
-            $users[$userrole->id]['roles'] = array();
+            if (!isset($users[$userrole->id]['roles'])) {
+                $users[$userrole->id]['roles'] = array();
+            }
             $users[$userrole->id]['roles'][$userrole->roleid] = array(
                 'text' => $roletext,
                 'unchangeable' => !$changeable
index 4c6dc8b..9fc233c 100644 (file)
@@ -304,7 +304,10 @@ class core_files_renderer extends plugin_renderer_base {
     private function fm_js_template_mkdir() {
         $rv = '
 <div class="filemanager fp-mkdir-dlg">
-    <div class="fp-mkdir-dlg-text">'.get_string('newfoldername','repository').'<br/><input type="text" /></div>
+    <div class="fp-mkdir-dlg-text">
+        <label>' . get_string('newfoldername', 'repository') . '</label><br/>
+        <input type="text" />
+    </div>
     <button class="{!}fp-dlg-butcreate">'.get_string('makeafolder').'</button>
     <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
 </div>';
index 3b4cc42..9f0eabb 100644 (file)
@@ -181,7 +181,7 @@ class grade_report_grader extends grade_report {
         // Were any changes made?
         $changedgrades = false;
 
-        foreach ($data as $varname => $postedvalue) {
+        foreach ($data as $varname => $students) {
 
             $needsupdate = false;
 
@@ -194,113 +194,116 @@ class grade_report_grader extends grade_report {
                 continue;
             }
 
-            $gradeinfo = explode("_", $varname);
-            $userid = clean_param($gradeinfo[1], PARAM_INT);
-            $itemid = clean_param($gradeinfo[2], PARAM_INT);
+            foreach ($students as $userid => $items) {
+                $userid = clean_param($userid, PARAM_INT);
+                foreach ($items as $itemid => $postedvalue) {
+                    $itemid = clean_param($itemid, PARAM_INT);
+
+                    // Was change requested?
+                    $oldvalue = $this->grades[$userid][$itemid];
+                    if ($datatype === 'grade') {
+                        // If there was no grade and there still isn't
+                        if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
+                            // -1 means no grade
+                            continue;
+                        }
 
-            // Was change requested?
-            $oldvalue = $this->grades[$userid][$itemid];
-            if ($datatype === 'grade') {
-                // If there was no grade and there still isn't
-                if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
-                    // -1 means no grade
-                    continue;
-                }
+                        // If the grade item uses a custom scale
+                        if (!empty($oldvalue->grade_item->scaleid)) {
 
-                // If the grade item uses a custom scale
-                if (!empty($oldvalue->grade_item->scaleid)) {
+                            if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
+                                continue;
+                            }
+                        } else {
+                            // The grade item uses a numeric scale
 
-                    if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
-                        continue;
-                    }
-                } else {
-                    // The grade item uses a numeric scale
+                            // Format the finalgrade from the DB so that it matches the grade from the client
+                            if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
+                                continue;
+                            }
+                        }
 
-                    // Format the finalgrade from the DB so that it matches the grade from the client
-                    if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
-                        continue;
+                        $changedgrades = true;
+
+                    } else if ($datatype === 'feedback') {
+                        if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
+                            continue;
+                        }
                     }
-                }
 
-                $changedgrades = true;
+                    if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) {
+                        print_error('invalidgradeitemid');
+                    }
 
-            } else if ($datatype === 'feedback') {
-                if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
-                    continue;
-                }
-            }
+                    // Pre-process grade
+                    if ($datatype == 'grade') {
+                        $feedback = false;
+                        $feedbackformat = false;
+                        if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
+                            if ($postedvalue == -1) { // -1 means no grade
+                                $finalgrade = null;
+                            } else {
+                                $finalgrade = $postedvalue;
+                            }
+                        } else {
+                            $finalgrade = unformat_float($postedvalue);
+                        }
 
-            if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) { // we must verify course id here!
-                print_error('invalidgradeitemid');
-            }
+                        $errorstr = '';
+                        // Warn if the grade is out of bounds.
+                        if (is_null($finalgrade)) {
+                            // ok
+                        } else {
+                            $bounded = $gradeitem->bounded_grade($finalgrade);
+                            if ($bounded > $finalgrade) {
+                            $errorstr = 'lessthanmin';
+                            } else if ($bounded < $finalgrade) {
+                                $errorstr = 'morethanmax';
+                            }
+                        }
+                        if ($errorstr) {
+                            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
+                            $gradestr = new stdClass();
+                            $gradestr->username = fullname($user);
+                            $gradestr->itemname = $gradeitem->get_name();
+                            $warnings[] = get_string($errorstr, 'grades', $gradestr);
+                        }
 
-            // Pre-process grade
-            if ($datatype == 'grade') {
-                $feedback = false;
-                $feedbackformat = false;
-                if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
-                    if ($postedvalue == -1) { // -1 means no grade
-                        $finalgrade = null;
-                    } else {
-                        $finalgrade = $postedvalue;
+                    } else if ($datatype == 'feedback') {
+                        $finalgrade = false;
+                        $trimmed = trim($postedvalue);
+                        if (empty($trimmed)) {
+                             $feedback = NULL;
+                        } else {
+                             $feedback = $postedvalue;
+                        }
                     }
-                } else {
-                    $finalgrade = unformat_float($postedvalue);
-                }
 
-                $errorstr = '';
-                // Warn if the grade is out of bounds.
-                if (is_null($finalgrade)) {
-                    // ok
-                } else {
-                    $bounded = $gradeitem->bounded_grade($finalgrade);
-                    if ($bounded > $finalgrade) {
-                    $errorstr = 'lessthanmin';
-                    } else if ($bounded < $finalgrade) {
-                        $errorstr = 'morethanmax';
+                    // group access control
+                    if ($separategroups) {
+                        // note: we can not use $this->currentgroup because it would fail badly
+                        //       when having two browser windows each with different group
+                        $sharinggroup = false;
+                        foreach($mygroups as $groupid) {
+                            if (groups_is_member($groupid, $userid)) {
+                                $sharinggroup = true;
+                                break;
+                            }
+                        }
+                        if (!$sharinggroup) {
+                            // either group membership changed or somebody is hacking grades of other group
+                            $warnings[] = get_string('errorsavegrade', 'grades');
+                            continue;
+                        }
                     }
-                }
-                if ($errorstr) {
-                    $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
-                    $gradestr = new stdClass();
-                    $gradestr->username = fullname($user);
-                    $gradestr->itemname = $gradeitem->get_name();
-                    $warnings[] = get_string($errorstr, 'grades', $gradestr);
-                }
 
-            } else if ($datatype == 'feedback') {
-                $finalgrade = false;
-                $trimmed = trim($postedvalue);
-                if (empty($trimmed)) {
-                     $feedback = NULL;
-                } else {
-                     $feedback = $postedvalue;
-                }
-            }
+                    $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
 
-            // group access control
-            if ($separategroups) {
-                // note: we can not use $this->currentgroup because it would fail badly
-                //       when having two browser windows each with different group
-                $sharinggroup = false;
-                foreach($mygroups as $groupid) {
-                    if (groups_is_member($groupid, $userid)) {
-                        $sharinggroup = true;
-                        break;
+                    // We can update feedback without reloading the grade item as it doesn't affect grade calculations
+                    if ($datatype === 'feedback') {
+                        $this->grades[$userid][$itemid]->feedback = $feedback;
                     }
                 }
-                if (!$sharinggroup) {
-                    // either group membership changed or somebody is hacking grades of other group
-                    $warnings[] = get_string('errorsavegrade', 'grades');
-                    continue;
-                }
-            }
-
-            $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
-
-            // We can update feedback without reloading the grade item as it doesn't affect grade calculations
-            if ($datatype === 'feedback') {
-                $this->grades[$userid][$itemid]->feedback = $feedback;
             }
         }
 
@@ -1017,7 +1020,7 @@ class grade_report_grader extends grade_report {
                             }
                             $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
                             $itemcell->text .= html_writer::label(get_string('typescale', 'grades'), $attributes['id'], false, array('class' => 'accesshide'));
-                            $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);
+                            $itemcell->text .= html_writer::select($scaleopt, 'grade['.$userid.']['.$item->id.']', $gradeval, array(-1=>$nogradestr), $attributes);
                         } elseif(!empty($scale)) {
                             $scales = explode(",", $scale->scale);
 
@@ -1036,8 +1039,8 @@ class grade_report_grader extends grade_report {
                         if ($this->get_pref('quickgrading') and $grade->is_editable()) {
                             $value = format_float($gradeval, $decimalpoints);
                             $itemcell->text .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade']
-                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade_'
-                                          .$userid.'_' .$item->id.'" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
+                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade['
+                                          .$userid.'][' .$item->id.']" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
                         } else {
                             $itemcell->text .= html_writer::tag('span', format_float($gradeval, $decimalpoints), array('class'=>"gradevalue$hidden$gradepass"));
                         }
@@ -1048,7 +1051,7 @@ class grade_report_grader extends grade_report {
                     if ($this->get_pref('showquickfeedback') and $grade->is_editable()) {
 
                         $itemcell->text .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'].'" id="feedback_'.$userid.'_'.$item->id
-                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_'.$userid.'_'.$item->id.'" value="' . s($grade->feedback) . '" />';
+                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback['.$userid.']['.$item->id.']" value="' . s($grade->feedback) . '" />';
                     }
 
                 } else { // Not editing
@@ -1730,25 +1733,21 @@ class grade_report_grader extends grade_report {
             // Will this number of students result in more fields that we are allowed?
             $maxinputvars = ini_get('max_input_vars');
             if ($maxinputvars !== false) {
-                $fieldspergradeitem = 0; // The number of fields output per grade item for each student
+                // We can't do anything about there being more grade items than max_input_vars,
+                // but we can decrease number of students per page if there are >= max_input_vars
+                $fieldsperstudent = 0; // The number of fields output per student
 
-                if ($this->get_pref('quickgrading')) {
-                    // One grade field
-                    $fieldspergradeitem ++;
-                }
-                if ($this->get_pref('showquickfeedback')) {
-                    // One feedback field
-                    $fieldspergradeitem ++;
+                if ($this->get_pref('quickgrading') || $this->get_pref('showquickfeedback')) {
+                    // Each array (grade, feedback) will gain one element
+                    $fieldsperstudent ++;
                 }
 
-                $fieldsperstudent = $fieldspergradeitem * count($this->gtree->get_items());
                 $fieldsrequired = $studentsperpage * $fieldsperstudent;
-                if ($fieldsrequired > $maxinputvars) {
-                    $studentsperpage = floor($maxinputvars / $fieldsperstudent);
+                if ($fieldsrequired >= $maxinputvars) {
+                    $studentsperpage = $maxinputvars - 1; // Subtract one to be on the safe side
                     if ($studentsperpage<1) {
-                        // Make sure students per page doesn't fall below 1
-                        // PHP max_input_vars could potentially be reached with 1 student
-                        // if there are >500 grade items and quickgrading and showquickfeedback are on
+                        // Make sure students per page doesn't fall below 1, though if your
+                        // max_input_vars is only 1 you've got bigger problems!
                         $studentsperpage = 1;
                     }
 
index 2babb4e..3652d71 100644 (file)
@@ -578,7 +578,7 @@ background-color:#f3ead8;
     vertical-align:middle;
 }
 
-.path-grade-report-grader .yui-overlay {
+.path-grade-report-grader .yui3-overlay {
     background-color: #FFEE69;
     border-color: #D4C237 #A6982B #A6982B;
     border-style: solid;
@@ -588,15 +588,15 @@ background-color:#f3ead8;
     font-size: 0.7em;
 }
 
-.path-grade-report-grader .yui-overlay .fullname {
+.path-grade-report-grader .yui3-overlay .fullname {
     color: #5F3E00;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .itemname {
+.path-grade-report-grader .yui3-overlay .itemname {
     color: #194F3E;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .feedback {
+.path-grade-report-grader .yui3-overlay .feedback {
     color: #5F595E;
 }
 /* table#user-grades td */
@@ -605,7 +605,7 @@ background-color:#f3ead8;
   text-align: left;
 }
 
-.path-grade-report-grader .yui-overlay a.container-close {
+.path-grade-report-grader .yui3-overlay a.container-close {
   margin-top: -3px;
 }
 
index 024e81b..684ed47 100644 (file)
@@ -634,9 +634,10 @@ function groups_parse_name($format, $groupnumber) {
  *
  * @param int groupingid
  * @param int groupid
+ * @param int $timeadded  The time the group was added to the grouping.
  * @return bool true or exception
  */
-function groups_assign_grouping($groupingid, $groupid) {
+function groups_assign_grouping($groupingid, $groupid, $timeadded = null) {
     global $DB;
 
     if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
@@ -645,7 +646,11 @@ function groups_assign_grouping($groupingid, $groupid) {
     $assign = new stdClass();
     $assign->groupingid = $groupingid;
     $assign->groupid    = $groupid;
-    $assign->timeadded  = time();
+    if ($timeadded != null) {
+        $assign->timeadded = (integer)$timeadded;
+    } else {
+        $assign->timeadded = time();
+    }
     $DB->insert_record('groupings_groups', $assign);
 
     return true;
@@ -767,7 +772,7 @@ function groups_calculate_role_people($rs, $context) {
                 $roles[$roledata->id] = $roledata;
             }
             // Record that user has role
-            $users[$rec->userid]->roles[] = $roles[$rec->roleid];
+            $users[$rec->userid]->roles[$rec->roleid] = $roles[$rec->roleid];
         }
     }
     $rs->close();
@@ -797,7 +802,8 @@ function groups_calculate_role_people($rs, $context) {
         } else if($rolecount > 1) {
             $roleid = '*';
         } else {
-            $roleid = $userdata->roles[0]->id;
+            $userrole = reset($userdata->roles);
+            $roleid = $userrole->id;
         }
         $roles[$roleid]->users[$userid] = $userdata;
     }
index ddfffbe..db31bba 100644 (file)
@@ -73,9 +73,9 @@ $string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全'
 $string['pathswrongadmindir'] = '管理目錄不存在';
 $string['phpextension'] = '{$a} PHP擴展';
 $string['phpversion'] = 'PHP版本';
-$string['phpversionhelp'] = '<p>Moodle 需要至少4.1.0.的PHP版本 </p>
+$string['phpversionhelp'] = '<p>Moodle 需要的PHP版本至少要4.3.0或是5.1.0 (5.0.x有一些已知的問題)  </p>
 <p>您目前執行的是{$a} 版</p>
-<p>您必須更新您的 PHP 或在有更新版本的主機進行安裝!</p>';
+<p>您必須更新您的 PHP 或在有更新版本的主機進行安裝!!(若是5.0.x,你可以下降到4.4.x 版本)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['welcomep20'] = '這個頁面是提醒您已經成功安裝與啟動 <strong>{$a->packname} {$a->packversion}</strong> ,恭喜!';
 $string['welcomep30'] = '<strong>{$a->installername}</strong>包含了可以建立<strong>Moodle</strong>執行環境的應用程序:';
index d662beb..0a1a1b2 100644 (file)
 $string['addtodock'] = 'Move this to the dock';
 $string['anypagematchingtheabove'] = 'Any page matching the above';
 $string['appearsinsubcontexts'] = 'Appears in sub-contexts';
+$string['assignrolesinblock'] = 'Assign roles in {$a} block';
 $string['blocksettings'] = 'Block settings';
 $string['bracketfirst'] = '{$a} (first)';
 $string['bracketlast'] = '{$a} (last)';
+$string['configureblock'] = 'Configure {$a} block';
 $string['contexts'] = 'Page contexts';
 $string['contexts_help'] = 'Contexts are more specific types of pages where this block can be displayed within the original block location. You will have different options here depending on the original block location and your current location. For example, you can restrict a block to only appearing on forum pages in a course by adding the block to the course (making it appear on all sub-pages), then going into a forum and editing the block settings again to restrict display to just forum pages.';
 $string['createdat'] = 'Original block location';
@@ -38,15 +40,19 @@ $string['defaultregion_help'] = 'Themes may define one or more named block regio
 $string['defaultweight'] = 'Default weight';
 $string['defaultweight_help'] = 'The default weight allows you to choose roughly where you want the block to appear in the chosen region, either at the top or the bottom. The final location is calculated from all the blocks in that region (for example, only one block can actually be at the top). This value can be overridden on specific pages if required.';
 $string['deletecheck'] = 'Delete {$a} block?';
+$string['deleteblock'] = 'Delete {$a} block';
 $string['deleteblockcheck'] = 'Are you sure that you want to delete this block titled {$a}?';
+$string['hideblock'] = 'Hide {$a} block';
 $string['hidedockpanel'] = 'Hide the dock panel';
 $string['hidepanel'] = 'Hide panel';
+$string['moveblock'] = 'Move {$a} block';
 $string['moveblockhere'] = 'Move block here';
 $string['movingthisblockcancel'] = 'Moving this block ({$a})';
 $string['onthispage'] = 'On this page';
 $string['pagetypes'] = 'Page types';
 $string['pagetypewarning'] = 'The previously specified page type is no longer selectable. Please choose the most appropriate page type below.';
 $string['region'] = 'Region';
+$string['showblock'] = 'Show {$a} block';
 $string['showoncontextandsubs'] = 'Display on \'{$a}\' and any pages within it';
 $string['showoncontextonly'] = 'Display on \'{$a}\' only';
 $string['showonentiresite'] = 'Display throughout the entire site';
index 56d1a07..c029060 100644 (file)
@@ -183,13 +183,13 @@ $string['invalidcategoryidforparent'] = 'Invalid category id for parent!';
 $string['invalidcategoryidtomove'] = 'Invalid category id to move!';
 $string['invalidconfirm'] = 'Confirmation string was incorrect';
 $string['invalidcontextinhasanyquestions'] = 'Invalid context passed to question_context_has_any_questions.';
+$string['invalidgrade'] = 'Grades ({$a}) do not match grade options - question skipped.';
 $string['invalidpenalty'] = 'Invalid penalty';
 $string['invalidwizardpage'] = 'Incorrect or no wizard page specified!';
 $string['lastmodifiedby'] = 'Last modified by';
 $string['linkedfiledoesntexist'] = 'Linked file {$a} doesn\'t exist';
 $string['makechildof'] = 'Make child of \'{$a}\'';
 $string['maketoplevelitem'] = 'Move to top level';
-$string['matcherror'] = 'Grades do not match grade options - question skipped';
 $string['matchgrades'] = 'Match grades';
 $string['matchgradeserror'] = 'Error if grade not listed';
 $string['matchgradesnearest'] = 'Nearest grade if not listed';
index 841a000..97d3802 100644 (file)
@@ -1023,13 +1023,15 @@ class block_manager {
         if ($this->page->user_can_edit_blocks()) {
             // Move icon.
             $controls[] = array('url' => $actionurl . '&bui_moveid=' . $block->instance->id,
-                    'icon' => 't/move', 'caption' => get_string('move'), 'class' => 'editing_move');
+                    'icon' => 't/move', 'caption' => get_string('moveblock', 'block', $block->title),
+                    'class' => 'editing_move');
         }
 
         if ($this->page->user_can_edit_blocks() || $block->user_can_edit()) {
             // Edit config icon - always show - needed for positioning UI.
             $controls[] = array('url' => $actionurl . '&bui_editid=' . $block->instance->id,
-                    'icon' => 't/edit', 'caption' => get_string('configuration'), 'class' => 'editing_edit');
+                    'icon' => 't/edit', 'caption' => get_string('configureblock', 'block', $block->title),
+                    'class' => 'editing_edit');
         }
 
         if ($this->page->user_can_edit_blocks() && $block->user_can_edit() && $block->user_can_addto($this->page)) {
@@ -1038,7 +1040,8 @@ class block_manager {
                     || $block->instance->parentcontextid != SITEID) {
                 // Delete icon.
                 $controls[] = array('url' => $actionurl . '&bui_deleteid=' . $block->instance->id,
-                        'icon' => 't/delete', 'caption' => get_string('delete'), 'class' => 'editing_delete');
+                        'icon' => 't/delete', 'caption' => get_string('deleteblock', 'block', $block->title),
+                        'class' => 'editing_delete');
             }
         }
 
@@ -1046,10 +1049,12 @@ class block_manager {
             // Show/hide icon.
             if ($block->instance->visible) {
                 $controls[] = array('url' => $actionurl . '&bui_hideid=' . $block->instance->id,
-                        'icon' => 't/hide', 'caption' => get_string('hide'), 'class' => 'editing_hide');
+                        'icon' => 't/hide', 'caption' => get_string('hideblock', 'block', $block->title),
+                        'class' => 'editing_hide');
             } else {
                 $controls[] = array('url' => $actionurl . '&bui_showid=' . $block->instance->id,
-                        'icon' => 't/show', 'caption' => get_string('show'), 'class' => 'editing_show');
+                        'icon' => 't/show', 'caption' => get_string('showblock', 'block', $block->title),
+                        'class' => 'editing_show');
             }
         }
 
@@ -1063,7 +1068,8 @@ class block_manager {
 
             $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
                     '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return),
-                    'icon' => 'i/roles', 'caption' => get_string('assignroles', 'role'), 'class' => 'editing_roles');
+                    'icon' => 'i/roles', 'caption' => get_string('assignrolesinblock', 'block', $block->title),
+                    'class' => 'editing_roles');
         }
 
         return $controls;
@@ -1271,7 +1277,10 @@ class block_manager {
         } else if ($data = $mform->get_data()) {
             $bi = new stdClass;
             $bi->id = $block->instance->id;
+
+            // This may get overwritten by the special case handling below.
             $bi->pagetypepattern = $data->bui_pagetypepattern;
+            $bi->showinsubcontexts = (bool) $data->bui_contexts;
             if (empty($data->bui_subpagepattern) || $data->bui_subpagepattern == '%@NULL@%') {
                 $bi->subpagepattern = null;
             } else {
index fcc6f58..b293c5c 100644 (file)
@@ -1021,7 +1021,7 @@ class completion_info {
      * @return bool
      */
     public function is_tracked_user($userid) {
-        return is_enrolled(context_course::instance($this->course->id), $userid, '', true);
+        return is_enrolled(context_course::instance($this->course->id), $userid, 'moodle/course:isincompletionreports', true);
     }
 
     /**
@@ -1038,7 +1038,7 @@ class completion_info {
         global $DB;
 
         list($enrolledsql, $enrolledparams) = get_enrolled_sql(
-                context_course::instance($this->course->id), '', $groupid, true);
+                context_course::instance($this->course->id), 'moodle/course:isincompletionreports', $groupid, true);
         $sql  = 'SELECT COUNT(eu.id) FROM (' . $enrolledsql . ') eu JOIN {user} u ON u.id = eu.id';
         if ($where) {
             $sql .= " WHERE $where";
index ce5c160..f01219d 100644 (file)
@@ -1425,6 +1425,7 @@ function &get_mimetypes_array() {
         'isf'  => array ('type'=>'application/inspiration', 'icon'=>'isf'),
         'ist'  => array ('type'=>'application/inspiration.template', 'icon'=>'isf'),
         'java' => array ('type'=>'text/plain', 'icon'=>'sourcecode'),
+        'jar'  => array ('type'=>'application/java-archive', 'icon' => 'archive'),
         'jcb'  => array ('type'=>'text/xml', 'icon'=>'markup'),
         'jcl'  => array ('type'=>'text/xml', 'icon'=>'markup'),
         'jcw'  => array ('type'=>'text/xml', 'icon'=>'markup'),
index bbadd5c..29d5112 100644 (file)
@@ -521,7 +521,8 @@ M.form_dndupload.init = function(Y, options) {
             if (!overwrite) {
                 this.currentfilecount++;
             }
-            if (this.options.maxfiles > 0 && this.currentfilecount > this.options.maxfiles) {
+            // The value for "unlimited files" is -1, so 0 should mean 0.
+            if (this.options.maxfiles >= 0 && this.currentfilecount > this.options.maxfiles) {
                 // Too many files - abort entire upload.
                 this.uploadqueue = [];
                 this.renamequeue = [];
index c715811..9e825e3 100644 (file)
@@ -169,8 +169,7 @@ M.form_filemanager.init = function(Y, options) {
                     scope: scope
                 },
                 headers: {
-                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
-                    'User-Agent': 'MoodleFileManager/3.0'
+                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                 },
                 data: build_querystring(params)
             };
@@ -317,6 +316,7 @@ M.form_filemanager.init = function(Y, options) {
                             on('keydown', function(e){
                                 if (e.keyCode == 13) {Y.bind(perform_action, this)(e);}
                             }, this);
+                        node.one('label').set('for', 'fm-newname-' + this.client_id);
                         node.all('.fp-dlg-butcancel').on('click', function(e){e.preventDefault();this.mkdir_dialog.hide();}, this);
                         node.all('.fp-dlg-curpath').set('id', 'fm-curpath-'+this.client_id);
                     }
index f6d968d..bf3cbdc 100644 (file)
@@ -323,7 +323,8 @@ class form_filemanager implements renderable {
             $defaults['defaultlicense'] = $CFG->sitedefaultlicense;
         }
         foreach ($defaults as $key=>$value) {
-            if (empty($options->$key)) {
+            // Using !isset() prevents us from overwriting falsey values with defaults (as empty() did).
+            if (!isset($options->$key)) {
                 $options->$key = $value;
             }
         }
index 858fe24..5d6f4ee 100644 (file)
@@ -813,6 +813,16 @@ M.util.focus_login_form = function(Y) {
     }
 }
 
+/**
+ * Set focus on login error message
+ */
+M.util.focus_login_error = function(Y) {
+    var errorlog = Y.one('#loginerrormessage');
+
+    if (errorlog) {
+        errorlog.focus();
+    }
+}
 /**
  * Adds lightbox hidden element that covers the whole node.
  *
index 5e1cf96..d00f634 100644 (file)
@@ -2272,15 +2272,14 @@ class paging_bar implements renderable {
                 $lastpage = 1;
             }
 
-            if ($this->page > 15) {
-                $startpage = $this->page - 10;
+            if ($this->page > round(($this->maxdisplay/3)*2)) {
+                $currpage = $this->page - round($this->maxdisplay/3);
 
                 $this->firstlink = html_writer::link(new moodle_url($this->baseurl, array($this->pagevar=>0)), '1', array('class'=>'first'));
             } else {
-                $startpage = 0;
+                $currpage = 0;
             }
 
-            $currpage = $startpage;
             $displaycount = $displaypage = 0;
 
             while ($displaycount < $this->maxdisplay and $currpage < $lastpage) {
index 6ead09f..f94c295 100644 (file)
@@ -93,6 +93,9 @@ $CFG->filepermissions = ($CFG->directorypermissions & 0666);
 if (!isset($CFG->phpunit_dataroot)) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, 'Missing $CFG->phpunit_dataroot in config.php, can not run tests!');
 }
+// Ensure we access to phpunit_dataroot realpath always.
+$CFG->phpunit_dataroot = realpath($CFG->phpunit_dataroot);
+
 if (isset($CFG->dataroot) and $CFG->phpunit_dataroot === $CFG->dataroot) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->dataroot and $CFG->phpunit_dataroot must not be identical, can not run tests!');
 }
index 81ad764..ac7d2bb 100644 (file)
@@ -176,7 +176,7 @@ function plagiarism_cron() {
         $plagiarismplugin->cron();
     }
 }
-/** 
+/**
  * helper function - also loads lib file of plagiarism plugin
  * @return array of available plugins
  */
index c5a75c8..4ac75de 100644 (file)
@@ -179,8 +179,23 @@ class web_testcase extends advanced_testcase {
     }
 
     function test_out_as_local_url() {
+        global $CFG;
+        // Test http url.
         $url1 = new moodle_url('/lib/tests/weblib_test.php');
         $this->assertEquals('/lib/tests/weblib_test.php', $url1->out_as_local_url());
+
+        // Test https url.
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+        $url2 = new moodle_url($httpswwwroot.'/login/profile.php');
+        $this->assertEquals('/login/profile.php', $url2->out_as_local_url());
+
+        // Test http url matching wwwroot.
+        $url3 = new moodle_url($CFG->wwwroot);
+        $this->assertEquals('', $url3->out_as_local_url());
+
+        // Test http url matching wwwroot ending with slash (/).
+        $url3 = new moodle_url($CFG->wwwroot.'/');
+        $this->assertEquals('/', $url3->out_as_local_url());
     }
 
     /**
@@ -192,6 +207,31 @@ class web_testcase extends advanced_testcase {
         $url2->out_as_local_url();
     }
 
+    /**
+     * You should get error with modified url
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_modified_url_out_as_local_url_error() {
+        global $CFG;
+
+        $modifiedurl = $CFG->wwwroot.'1';
+        $url3 = new moodle_url($modifiedurl.'/login/profile.php');
+        $url3->out_as_local_url();
+    }
+
+    /**
+     * Try get local url from external https url and you should get error
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_https_out_as_local_url_error() {
+        $url4 = new moodle_url('https://www.google.com/lib/tests/weblib_test.php');
+        $url4->out_as_local_url();
+    }
+
     public function test_clean_text() {
         $text = "lala <applet>xx</applet>";
         $this->assertEquals($text, clean_text($text, FORMAT_PLAIN));
index 500467b..6c8ebab 100644 (file)
@@ -747,12 +747,18 @@ class moodle_url {
         global $CFG;
 
         $url = $this->out($escaped, $overrideparams);
-
-        if (strpos($url, $CFG->wwwroot) !== 0) {
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+
+        // $url should be equal to wwwroot or httpswwwroot. If not then throw exception.
+        if (($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($CFG->wwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else if (($url === $httpswwwroot) || (strpos($url, $httpswwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($httpswwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else {
             throw new coding_exception('out_as_local_url called on a non-local URL');
         }
-
-        return str_replace($CFG->wwwroot, '', $url);
     }
 
     /**
index c8bd732..03a19cf 100644 (file)
@@ -31,7 +31,7 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
         },
 
         prepare_chooser : function () {
-            if (this.overlay) {
+            if (this.panel) {
                 return;
             }
 
index 01d6668..39525db 100644 (file)
@@ -40,9 +40,17 @@ YUI.add('moodle-core-formautosubmit',
                 }
 
                 // Assign this select items 'nothing' value and lastindex (current value)
-                var thisselect = Y.one('select#' + this.get('selectid'));
-                thisselect.setData('nothing', this.get('nothing'));
-                thisselect.setData('startindex', thisselect.get('selectedIndex'));
+                if (this.get('selectid')) {
+                    var thisselect = Y.one('select#' + this.get('selectid'));
+                    if (thisselect) {
+                        if (this.get('nothing')) {
+                            thisselect.setData('nothing', this.get('nothing'));
+                        }
+                        thisselect.setData('startindex', thisselect.get('selectedIndex'));
+                    } else {
+                        Y.log("Warning: A single_select element was renderered, but the output is not displayed on the page.");
+                    }
+                }
             },
 
             /**
index 1847544..4526ba6 100644 (file)
@@ -345,7 +345,9 @@ if (isloggedin() and !isguestuser()) {
     echo $OUTPUT->box_end();
 } else {
     include("index_form.html");
-    if (!empty($CFG->loginpageautofocus)) {
+    if ($errormsg) {
+        $PAGE->requires->js_init_call('M.util.focus_login_error', null, true);
+    } else if (!empty($CFG->loginpageautofocus)) {
         //focus username or password
         $PAGE->requires->js_init_call('M.util.focus_login_form', null, true);
     }
index 1765064..f7557a5 100644 (file)
@@ -30,9 +30,10 @@ if (empty($CFG->xmlstrictheaders) and !empty($CFG->loginpasswordautocomplete)) {
         </div>
         <?php
           if (!empty($errormsg)) {
-              echo '<div class="loginerrors">';
+              echo html_writer::start_tag('div', array('class' => 'loginerrors'));
+              echo html_writer::link('#', $errormsg, array('id' => 'loginerrormessage', 'class' => 'accesshide'));
               echo $OUTPUT->error_text($errormsg);
-              echo '</div>';
+              echo html_writer::end_tag('div');
           }
         ?>
         <form action="<?php echo $CFG->httpswwwroot; ?>/login/index.php" method="post" id="login" <?php echo $autocomplete; ?> >
index 6510353..ea027e0 100644 (file)
@@ -141,7 +141,9 @@ class assign_feedback_comments extends assign_feedback_plugin {
             }
         }
 
-        $mform->addElement('editor', 'assignfeedbackcomments_editor', '', null, null);
+        $mform->addElement('editor', 'assignfeedbackcomments_editor', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, null);
+
         return true;
     }
 
index f019f8e..57c413b 100644 (file)
@@ -94,8 +94,8 @@ class assign_feedback_file extends assign_feedback_plugin {
                                                   'assignfeedback_file',
                                                   ASSIGNFEEDBACK_FILE_FILEAREA,
                                                   $gradeid);
-
-        $mform->addElement('filemanager', $elementname . '_filemanager', '', null, $fileoptions);
+        $mform->addElement('filemanager', $elementname . '_filemanager', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $fileoptions);
 
         return true;
     }
index 92490ec..bc0e118 100644 (file)
@@ -326,7 +326,7 @@ function assign_print_overview($courses, &$htmlarray) {
     // get all user submissions, indexed by assignment id
     $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS nosubmissions, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
                             FROM {assign} a LEFT JOIN {assign_grades} g ON g.assignment = a.id AND g.userid = ? LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = ?
-                            AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
+                            WHERE a.id $sqlassignmentids", array($USER->id, $USER->id));
 
     foreach ($assignments as $assignment) {
         // Do not show assignments that are not open
index 1d91186..addc361 100644 (file)
@@ -113,7 +113,12 @@ class assign_submission_comments extends assign_submission_plugin {
      * @return bool was it a success? (false will trigger a rollback)
      */
     public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) {
-        // first upgrade settings (nothing to do)
+        if ($oldassignment->assignmenttype == 'upload') {
+            // Disable if allow notes was not enabled.
+            if (!$oldassignment->var2) {
+                $this->disable();
+            }
+        }
         return true;
     }
 
index ed1e234..833b0a6 100644 (file)
@@ -150,9 +150,10 @@ class assign_submission_file extends assign_submission_plugin {
         $fileoptions = $this->get_file_options();
         $submissionid = $submission ? $submission->id : 0;
 
-
         $data = file_prepare_standard_filemanager($data, 'files', $fileoptions, $this->assignment->get_context(), 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submissionid);
-        $mform->addElement('filemanager', 'files_filemanager', '', null, $fileoptions);
+        $mform->addElement('filemanager', 'files_filemanager', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $fileoptions);
+
         return true;
     }
 
@@ -301,14 +302,31 @@ class assign_submission_file extends assign_submission_plugin {
      * @return bool Was it a success? (false will trigger rollback)
      */
     public function upgrade_settings(context $oldcontext,stdClass $oldassignment, & $log) {
+        global $DB;
+
         if ($oldassignment->assignmenttype == 'uploadsingle') {
             $this->set_config('maxfilesubmissions', 1);
             $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes);
             return true;
-        }else {
-
+        } else if ($oldassignment->assignmenttype == 'upload') {
             $this->set_config('maxfilesubmissions', $oldassignment->var1);
             $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes);
+
+            // Advanced file upload uses a different setting to do the same thing.
+            $DB->set_field('assign',
+                           'submissiondrafts',
+                           $oldassignment->var4,
+                           array('id'=>$this->assignment->get_instance()->id));
+
+            // Convert advanced file upload "hide description before due date" setting.
+            $alwaysshow = 0;
+            if (!$oldassignment->var3) {
+                $alwaysshow = 1;
+            }
+            $DB->set_field('assign',
+                           'alwaysshowdescription',
+                           $alwaysshow,
+                           array('id'=>$this->assignment->get_instance()->id));
             return true;
         }
 
index 7d5b624..f744bc2 100644 (file)
@@ -90,9 +90,10 @@ class assign_submission_onlinetext extends assign_submission_plugin {
 
         }
 
-
         $data = file_prepare_standard_editor($data, 'onlinetext', $editoroptions, $this->assignment->get_context(), 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submissionid);
-        $mform->addElement('editor', 'onlinetext_editor', '', null, $editoroptions);
+        $mform->addElement('editor', 'onlinetext_editor', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $editoroptions);
+
         return true;
     }
 
index f50aac0..89f15a2 100644 (file)
@@ -156,6 +156,20 @@ class assign_upgrade_manager {
                 $gradingdefinitions = $DB->get_records('grading_definitions', array('areaid'=>$gradingarea->id));
             }
 
+            // Upgrade availability data.
+            $DB->set_field('course_modules_availability',
+                           'coursemoduleid',
+                           $newcoursemodule->id,
+                           array('coursemoduleid'=>$oldcoursemodule->id));
+            $DB->set_field('course_modules_availability',
+                           'sourcecmid',
+                           $newcoursemodule->id,
+                           array('sourcecmid'=>$oldcoursemodule->id));
+            $DB->set_field('course_sections_availability',
+                           'sourcecmid',
+                           $newcoursemodule->id,
+                           array('sourcecmid'=>$oldcoursemodule->id));
+
             // upgrade completion data
             $DB->set_field('course_modules_completion', 'coursemoduleid', $newcoursemodule->id, array('coursemoduleid'=>$oldcoursemodule->id));
             $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance'=>$oldcoursemodule->id));
index b846573..8a89006 100644 (file)
@@ -54,7 +54,7 @@ function toolbook_importhtml_import_chapters($package, $type, $book, $context, $
     }
     if ($type == 0) {
         $chapterfile = reset($chapterfiles);
-        if ($file = $fs->get_file_by_hash("$context->id/mod_book/importhtmltemp/0/$chapterfile->pathname")) {
+        if ($file = $fs->get_file_by_hash(sha1("$context->id/mod_book/importhtmltemp/0/$chapterfile->pathname"))) {
             $htmlcontent = toolbook_importhtml_fix_encoding($file->get_content());
             $htmlchapters = toolbook_importhtml_parse_headings(toolbook_importhtml_parse_body($htmlcontent));
             // TODO: process h1 as main chapter and h2 as subchapters
index ea00ab2..903c9a1 100644 (file)
@@ -112,6 +112,7 @@ class restore_forum_activity_task extends restore_activity_task {
         $rules[] = new restore_log_rule('forum', 'delete discussion', 'view.php?id={course_module}', '{forum}');
         $rules[] = new restore_log_rule('forum', 'add post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}#p{forum_post}&parent={forum_post}', '{forum_post}');
+        $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'prune post', 'discuss.php?d={forum_discussion}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'delete post', 'discuss.php?d={forum_discussion}', '[post]');
 
index 106f0d9..79259e1 100644 (file)
@@ -710,6 +710,14 @@ function forum_cron() {
                 $eventdata->fullmessagehtml  = $posthtml;
                 $eventdata->notification = 1;
 
+                // If forum_replytouser is not set then send mail using the noreplyaddress.
+                if (empty($CFG->forum_replytouser)) {
+                    // Clone userfrom as it is referenced by $users.
+                    $cloneduserfrom = clone($userfrom);
+                    $cloneduserfrom->email = $CFG->noreplyaddress;
+                    $eventdata->userfrom = $cloneduserfrom;
+                }
+
                 $smallmessagestrings = new stdClass();
                 $smallmessagestrings->user = fullname($userfrom);
                 $smallmessagestrings->forumname = "$shortname: ".format_string($forum->name,true).": ".$discussion->name;
@@ -1011,10 +1019,9 @@ function forum_cron() {
                 }
 
                 $attachment = $attachname='';
-                $usetrueaddress = true;
                 // Directly email forum digests rather than sending them via messaging, use the
                 // site shortname as 'from name', the noreply address will be used by email_to_user.
-                $mailresult = email_to_user($userto, $site->shortname, $postsubject, $posttext, $posthtml, $attachment, $attachname, $usetrueaddress, $CFG->forum_replytouser);
+                $mailresult = email_to_user($userto, $site->shortname, $postsubject, $posttext, $posthtml, $attachment, $attachname);
 
                 if (!$mailresult) {
                     mtrace("ERROR!");
index 11d8e78..20f1a31 100644 (file)
@@ -2309,9 +2309,14 @@ abstract class lesson_page extends lesson_base {
         }
         if (count($this->answers)>0) {
             $count = 0;
+            $qtype = $properties->qtype;
             foreach ($this->answers as $answer) {
-                $properties->{'answer_editor['.$count.']'} = array('text'=>$answer->answer, 'format'=>$answer->answerformat);
-                $properties->{'response_editor['.$count.']'} = array('text'=>$answer->response, 'format'=>$answer->responseformat);
+                $properties->{'answer_editor['.$count.']'} = array('text' => $answer->answer, 'format' => $answer->answerformat);
+                if ($qtype != LESSON_PAGE_MATCHING) {
+                    $properties->{'response_editor['.$count.']'} = array('text' => $answer->response, 'format' => $answer->responseformat);
+                } else {
+                    $properties->{'response_editor['.$count.']'} = $answer->response;
+                }
                 $properties->{'jumpto['.$count.']'} = $answer->jumpto;
                 $properties->{'score['.$count.']'} = $answer->score;
                 $count++;
index 78323ec..9e9b42c 100644 (file)
@@ -213,6 +213,7 @@ class lesson_page_type_essay extends lesson_page {
             } else {
                 $essayinfo = new stdClass();
                 $essayinfo->answer = get_string("didnotanswerquestion", "lesson");
+                $essayinfo->answerformat = null;
             }
 
             if (isset($pagestats[$this->properties->id])) {
index be4be19..09cdf47 100644 (file)
@@ -72,16 +72,17 @@ class lesson_page_type_matching extends lesson_page {
         foreach ($answers as $answer) {
             // get all the response
             if ($answer->response != NULL) {
-                $responses[] = trim($answer->response);
+                $responses[$answer->id] = trim($answer->response);
             }
         }
 
         $responseoptions = array(''=>get_string('choosedots'));
         if (!empty($responses)) {
-            shuffle($responses);
-            $responses = array_unique($responses);
-            foreach ($responses as $response) {
-                $responseoptions[htmlspecialchars(trim($response))] = $response;
+            $shuffleresponses = $responses;
+            shuffle($shuffleresponses);
+            foreach ($shuffleresponses as  $response) {
+                $key = array_search($response, $responses);
+                $responseoptions[$key] = $response;
             }
         }
         if (isset($USER->modattempts[$this->lesson->id]) && !empty($attempt->useranswer)) {
@@ -115,9 +116,9 @@ class lesson_page_type_matching extends lesson_page {
                 $answer->answer = $properties->answer_editor[$i]['text'];
                 $answer->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $answer->response = $properties->response_editor[$i]['text'];
-                $answer->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $answer->response = $properties->response_editor[$i];
+                $answer->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -171,27 +172,26 @@ class lesson_page_type_matching extends lesson_page {
         $wrong   = array_shift($answers);
 
         foreach ($answers as $key=>$answer) {
-            if ($answer->answer === '' or $answer->response === '') {
-                // incomplete option!
-                unset($answers[$key]);
+            if ($answer->answer !== '' or $answer->response !== '') {
+                $answers[$answer->id] = $answer;
             }
+            unset($answers[$key]);
         }
         // get he users exact responses for record keeping
         $hits = 0;
         $userresponse = array();
-        foreach ($response as $key => $value) {
-            foreach($answers as $answer) {
-                if ($value === $answer->response) {
-                    $userresponse[] = $answer->id;
-                }
-                if ((int)$answer->id === (int)$key) {
-                    $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$value;
-                }
-                if ((int)$answer->id === (int)$key and $value === $answer->response) {
+        foreach ($response as $id => $value) {
+            $userresponse[] = $value;
+            // Make sure the user's answer is exist in question's answer
+            if (array_key_exists($id, $answers)) {
+                $answer = $answers[$id];
+                $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$answers[$value]->response;
+                if ($id == $value) {
                     $hits++;
                 }
             }
         }
+
         $result->userresponse = implode(",", $userresponse);
 
         if ($hits == count($answers)) {
@@ -315,9 +315,9 @@ class lesson_page_type_matching extends lesson_page {
                 $this->answers[$i]->answer = $properties->answer_editor[$i]['text'];
                 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $this->answers[$i]->response = $properties->response_editor[$i]['text'];
-                $this->answers[$i]->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $this->answers[$i]->response = $properties->response_editor[$i];
+                $this->answers[$i]->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -473,12 +473,18 @@ class lesson_add_page_form_matching extends lesson_add_page_form_base {
         for ($i = 2; $i < $this->_customdata['lesson']->maxanswers+2; $i++) {
             $this->_form->addElement('header', 'matchingpair'.($i-1), get_string('matchingpair', 'lesson', $i-1));
             $this->add_answer($i, NULL, ($i < 4));
-            $this->add_response($i, get_string('matchesanswer','lesson'), ($i < 4));
+            $required = ($i < 4);
+            $label = get_string('matchesanswer','lesson');
+            $count = $i;
+            $this->_form->addElement('text', 'response_editor['.$count.']', $label, array('size'=>'50'));
+            $this->_form->setDefault('response_editor['.$count.']', '');
+            if ($required) {
+                $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client');
+            }
         }
     }
 }
 
-
 class lesson_display_answer_form_matching extends moodleform {
 
     public function definition() {
index 8014bc1..d4a384b 100644 (file)
@@ -306,7 +306,11 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
         $data->timestart = $this->apply_date_offset($data->timestart);
         $data->timefinish = $this->apply_date_offset($data->timefinish);
         $data->timemodified = $this->apply_date_offset($data->timemodified);
-        $data->timecheckstate = $this->apply_date_offset($data->timecheckstate);
+        if (!empty($data->timecheckstate)) {
+            $data->timecheckstate = $this->apply_date_offset($data->timecheckstate);
+        } else {
+            $data->timecheckstate = 0;
+        }
 
         // Deals with up-grading pre-2.3 back-ups to 2.3+.
         if (!isset($data->state)) {
index c8776de..175e5c6 100644 (file)
@@ -100,7 +100,8 @@ class mod_quiz_overdue_attempt_updater {
 
 
         // SQL to compute timeclose and timelimit for each attempt:
-        $quizausersql = quiz_get_attempt_usertime_sql();
+        $quizausersql = quiz_get_attempt_usertime_sql(
+                "iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
 
         // This query should have all the quiz_attempts columns.
         return $DB->get_recordset_sql("
@@ -116,6 +117,6 @@ class mod_quiz_overdue_attempt_updater {
             AND quiza.timecheckstate <= :processto
        ORDER BY quiz.course, quiza.quiz",
 
-                array('processto' => $processto));
+                array('processto' => $processto, 'iprocessto' => $processto));
     }
 }
index ae23dd8..ca78f67 100644 (file)
@@ -783,34 +783,48 @@ function quiz_update_open_attempts(array $conditions) {
     }
 
     $params = array();
-    $coursecond = '';
-    $usercond = '';
-    $quizcond = '';
-    $groupcond = '';
+    $wheres = array("quiza.state IN ('inprogress', 'overdue')");
+    $iwheres = array("iquiza.state IN ('inprogress', 'overdue')");
 
     if (isset($conditions['courseid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'cid');
         $params = array_merge($params, $inparams);
-        $coursecond = "AND quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'icid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
     }
+
     if (isset($conditions['userid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'uid');
         $params = array_merge($params, $inparams);
-        $usercond = "AND quiza.userid $incond";
+        $wheres[] = "quiza.userid $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'iuid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.userid $incond";
     }
+
     if (isset($conditions['quizid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'qid');
         $params = array_merge($params, $inparams);
-        $quizcond = "AND quiza.quiz $incond";
+        $wheres[] = "quiza.quiz $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'iqid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz $incond";
     }
+
     if (isset($conditions['groupid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'gid');
         $params = array_merge($params, $inparams);
-        $groupcond = "AND quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'igid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
     }
 
     // SQL to compute timeclose and timelimit for each attempt:
-    $quizausersql = quiz_get_attempt_usertime_sql();
+    $quizausersql = quiz_get_attempt_usertime_sql(
+            implode("\n                AND ", $iwheres));
 
     // SQL to compute the new timecheckstate
     $timecheckstatesql = "
@@ -822,11 +836,7 @@ function quiz_update_open_attempts(array $conditions) {
           CASE WHEN quiza.state = 'overdue' THEN quiz.graceperiod ELSE 0 END";
 
     // SQL to select which attempts to process
-    $attemptselect = " quiza.state IN ('inprogress', 'overdue')
-                       $coursecond
-                       $usercond
-                       $quizcond
-                       $groupcond";
+    $attemptselect = implode("\n                         AND ", $wheres);
 
    /*
     * Each database handles updates with inner joins differently:
@@ -876,9 +886,14 @@ function quiz_update_open_attempts(array $conditions) {
 /**
  * Returns SQL to compute timeclose and timelimit for every attempt, taking into account user and group overrides.
  *
- * @return string         SQL select with columns attempt.id, usertimeclose, usertimelimit
+ * @param string $redundantwhereclauses extra where clauses to add to the subquery
+ *      for performance. These can use the table alias iquiza for the quiz attempts table.
+ * @return string SQL select with columns attempt.id, usertimeclose, usertimelimit.
  */
-function quiz_get_attempt_usertime_sql() {
+function quiz_get_attempt_usertime_sql($redundantwhereclauses = '') {
+    if ($redundantwhereclauses) {
+        $redundantwhereclauses = 'WHERE ' . $redundantwhereclauses;
+    }
     // The multiple qgo JOINS are necessary because we want timeclose/timelimit = 0 (unlimited) to supercede
     // any other group override
     $quizausersql = "
@@ -894,6 +909,7 @@ function quiz_get_attempt_usertime_sql() {
       LEFT JOIN {quiz_overrides} qgo2 ON qgo2.quiz = iquiza.quiz AND qgo2.groupid = gm.groupid AND qgo2.timeclose > 0
       LEFT JOIN {quiz_overrides} qgo3 ON qgo3.quiz = iquiza.quiz AND qgo3.groupid = gm.groupid AND qgo3.timelimit = 0
       LEFT JOIN {quiz_overrides} qgo4 ON qgo4.quiz = iquiza.quiz AND qgo4.groupid = gm.groupid AND qgo4.timelimit > 0
+          $redundantwhereclauses
        GROUP BY iquiza.id, iquiz.id, iquiz.timeclose, iquiz.timelimit";
     return $quizausersql;
 }
index c2f1c40..182de24 100644 (file)
@@ -745,7 +745,7 @@ function scorm_course_format_display($user, $course) {
 }
 
 function scorm_view_display ($user, $scorm, $action, $cm) {
-    global $CFG, $DB, $PAGE, $OUTPUT;
+    global $CFG, $DB, $PAGE, $OUTPUT, $COURSE;
 
     if ($scorm->scormtype != SCORM_TYPE_LOCAL && $scorm->updatefreq == SCORM_UPDATE_EVERYTIME) {
         scorm_parse($scorm, false);
@@ -824,7 +824,7 @@ function scorm_view_display ($user, $scorm, $action, $cm) {
                       <label for="a"><?php print_string('newattempt', 'scorm') ?></label>
             <?php
         }
-        if (!empty($scorm->popup)) {
+        if ($COURSE->format != 'scorm' && !empty($scorm->popup)) {
             echo '<input type="hidden" name="display" value="popup" />'."\n";
         }
         ?>
index d332563..a3736e7 100644 (file)
@@ -197,6 +197,7 @@ $string['saving'] = 'Saving wiki page';
 $string['savingerror'] = 'Saving error';
 $string['searchcontent'] = 'Search in page content';
 $string['searchresult'] = 'Search results:';
+$string['searchterms'] = 'Search terms';
 $string['searchwikis'] = 'Search wikis';
 $string['special'] = 'Special';
 $string['tableofcontents'] = 'Table of contents';
index 974c46d..f42f3a6 100644 (file)
@@ -474,7 +474,8 @@ function wiki_search_form($cm, $search = '') {
     $output = '<div class="wikisearch">';
     $output .= '<form method="post" action="' . $CFG->wwwroot . '/mod/wiki/search.php" style="display:inline">';
     $output .= '<fieldset class="invisiblefieldset">';
-    $output .= '<label class="accesshide" for="searchwiki">' . get_string("searchwikis", "wiki") . '</label>';
+    $output .= '<legend class="accesshide">'. get_string('searchwikis', 'wiki') .'</legend>';
+    $output .= '<label class="accesshide" for="searchwiki">' . get_string("searchterms", "wiki") . '</label>';
     $output .= '<input id="searchwiki" name="searchstring" type="text" size="18" value="' . s($search, true) . '" alt="search" />';
     $output .= '<input name="courseid" type="hidden" value="' . $cm->course . '" />';
     $output .= '<input name="cmid" type="hidden" value="' . $cm->id . '" />';
index 811e9bc..6125015 100644 (file)
@@ -348,18 +348,19 @@ class qformat_default {
         foreach ($questions as $question) {
             if (!empty($question->fraction) and (is_array($question->fraction))) {
                 $fractions = $question->fraction;
-                $answersvalid = true; // in case they are!
+                $invalidfractions = array();
                 foreach ($fractions as $key => $fraction) {
                     $newfraction = match_grade_options($gradeoptionsfull, $fraction,
                             $this->matchgrades);
                     if ($newfraction === false) {
-                        $answersvalid = false;
+                        $invalidfractions[] = $fraction;
                     } else {
                         $fractions[$key] = $newfraction;
                     }
                 }
-                if (!$answersvalid) {
-                    echo $OUTPUT->notification(get_string('invalidgrade', 'question'));
+                if ($invalidfractions) {
+                    echo $OUTPUT->notification(get_string('invalidgrade', 'question',
+                            implode(', ', $invalidfractions)));
                     ++$gradeerrors;
                     continue;
                 } else {
index 64f0dbf..f1472af 100644 (file)
@@ -149,6 +149,40 @@ class qformat_xml extends qformat_default {
         return $xml;
     }
 
+    public function import_text_with_files($data, $path, $defaultvalue = '', $defaultformat = 'html') {
+        $field  = array();
+        $field['text'] = $this->getpath($data,
+                array_merge($path, array('#', 'text', 0, '#')), $defaultvalue, true);
+        $field['format'] = $this->trans_format($this->getpath($data,
+                array_merge($path, array('@', 'format')), $defaultformat));
+        $itemid = $this->import_files_as_draft($this->getpath($data,
+                array_merge($path, array('#', 'file')), array(), false));
+        if (!empty($itemid)) {
+            $field['itemid'] = $itemid;
+        }
+        return $field;
+    }
+
+    public function import_files_as_draft($xml) {
+        global $USER;
+        if (empty($xml)) {
+            return null;
+        }
+        $fs = get_file_storage();
+        $itemid = file_get_unused_draft_itemid();
+        foreach ($xml as $file) {
+            $filerecord = array(
+                'contextid' => context_user::instance($USER->id)->id,
+                'component' => 'user',
+                'filearea'  => 'draft',
+                'itemid'    => $itemid,
+                'filepath'  => '/',
+                'filename'  => $file['@']['name'],
+            );
+            $fs->create_file_from_string($filerecord, base64_decode($file['#']));
+        }
+        return $itemid;
+    }
 
     /**
      * import parts of question common to all types
@@ -156,7 +190,7 @@ class qformat_xml extends qformat_default {
      * @return object question object
      */
     public function import_headers($question) {
-        global $CFG;
+        global $CFG, $USER;
 
         // get some error strings
         $error_noname = get_string('xmlimportnoname', 'qformat_xml');
@@ -169,35 +203,42 @@ class qformat_xml extends qformat_default {
         $qo->name = $this->clean_question_name($this->getpath($question,
                 array('#', 'name', 0, '#', 'text', 0, '#'), '', true,
                 get_string('xmlimportnoname', 'qformat_xml')));
-        $qo->questiontext = $this->getpath($question,
-                array('#', 'questiontext', 0, '#', 'text', 0, '#'), '', true);
-        $qo->questiontextformat = $this->trans_format($this->getpath(
-                $question, array('#', 'questiontext', 0, '@', 'format'), 'html'));
-
-        $qo->questiontextfiles = $this->import_files($this->getpath($question,
-                array('#', 'questiontext', 0, '#', 'file'), array(), false));
-
+        $questiontext = $this->import_text_with_files($question,
+                array('#', 'questiontext', 0));
+        $qo->questiontext = $questiontext['text'];
+        $qo->questiontextformat = $questiontext['format'];
+        if (!empty($questiontext['itemid'])) {
+            $qo->questiontextitemid = $questiontext['itemid'];
+        }
         // Backwards compatibility, deal with the old image tag.
         $filedata = $this->getpath($question, array('#', 'image_base64', '0', '#'), null, false);
         $filename = $this->getpath($question, array('#', 'image', '0', '#'), null, false);
         if ($filedata && $filename) {
-            $data = new stdClass();
-            $data->content = $filedata;
-            $data->encoding = 'base64';
-            // Question file areas don't support subdirs, so convert path to filename if necessary.
-            $data->name = clean_param(str_replace('/', '_', $filename), PARAM_FILE);
-            $qo->questiontextfiles[] = $data;
-            $qo->questiontext .= ' <img src="@@PLUGINFILE@@/' . $data->name . '" />';
+            $fs = get_file_storage();
+            if (empty($qo->questiontextitemid)) {
+                $qo->questiontextitemid = file_get_unused_draft_itemid();
+            }
+            $filename = clean_param(str_replace('/', '_', $filename), PARAM_FILE);
+            $filerecord = array(
+                'contextid' => context_user::instance($USER->id)->id,
+                'component' => 'user',
+                'filearea'  => 'draft',
+                'itemid'    => $qo->questiontextitemid,
+                'filepath'  => '/',
+                'filename'  => $filename,
+            );
+            $fs->create_file_from_string($filerecord, base64_decode($filedata));
+            $qo->questiontext .= ' <img src="@@PLUGINFILE@@/' . $filename . '" />';
         }
 
         // restore files in generalfeedback
-        $qo->generalfeedback = $this->getpath($question,
-                array('#', 'generalfeedback', 0, '#', 'text', 0, '#'), $qo->generalfeedback, true);
-        $qo->generalfeedbackfiles = array();
-        $qo->generalfeedbackformat = $this->trans_format($this->getpath($question,
-                array('#', 'generalfeedback', 0, '@', 'format'), $this->get_format($qo->questiontextformat)));
-        $qo->generalfeedbackfiles = $this->import_files($this->getpath($question,
-                array('#', 'generalfeedback', 0, '#', 'file'), array(), false));
+        $generalfeedback = $this->import_text_with_files($question,
+                array('#', 'generalfeedback', 0), $qo->generalfeedback, $this->get_format($qo->questiontextformat));
+        $qo->generalfeedback = $generalfeedback['text'];
+        $qo->generalfeedbackformat = $generalfeedback['format'];
+        if (!empty($generalfeedback['itemid'])) {
+            $qo->generalfeedbackitemid = $generalfeedback['itemid'];
+        }
 
         $qo->defaultmark = $this->getpath($question,
                 array('#', 'defaultgrade', 0, '#'), $qo->defaultmark);
@@ -234,24 +275,15 @@ class qformat_xml extends qformat_default {
     public function import_answer($answer, $withanswerfiles = false, $defaultformat = 'html') {
         $ans = new stdClass();
 
-        $ans->answer = array();
-        $ans->answer['text']   = $this->getpath($answer, array('#', 'text', 0, '#'), '', true);
-        $ans->answer['format'] = $this->trans_format($this->getpath($answer,
-                array('@', 'format'), $defaultformat));
         if ($withanswerfiles) {
-            $ans->answer['files']  = $this->import_files($this->getpath($answer,
-                    array('#', 'file'), array()));
+            $ans->answer = $this->import_text_with_files($answer, array(), '', $defaultformat);
         } else {
+            $ans->answer = array();
+            $ans->answer['text']   = $this->getpath($answer, array('#', 'text', 0, '#'), '', true);
             $ans->answer['format'] = FORMAT_PLAIN;
         }
 
-        $ans->feedback = array();
-        $ans->feedback['text']   = $this->getpath($answer,
-                array('#', 'feedback', 0, '#', 'text', 0, '#'), '', true);
-        $ans->feedback['format'] = $this->trans_format($this->getpath($answer,
-                array('#', 'feedback', 0, '@', 'format'), $defaultformat));
-        $ans->feedback['files']  = $this->import_files($this->getpath($answer,
-                array('#', 'feedback', 0, '#', 'file'), array()));
+        $ans->feedback = $this->import_text_with_files($answer, array('#', 'feedback', 0), '', $defaultformat);
 
         $ans->fraction = $this->getpath($answer, array('@', 'fraction'), 0) / 100;
 
@@ -267,15 +299,8 @@ class qformat_xml extends qformat_default {
     public function import_combined_feedback($qo, $questionxml, $withshownumpartscorrect = false) {
         $fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
         foreach ($fields as $field) {
-            $text = array();
-            $text['text'] = $this->getpath($questionxml,
-                    array('#', $field, 0, '#', 'text', 0, '#'), '', true);
-            $text['format'] = $this->trans_format($this->getpath($questionxml,
-                    array('#', $field, 0, '@', 'format'), $this->get_format($qo->questiontextformat)));
-            $text['files'] = $this->import_files($this->getpath($questionxml,
-                    array('#', $field, 0, '#', 'file'), array(), false));
-
-            $qo->$field = $text;
+            $qo->$field = $this->import_text_with_files($questionxml,
+                    array('#', $field, 0), '', $this->get_format($qo->questiontextformat));
         }
 
         if ($withshownumpartscorrect) {
@@ -296,15 +321,13 @@ class qformat_xml extends qformat_default {
      * @return object hint for storing in the database.
      */
     public function import_hint($hintxml, $defaultformat) {
+        $hint = new stdClass();
         if (array_key_exists('hintcontent', $hintxml['#'])) {
             // Backwards compatibility:
 
-            $hint = new stdClass();
-            $hint->hint = array('format' => FORMAT_HTML, 'files' => array());
-            $hint->hint['text'] = $this->getpath($hintxml,
-                    array('#', 'hintcontent', 0, '#', 'text', 0, '#'), '', true);
-            $hint->hint['format'] = $this->trans_format($defaultformat);
-            $hint->hint['files'] = array();
+            $hint->hint = $this->import_text_with_files($hintxml,
+                    array('#', 'hintcontent', 0), '', $defaultformat);
+
             $hint->shownumcorrect = $this->getpath($hintxml,
                     array('#', 'statenumberofcorrectresponses', 0, '#'), 0);
             $hint->clearwrong = $this->getpath($hintxml,
@@ -314,14 +337,7 @@ class qformat_xml extends qformat_default {
 
             return $hint;
         }
-
-        $hint = new stdClass();
-        $hint->hint['text'] = $this->getpath($hintxml,
-                array('#', 'text', 0, '#'), '', true);
-        $hint->hint['format'] = $this->trans_format($this->getpath($hintxml,
-                array('@', 'format'), $defaultformat));
-        $hint->hint['files'] = $this->import_files($this->getpath($hintxml,
-                array('#', 'file'), array(), false));
+        $hint->hint = $this->import_text_with_files($hintxml, array(), '', $defaultformat);
         $hint->shownumcorrect = array_key_exists('shownumcorrect', $hintxml['#']);
         $hint->clearwrong = array_key_exists('clearwrong', $hintxml['#']);
         $hint->options = $this->getpath($hintxml, array('#', 'options', 0, '#'), '', true);
@@ -440,9 +456,11 @@ class qformat_xml extends qformat_default {
         $qo->name = $this->clean_question_name($this->import_text($question['#']['name'][0]['#']['text']));
         $qo->questiontextformat = $questiontext['format'];
         $qo->questiontext = $qo->questiontext['text'];
-        $qo->questiontextfiles = $this->import_files($this->getpath($question,
+        $itemid = $this->import_files($this->getpath($question,
                 array('#', 'questiontext', 0, '#', 'file'), array(), false));
-
+        if (!empty($itemid)) {
+            $qo->questiontextitemid = $itemid;
+        }
         // Backwards compatibility, deal with the old image tag.
         $filedata = $this->getpath($question, array('#', 'image_base64', '0', '#'), null, false);
         $filename = $this->getpath($question, array('#', 'image', '0', '#'), null, false);
@@ -457,12 +475,13 @@ class qformat_xml extends qformat_default {
         }
 
         // restore files in generalfeedback
-        $qo->generalfeedback = $this->getpath($question,
-                array('#', 'generalfeedback', 0, '#', 'text', 0, '#'), $qo->generalfeedback, true);
-        $qo->generalfeedbackformat = $this->trans_format($this->getpath($question,
-                array('#', 'generalfeedback', 0, '@', 'format'), $this->get_format($qo->questiontextformat)));
-        $qo->generalfeedbackfiles = $this->import_files($this->getpath($question,
-                array('#', 'generalfeedback', 0, '#', 'file'), array(), false));
+        $generalfeedback = $this->import_text_with_files($question,
+                array('#', 'generalfeedback', 0), $qo->generalfeedback, $this->get_format($qo->questiontextformat));
+        $qo->generalfeedback = $generalfeedback['text'];
+        $qo->generalfeedbackformat = $generalfeedback['format'];
+        if (!empty($generalfeedback['itemid'])) {
+            $qo->generalfeedbackitemid = $generalfeedback['itemid'];
+        }
 
         $qo->penalty = $this->getpath($question,
                 array('#', 'penalty', 0, '#'), $this->defaultquestion()->penalty);
@@ -498,20 +517,9 @@ class qformat_xml extends qformat_default {
         foreach ($question['#']['answer'] as $answer) {
             $answertext = $this->getpath($answer,
                     array('#', 'text', 0, '#'), '', true);
-            $feedback = $this->getpath($answer,
-                    array('#', 'feedback', 0, '#', 'text', 0, '#'), '', true);
-            $feedbackformat = $this->getpath($answer,
-                    array('#', 'feedback', 0, '@', 'format'), $this->get_format($qo->questiontextformat));
-            $feedbackfiles = $this->getpath($answer,
-                    array('#', 'feedback', 0, '#', 'file'), array());
-            $files = array();
-            foreach ($feedbackfiles as $file) {
-                $data = new stdClass();
-                $data->content = $file['#'];
-                $data->encoding = $file['@']['encoding'];
-                $data->name = $file['@']['name'];
-                $files[] = $data;
-            }
+            $feedback = $this->import_text_with_files($answer,
+                    array('#', 'feedback', 0), '', $this->get_format($qo->questiontextformat));
+
             if ($answertext != 'true' && $answertext != 'false') {
                 // Old style file, assume order is true/false.
                 $warning = true;
@@ -525,17 +533,11 @@ class qformat_xml extends qformat_default {
             if ($answertext == 'true') {
                 $qo->answer = ($answer['@']['fraction'] == 100);
                 $qo->correctanswer = $qo->answer;
-                $qo->feedbacktrue = array();
-                $qo->feedbacktrue['text'] = $feedback;
-                $qo->feedbacktrue['format'] = $this->trans_format($feedbackformat);
-                $qo->feedbacktrue['files'] = $files;
+                $qo->feedbacktrue = $feedback;
             } else {
                 $qo->answer = ($answer['@']['fraction'] != 100);
                 $qo->correctanswer = $qo->answer;
-                $qo->feedbackfalse = array();
-                $qo->feedbackfalse['text'] = $feedback;
-                $qo->feedbackfalse['format'] = $this->trans_format($feedbackformat);
-                $qo->feedbackfalse['files'] = $files;
+                $qo->feedbackfalse = $feedback;
             }
             $first = false;
         }
@@ -650,13 +652,8 @@ class qformat_xml extends qformat_default {
         $qo->instructions['format'] = FORMAT_HTML;
         $instructions = $this->getpath($question, array('#', 'instructions'), array());
         if (!empty($instructions)) {
-            $qo->instructions = array();
-            $qo->instructions['text'] = $this->getpath($instructions,
-                    array('0', '#', 'text', '0', '#'), '', true);
-            $qo->instructions['format'] = $this->trans_format($this->getpath($instructions,
-                    array('0', '@', 'format'), $this->get_format($qo->questiontextformat)));
-            $qo->instructions['files'] = $this->import_files($this->getpath(
-                    $instructions, array('0', '#', 'file'), array()));
+            $qo->instructions = $this->import_text_with_files($instructions,
+                    array('0'), '', $this->get_format($qo->questiontextformat));
         }
 
         if (is_null($qo->showunits)) {
@@ -691,14 +688,9 @@ class qformat_xml extends qformat_default {
         $qo->subquestions = array();
         $qo->subanswers = array();
         foreach ($question['#']['subquestion'] as $subqxml) {
-            $subquestion = array();
-            $subquestion['text'] = $this->getpath($subqxml, array('#', 'text', 0, '#'), '', true);
-            $subquestion['format'] = $this->trans_format($this->getpath($subqxml,
-                    array('@', 'format'), $this->get_format($qo->questiontextformat)));
-            $subquestion['files'] = $this->import_files($this->getpath($subqxml,
-                    array('#', 'file'), array()));
-
-            $qo->subquestions[] = $subquestion;
+            $qo->subquestions[] = $this->import_text_with_files($subqxml,
+                    array(), '', $this->get_format($qo->questiontextformat));
+
             $answers = $this->getpath($subqxml, array('#', 'answer'), array());
             $qo->subanswers[] = $this->getpath($subqxml,
                     array('#', 'answer', 0, '#', 'text', 0, '#'), '', true);
@@ -728,12 +720,8 @@ class qformat_xml extends qformat_default {
                 array('#', 'responsefieldlines', 0, '#'), 15);
         $qo->attachments = $this->getpath($question,
                 array('#', 'attachments', 0, '#'), 0);
-        $qo->graderinfo['text'] = $this->getpath($question,
-                array('#', 'graderinfo', 0, '#', 'text', 0, '#'), '', true);
-        $qo->graderinfo['format'] = $this->trans_format($this->getpath($question,
-                array('#', 'graderinfo', 0, '@', 'format'), $this->get_format($qo->questiontextformat)));
-        $qo->graderinfo['files'] = $this->import_files($this->getpath($question,
-                array('#', 'graderinfo', '0', '#', 'file'), array()));
+        $qo->graderinfo = $this->import_text_with_files($question,
+                array('#', 'graderinfo', 0), '', $this->get_format($qo->questiontextformat));
 
         return $qo;
     }
@@ -767,13 +755,8 @@ class qformat_xml extends qformat_default {
         $qo->instructions = $this->getpath($question,
                 array('#', 'instructions', 0, '#', 'text', 0, '#'), '', true);
         if (!empty($instructions)) {
-            $qo->instructions = array();
-            $qo->instructions['text'] = $this->getpath($instructions,
-                    array('0', '#', 'text', '0', '#'), '', true);
-            $qo->instructions['format'] = $this->trans_format($this->getpath($instructions,
-                    array('0', '@', 'format'), $this->get_format($qo->questiontextformat)));
-            $qo->instructions['files'] = $this->import_files($this->getpath($instructions,
-                    array('0', '#', 'file'), array()));
+            $qo->instructions = $this->import_text_with_files($instructions,
+                    array('0'), '', $this->get_format($qo->questiontextformat));
         }
 
         // get answers array
@@ -817,13 +800,8 @@ class qformat_xml extends qformat_default {
         }
         $instructions = $this->getpath($question, array('#', 'instructions'), array());
         if (!empty($instructions)) {
-            $qo->instructions = array();
-            $qo->instructions['text'] = $this->getpath($instructions,
-                    array('0', '#', 'text', '0', '#'), '', true);
-            $qo->instructions['format'] = $this->trans_format($this->getpath($instructions,
-                    array('0', '@', 'format'), $this->get_format($qo->questiontextformat)));
-            $qo->instructions['files'] = $this->import_files($this->getpath($instructions,
-                    array('0', '#', 'file'), array()));
+            $qo->instructions = $this->import_text_with_files($instructions,
+                    array('0'), '', $this->get_format($qo->questiontextformat));
         }
 
         if (is_null($qo->unitpenalty)) {
diff --git a/question/format/xml/tests/fixtures/multichoice.xml b/question/format/xml/tests/fixtures/multichoice.xml
new file mode 100644 (file)
index 0000000..dbf5845
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<quiz>
+<!-- question: 0  -->
+  <question type="category">
+    <category>
+        <text>$course$/Default for testhead/Multichoice</text>
+
+    </category>
+  </question>
+
+<!-- question: 2295  -->
+  <question type="multichoice">
+    <name>
+      <text>Greeting</text>
+    </name>
+    <questiontext format="html">
+      <text><![CDATA[<p><a href="@@PLUGINFILE@@/bonjour.mp3">Listen to this greeting:</a><br /><br />What language is being spoken?</p>]]></text>
+<file name="bonjour.mp3" encoding="base64">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Fl7pz/jb6rABwGCAGDAGhSDiEYjCYFBTQjFYJHgumNR////////////+v69////////////7sToIDJhMBjQYMHDsFBgwCBDdpEfY20TiErmN0iYRIBteqiV1NLe81CJTXUoNyiIw8VAeLDFhQMML41sHTEYbBrIMVlcw8LjTAuaCxIzGXVfEoFMhG54CAIqFNyV/Xd56yYPTCzG6qYU61nheF5IKUtZ02WWOUqtKpuii81BRfNnAXD7ZoKY7khaoKOBNTRmrv05UBikgYAyIeNbxfsGhNUZAOB4XP4XDSeoX0MDAorApAOiIjOiWkfdiEMhcKNKEYuMJACDkt4qCQOBgwCAMZeCACCCOtosA4LgQlAAkDa6E0RCcvABA//LCwD145VuTxnQBnOAA8LFlX6lU8yoAghQIIF76FthgPtIBwAM3j9nrOc24l1nCFQE/YsAe/70ts5RICy7o6Dy4QiDIICRgYNhUXJfCME3/+Z3MgwAMVCoFBAQS4MTCMVFAYLyYYmFwDz//8Eqh0DLtlsoQ5AENltwENQMAiIA2f////////////JgBz////////////4dTEFNRTMuOTWqqqgAAHHsAAYVAUYBiiAh5BIHiRECotGiaPGD4vG5w/mDgamtpLmAwNmW/8GUxUGu6Dm2AuGVmHhAGGFaID4dmEYqmH4dnMYKBB1mAZgmvIQmFIyGWJxioCgAETJwvAUCq0jGkdS5AhAIHDSDAUMXgfRVCA1CojGKIKjgDFrhACQKIpTERhHOCEF0uSwAyARziqBcgWkUBk9xADLEyEBV9LRVqHgLL7GNwCr3HgJlooCpeEwDEgwaAWyztsinClBgaHimRZgBA2wwEBQNBgDgCMNgbkhfxsBbBp7WjBYGhAD6xnmBQBGAoE5MiMGgVbGFwNhquhiWpAAYqAigHmWQ9GP/ywsBMeP9qc8pgcZ3oAAgHBQANCAGCsACyw4DKlg8CQWDUKBGYShMYLE+YKBChjGB0DgICBEJJgWBTzRkIA0CAuBRKMUQCMNwssy53kIgEB6OMzFMv//8LARFy7wJBIgA4wjAYHCwWhMHAjKAixwwsdjhKBCA0FAyWAJKoFBcEDAsLDCMCh4LwwGtz0v68MDI7OwkkzVDqPAKNAIVAMLvMedTn////////////3+f////////////OcgAJmQABIvDDVFwE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T3y3///MCg7MVhnFiUMOhpMSAXMDAjMHg5yjL//ywsCcOINahC4EAZ3oABSqerSr////zAgDDC8RjBIQzFoWzGAiQCBhhSIRiiOxiAQte5yVQTMw7Eq3/////5jsGYyAxgABBjyXhmCQxhmERh0QJkMKZiUOJKTxluBRk2jxpKZFNTTU+wF0YQ1qozpGVpMC////////+YJjuAhCMTBlMKAyMIAdAIJBUGzCsPBEJpiwA5igRJi8DKPRgEAZgGDgcFUMujIHafaRv7KYq0p9pFqt3H//////////1Amxoqx1iLGoquZlbDnxdxyXqfNrUTkDSYTax5//rXcd81/7/9f///////////////1r8pyps0xBTUUzLjk1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/8sLAaDysAAADSAGAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTEFNRTMuOTVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//LCwByZ/wAAA0gBgAAAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUxBTUUzLjk1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==</file>    </questiontext>
+    <generalfeedback format="html">
+      <text></text>
+    </generalfeedback>
+    <defaultgrade>1.0000000</defaultgrade>
+    <penalty>0.1000000</penalty>
+    <hidden>0</hidden>
+    <single>true</single>
+    <shuffleanswers>true</shuffleanswers>
+    <answernumbering>abc</answernumbering>
+    <correctfeedback format="html">
+      <text></text>
+    </correctfeedback>
+    <partiallycorrectfeedback format="html">
+      <text></text>
+    </partiallycorrectfeedback>
+    <incorrectfeedback format="html">
+      <text></text>
+    </incorrectfeedback>
+    <answer fraction="0" format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/flag-uk.jpg" alt="British Flag" width="30" height="20" /> English</p>]]></text>
+<file name="flag-uk.jpg" encoding="base64">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</file>      <feedback format="html">
+        <text><![CDATA[<p>Sorry, listen again.</p>]]></text>
+      </feedback>
+    </answer>
+    <answer fraction="100" format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/flag-france.jpg" alt="French flag" width="30" height="20" /> French</p>]]></text>
+<file name="flag-france.jpg" encoding="base64">/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAFAAeAwERAAIRAQMRAf/EALYAAAMBAQAAAAAAAAAAAAAAAAgJCgcLAQADAQEAAAAAAAAAAAAAAAAHCAkFChAAAAEHCQEIEwEAAAAAAAAAAgEREgMTBAUAFBUGFgcXCAkYMUFhMkIjdSchUYEisjOktDZmN0dnxzhIiLgKOREAAAEIAwUQEAcAAAAAAAAAAQARAhIDEwQFFAYHQaEzFRYhMVFxscHRIkKCI3M0hDUXgZFyorLCQ4OTo7O0RYU3CbXFJjZHCBj/2gAMAwEAAhEDEQA/ABDzlatOaG7e+OM1XgMTdiOEPeX53ViG9vQBjCoeWYCiCAKJCkCSVB6p2YVcmEpQiWyIrpAFwNAl3m9aZlDxYskB2oCJWtaIl9Vb8w+mBljvir4tAvrXXDGilVoBjWBFZ/MJexVdxMNZ35UYbBFJOzvkkolsMohZFaNMZVBAaGZUdXfQrFMb6QkYamxjWPq3DRbfCpvD9hqmiF4CFzXNzN3i5ctl2wDwrUWxxspZNasVpWewjmBmZCnRpxdu9uQTnsU0hnTvdLXldkq1fbbsdqpazlnlOiKWL8UOjAA4fGa+fxKBTaPWo1mPer0YbGx1lWhUw2DrmMJA9LyOKxY8O706DXricYa0gV5SkLuEMThlioRjdJmnECO2RADBpiAFQ6sFg1nUqrTIbNoOCZhATSKiEm7YUQFqkDGCiG6CAXAQBNkiIhdHNEcwABJ+oX9RFaekIp56WViKi9BM+5DULkCn/SCWmJdED+cv/GjJz+Qn7UX4SRG3v6szbmvucOR6s/8A2jCed9s0IL/6S/sx/Ir5FSXesvkd/wCKVzftFfyD8i/OSlJL6ZE6JJ4YpYbLkbXSDwgKjlcvrjVDjY38MjSW5mgs5jxeZaS3dLWqik58cY84FxJ5zrE/E5KJjSpel1mUdjQ1aG7BR2ZU2ofRLjODJh4m+O+WFZbPPsFUzpW7cOwXcRgHijhN1n2UmzBh7Zbw6dQP6yzw/CeSm2k41y1jcdnxnwK58/AMle8VIuVZomI2FB5Lt1fSJnvnLA9WDa06hNoHE73pWSnM3+HNPIeRH7khdNqNwdINujXj6xUV/o/1tfqfqtX+HUpXn7k/rSTu6T6dRZpb6l6Odpu0ZtGU+d02CPNpM0jpck5t6WajQXSRjKZh+2GuTeTj/R2WkppzzKR42oxzn5K2eGuYJ4e6X//Z</file>      <feedback format="html">
+        <text><![CDATA[<p>Yes, well done!</p>]]></text>
+      </feedback>
+    </answer>
+    <answer fraction="0" format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/flag-german.jpg" alt="German flag" width="30" height="20" /> German</p>]]></text>
+<file name="flag-german.jpg" encoding="base64">/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAFAAeAwERAAIRAQMRAf/EAKYAAQACAwAAAAAAAAAAAAAAAAcACQEICgEAAQMFAQAAAAAAAAAAAAAAAAUGCQECAwQHCBAAAAMFBQMICwAAAAAAAAAAAQIFEQMEBggAMRIUByETFWEyldUWF1cYQVFxgZGhsSIjNSgRAAACBQYGDQ0AAAAAAAAAAAEEABECAwUhMRITBgdhk9MVFghBkaEiMtIjoxTUVVYXUYHBUmKiwnM1lSYnGP/aAAwDAQACEQMRAD8ApA1tqzq/RdQlxOSpRn4YGHinjtxuZTmM7vAUwlBhiQLLg9dk9qOQJkVNnSgDhfOw+JHm7uwvOfs1jizkfbdjMLMPNiA+cHIghOFZlahQYWVNRwALgCUpoAPgEFawY3Z0RWJwkI/OdcZMnhXer3atD9uOZFMDWZWoN8p6jD7ZSmgfrBWAjdnQmOksc64yVC629YJrNWi+3HMihAtVN1dKmqMnTVGImoIK0tPFR4kp3ZqYimO8UENUSYl4LgYPePTFgo94xgbL7ZAjMDFgWwNlKsJxrXatukpNdq7m8tl+yVagEdA01wWBIm6YyLFTNUsZAEZAmTqM1SpOqUjpyVomD0smN9DvIh4Lt4SPQylMAmFjAMslH5Wixjms9q/k4i8LmrSkWHzIygLsysNpwKT+2Rviu7LwNy6fRlyy8BkFhy3EQ78oVTvhPMvSKD13ZI/qjV370EMUZ6ujm8aLtu23HPZNJ5QqnfCeZekUHrux/VGrv3oIYoz1dDxou27bcc9k01zWqXah3Wu8mpDzTSYCqcTxTLwox6KLx5u0NVenwmBXF2GF27MO0wXWepXWRuLe2SMxR3aIkMPd0KTdWYUC3jABJULlEQCQNlOUxC9mwLd5BA6zF3IlmKxbXKqBbp4HqLnEAS+zXvzHdvY3gOS4EweG5HHzMX5M3j+7OYuf6GMZsZaHKC6C0X2ltZpHWjXUpl7FD2FcHZnXKtPBhnO62c3K6FR3qvTh8qCf9R8tlv8AUaav5Jh3Un9R8tj9RofkmHdQXU++PvXlvON7bNj+EXN/WR+Z92S3tn0U0H0ONVH0DeVmMYo+9RRKeZ2zk7pr6ZLR2hXuLT//2Q==</file>      <feedback format="html">
+        <text><![CDATA[<p>Sorry, listen again.</p>]]></text>
+      </feedback>
+    </answer>
+    <answer fraction="0" format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/flag-denmark.jpg" alt="Denmark flag" width="30" height="20" /> Danish</p>]]></text>
+<file name="flag-denmark.jpg" encoding="base64">/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAZAAA/+4ADkFkb2JlAGTAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQECAQECAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAFAAeAwERAAIRAQMRAf/EALoAAAMBAQAAAAAAAAAAAAAAAAYJCgQHAQACAgMBAAAAAAAAAAAAAAAHCQYIAwQFChAAAAAKBwIIDwEAAAAAAAAAARECEgMTBBQVFwAFBhYIGAkxByFBM2QnR2cZYSJC0iNDhJSkVShoqOgKGhEAAAMEBQQICxkAAAAAAAAAARECEgMTFAAEBRUGMRYHFyFBIqJjCBgJUWFxcoJDg2RFZSaBkaGx0TJCUmKSsjNTcyREpOQl5aYnZygZ/9oADAMBAAIRAxEAPwAlxSak2IOwu9CtLP1O3oAMbEna0KMJTQ0ElFEok5hBwCSTQBAClHsTaRLeqNpKq7lQMJEQyjT1R6DuJpolxRghxa1oulTDxCBHcpHKkxo6HX9xWbzMMeUyXTSjZ77z3jCxKlRH3ak1DxKwBONj6fbsHQwadcUWlhu6rvEo0y12EuXwhot/moNBGCtNmf2eCBXdlyQSABKYveJl+YRSc3vWMTHzFn96afNpX7WhiP2weeNHB8hLQt8iv3qfVoD1tqfYnWy3FlK2vIWgQVQzVwVDELU0EsrclamJMxgSNgRHFgZyGg4gkQgFgGEfALO6x3iCsu3tpLeiCqsgGUgIkIrWlAirqAoSDo05VocU3Q9YddqGCavZ7tbu26ysHr9SQF47RV6u+rKUugyA08cpbUZinYAgM6L99n9Gcnbb1hY3JzeJwTNCGJZhIQtUJVZznI+tDD9oloRUNls8YG6K6qp3REZEQOaZydKWV6dFdaNOZ71iYZdYi1iScVKRh3DFJoD9ffTsy60KMH1RNUTu2ZG9Bs55zzM6zJdXbl1L7s+t3GIxfvmru6+tW+jnukvSXq7kvoU5ORu3QmIULgnjTUT3JM7Z7FSuI/xH+WXnP5T5t5t3d4OvCYvCf7/qUGDJcLEi+wY3amf9RP2N/kx+v1BZylfEv2z7rS+/+IH8n/pz8+pyi1H9Kcc3n7srXZLnW5RdpGuH5jF8Sitm63qBW9yJQuaiLrRqkpys0QDjid5xxiY9Tf1u5yggkSmzNpaU5ZbYJo8g5CpFbW5mW68R2XYGshu8nj1ETN9mHCq75+bN9i21CYJpJNNGJEM2WLycM+Lev0UFH6ydXh3Vu7wFW7eSpNFs49vDQS1rNCdfXzMTkQTaLe7RdSjEMP8AKLzXszVrc2bkmhmC0Zl20903121k2KOC16c830p5hnPrzuhC1PY9H15/sRovDQ66cM3fwu/2/rMNnuDR72in+au1zeXeqOX8CzcU/G0Bku7H5lJ4+lLnXwtAJ+3XC+hRuf8AczvDfUwFzGiSBc/PbqmdDXMzlES5YPxuSGIXHTpVbMOQrMKJLspb6JREEXZFSE25ys87rFnZO9oz+XI2WpSsRGtv4psi2yp//9k=</file>      <feedback format="html">
+        <text><![CDATA[<p>Sorry, listen again.</p>]]></text>
+      </feedback>
+    </answer>
+  </question>
+
+</quiz>
\ No newline at end of file
diff --git a/question/format/xml/tests/fixtures/truefalse.xml b/question/format/xml/tests/fixtures/truefalse.xml
new file mode 100644 (file)
index 0000000..2453a30
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<quiz>
+<!-- question: 0  -->
+  <question type="category">
+    <category>
+        <text>$course$/Default for testhead/TrueFalse</text>
+
+    </category>
+  </question>
+
+<!-- question: 2284  -->
+  <question type="truefalse">
+    <name>
+      <text>Moodle acronym (False)</text>
+    </name>
+    <questiontext format="html">
+      <text><![CDATA[<p>Moodle <img src="@@PLUGINFILE@@/logo.jpg" alt="Moodle logo" width="48" height="48" /> is an acronym for <span style="font-style: italic;">Modular Object-Oriented Dynamic Learning Education</span>.</p>]]></text>
+<file name="logo.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBggGBQkIBwgKCQkKDRYODQwMDRoTFBAWHxwhICocHh4jJzIqIyUvLR4eNzssLy41ODg0JSo4QTAqPDwsNDUBCQoKDQsNGQ4OGTUkHiQ1NTU1NTU1NTU1NTUuNTU1LTU1NTU1NTQsMjU1NTU1NSk0KSw0MjQ2Miw1NDQyNDQ0Nf/AABEIADAAMAMBIgACEQEDEQH/xAAbAAEAAgIDAAAAAAAAAAAAAAAHAAYDBQEECP/EADUQAAEDAwEEBgcJAAAAAAAAAAECAwQABREGEiExURNBYXORsQcUFRZDYqEXIyQ2QnGywfD/xAAYAQEAAwEAAAAAAAAAAAAAAAAAAQMEAv/EACIRAAEEAgIBBQAAAAAAAAAAAAMAAQIEETESIeEFUYGhsf/aAAwDAQACEQMRAD8AcalSsT8lmMkKfdbaSeBWoJH1oiy1K0z+sbDGTly7Q+WEuhR8BWW16lt16dUm3vF9KeLiUKCM8tojGaItpUqVKIqRq7Xr9sBj2i3yZEg/FUyoIT2jPH/caHbtepdzubqr3ch06fhLXgp7N/DwFOMwx/f9MZxoEuQUuBRJI3OKGMcOsdtHOsNMRGLxNu7TilqcfUVNuIBAwcYBGKpKcYcc3xlWjFMueDaVEj3Bj2mwOi9ZZ6QBaUfqGeA516GsKbTAtTD7LiSgpGyAN6ezZHDFG1j9GsyVLXd0pSwlP3jTSgOXnXfuM+VDiNR4qg2uSpKARu3msNu7MBIwjHPL9WqtViaDzeWkie9ltSrZcW432qbOK2caUzLZDsdxLrauCknIo6XpCdbrYJ65q3hu20L5E43eNcaZubtq1emEFH1eUkko6goddViuHhYYB2bvWF3OsKQXKF9e6sdzVI+0SGCn8N6go7Xz9Kn+qquskj2fK71f8qTHojTzyHlIBcQMJV1gccfQUa6ptl7lPSYzVv2mluKUle2N4Jzzp6oEheHBs4dcUiRg8uT46V8s35fa7s+VHN8QBNtffN+YpItTTjdjbQUkL6PGDzo6m2q9yrnEDtvKG47ySVBQO4H96i+EhDilBum39KapIxHNnfaQruM6acHyJ8xVAaSB6QIGOSqQbsy+7px1uO30j2wnZRnGSCKoVstt3e1dFly4JZbbyCQoGoshJK8ObN02O/l0CSLVpRd+38L/2Q==</file>    </questiontext>
+    <generalfeedback format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/infos.jpg" alt="Informations" width="34" height="49" />For further information, see the <a title="Moodle Docs - About Moodle" href="http://docs.moodle.org/en/About_Moodle">documentation about Moodle</a>.</p>]]></text>
+<file name="infos.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBggGBQkIBwgKCQkKGRYaDQwMDRodFBAhKhwlIB8lHh4jIjIoIyQvJSQeKy8sLzMtODgsISo9QTs2QTIuMywBCQoKDQsNGQ4OGTUkHiQ1NTU1NTU1NTU1NTU1NTU1Ly82NTU1NDUtLTQ0NTU1MCwsLCw0KTU0LzU2NjMpKTQ2Kf/AABEIADEAIgMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAABQYHBAID/8QALhAAAQMCBAMHBAMAAAAAAAAAAgABAwQFBhEhMUFRgRITIjJxsfAHYWKRFBVC/8QAGQEAAgMBAAAAAAAAAAAAAAAAAAEDBAUC/8QAIREAAgEDBAMBAAAAAAAAAAAAAAECAxExBBITISIjQQX/2gAMAwEAAhEDEQA/ANxXk5AiHtSGINzJ8lz3GvitlCdTOTCAcVl16xZU3SoMhMoof8iz65fdWaGmlXfWCOpUUMmrDVwGbCM8RE+zMbZuvqsdvzR2WSme3Xf+W8o5n3ZeX11dsn5PyVowJjUrof8AX1xN3w+Qufzbq3TuppHCHJF3RzGqnLa8l6REVMmKV9UpzhsMLA7sJF4v2yySe5OD9mPV+LvwW84osg3+xzUj6G7eF23+cfVmWAXW01Vnrnp62JwJn0LLwn6fNFt/mzi4OH0p6iLvuJ3HZi01EUEQQCTFm0YMLPtyUdg+eePFNI8RF2vFx/F392ZSGN7va7sVva0yHI0Ik0jlG46u7ZZZ77Kx/TPBdQFc1zr4ii7HkAm1bjryd9NOWee7KS/Fo/Zl3FbdV8TV0RFgF0LiuFmoboDjWU4SZ75t78H6rtRCdgISiwdaKCbvYKUBPg4gIu3UWZ1MhGEQMEYsAtswtoy9Im5OXbYrWCIiQwiIgAiIgAiIgD//2Q==</file>    </generalfeedback>
+    <defaultgrade>1.0000000</defaultgrade>
+    <penalty>1.0000000</penalty>
+    <hidden>0</hidden>
+    <answer fraction="0" format="moodle_auto_format">
+      <text>true</text>
+      <feedback format="html">
+        <text><![CDATA[<p><img src="@@PLUGINFILE@@/thumbdown.jpg" alt="Thumb down" width="24" height="24" /> Your answer is incorrect.</p>]]></text>
+<file name="thumbdown.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzf/wAARCAAYABgDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAQFAQMGB//EACcQAAIBAwMDBAMBAAAAAAAAAAECAwAEBQYRIRITMTJBUXEiUmKh/8QAFwEAAwEAAAAAAAAAAAAAAAAAAgQFA//EACIRAAIBAwQCAwAAAAAAAAAAAAECAwAEERIhMVEFQROh8f/aAAwDAQACEQMRAD8A9AubiTK5m5t5JpEihZlVUiaTbpO3pX5PvWy4wLR2Ml1Fc9QRS/TJAYzsPPnn2+KqsdcompsksjxoO7MAZLpoBv3P2Uf5XTX17BFpm7l7iSKI2jJhnM4DNwPyPJ9QPPipiKkgZn537q9N8kLIkfBx17+6qrd7vC5i2tZpFKzMoKoSVIY7b/e9KrchmoMtqXGS2qyKglhTZwAd+5v7fdKYtGB1BTsDtSfkY2XQzjDEb1jVGlb45Oe6sYmmincuQnJUnzx91GgsdQQ4efFrj5jBO4diYh1Ajbwer+RSlC1jGWLAkZ6/KJPLzhFQgHGOR1x7qTpfSt8MnBdX0TQxQOHAfgsR44+6UpW8ECwrpWlLq7kun1yV/9k=</file>      </feedback>
+    </answer>
+    <answer fraction="100" format="moodle_auto_format">
+      <text>false</text>
+      <feedback format="html">
+        <text><![CDATA[<p><img src="@@PLUGINFILE@@/thumbup.jpg" alt="Thumb up" width="24" height="24" /> Your answer is correct.</p>]]></text>
+<file name="thumbup.jpg" encoding="base64">/9j/4AAQSkZJRgABAQEAYABgAAD/4RDARXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAExAAIAAAAuAAAIVgEyAAIAAAAUAAAIhIdpAAQAAAABAAAImOocAAcAAAgMAAAASgAAAAAc6gAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE1pY3Jvc29mdCBXaW5kb3dzIFBob3RvIFZpZXdlciA2LjEuNzYwMC4xNjM4NQAyMDEzOjAxOjEwIDE4OjI1OjUzAAAB6hwABwAACAwAAAiqAAAAABzqAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4TG4aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+PHhtcDpDcmVhdG9yVG9vbD5NaWNyb3NvZnQgV2luZG93cyBQaG90byBWaWV3ZXIgNi4xLjc2MDAuMTYzODU8L3htcDpDcmVhdG9yVG9vbD48L3JkZjpEZXNjcmlwdGlvbj48L3JkZjpSREY+PC94OnhtcG1ldGE+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSd3Jz8+/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgAGAAYAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A99+OX7RviD/hMdS0fQrt9O0/TpzAzwLh5WUfP83+9WHqPjz4o6Z4D0zxZJ4n1FtPv5ngiCXKeYrLu+8vlf8ATJ61fB3wssfiL8W/FVjfyTRQ/a76dXhKht32nb/ED617p4Y8IadbfA3RbOSCKaFbZLtFvtPfUQkkh3N+6T5m/wBYy/L90e1fndHDYzHValWVVqOtrO2x+w4jG5RleGw9CGHjOS5XO63TXQ8T+CP7RviE+MtN0XxBdvqWn6lOsKNcDc8bsPl+f/eoqv4x0CGy+Lfhia2SCKNbuycrbaVLp6l/tP8Azykb9aK7MFjMRhoSo1ZtuL3/AKZ4ue4HA4ypSxNCkoKcU2vmzvdY0zV/hR4/1TUrOCNo7ySSRJpi5jZZG3bf97dV3Svi5LZ+GbXRbvShPFBGsHm2t+9qwVRhMbfmH3f71FFefi8TVwdepSouy1PXwOEoZlg6dfExvKy8tvQztH8PXHxB8d6TfQ2NxaWVpIksks13LcFfLfcB5sn95v4P9miiivpsqw8MRQdSpq2/L/I+SzitOjinRp6RirL+mf/Z</file>      </feedback>
+    </answer>
+  </question>
+
+<!-- question: 2283  -->
+  <question type="truefalse">
+    <name>
+      <text>Moodle acronym (True)</text>
+    </name>
+    <questiontext format="html">
+      <text><![CDATA[<p>Moodle <img src="@@PLUGINFILE@@/logo.jpg" alt="Moodle logo" width="48" height="48" /> is an acronym for <span style="font-style: italic;">Modular Object-Oriented Dynamic Learning Environment</span>.</p>]]></text>
+<file name="logo.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBggGBQkIBwgKCQkKDRYODQwMDRoTFBAWHxwhICocHh4jJzIqIyUvLR4eNzssLy41ODg0JSo4QTAqPDwsNDUBCQoKDQsNGQ4OGTUkHiQ1NTU1NTU1NTU1NTUuNTU1LTU1NTU1NTQsMjU1NTU1NSk0KSw0MjQ2Miw1NDQyNDQ0Nf/AABEIADAAMAMBIgACEQEDEQH/xAAbAAEAAgIDAAAAAAAAAAAAAAAHAAYDBQEECP/EADUQAAEDAwEEBgcJAAAAAAAAAAECAwQABREGEiExURNBYXORsQcUFRZDYqEXIyQ2QnGywfD/xAAYAQEAAwEAAAAAAAAAAAAAAAAAAQMEAv/EACIRAAEEAgIBBQAAAAAAAAAAAAMAAQIEETESIeEFUYGhsf/aAAwDAQACEQMRAD8AcalSsT8lmMkKfdbaSeBWoJH1oiy1K0z+sbDGTly7Q+WEuhR8BWW16lt16dUm3vF9KeLiUKCM8tojGaItpUqVKIqRq7Xr9sBj2i3yZEg/FUyoIT2jPH/caHbtepdzubqr3ch06fhLXgp7N/DwFOMwx/f9MZxoEuQUuBRJI3OKGMcOsdtHOsNMRGLxNu7TilqcfUVNuIBAwcYBGKpKcYcc3xlWjFMueDaVEj3Bj2mwOi9ZZ6QBaUfqGeA516GsKbTAtTD7LiSgpGyAN6ezZHDFG1j9GsyVLXd0pSwlP3jTSgOXnXfuM+VDiNR4qg2uSpKARu3msNu7MBIwjHPL9WqtViaDzeWkie9ltSrZcW432qbOK2caUzLZDsdxLrauCknIo6XpCdbrYJ65q3hu20L5E43eNcaZubtq1emEFH1eUkko6goddViuHhYYB2bvWF3OsKQXKF9e6sdzVI+0SGCn8N6go7Xz9Kn+qquskj2fK71f8qTHojTzyHlIBcQMJV1gccfQUa6ptl7lPSYzVv2mluKUle2N4Jzzp6oEheHBs4dcUiRg8uT46V8s35fa7s+VHN8QBNtffN+YpItTTjdjbQUkL6PGDzo6m2q9yrnEDtvKG47ySVBQO4H96i+EhDilBum39KapIxHNnfaQruM6acHyJ8xVAaSB6QIGOSqQbsy+7px1uO30j2wnZRnGSCKoVstt3e1dFly4JZbbyCQoGoshJK8ObN02O/l0CSLVpRd+38L/2Q==</file>    </questiontext>
+    <generalfeedback format="html">
+      <text><![CDATA[<p><img src="@@PLUGINFILE@@/infos.jpg" alt="Informations" width="34" height="49" />For further information, see the <a title="Moodle Docs - About Moodle" href="http://docs.moodle.org/en/About_Moodle">documentation about Moodle</a></p>\r
+<p>.</p>]]></text>
+<file name="infos.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBggGBQkIBwgKCQkKGRYaDQwMDRodFBAhKhwlIB8lHh4jIjIoIyQvJSQeKy8sLzMtODgsISo9QTs2QTIuMywBCQoKDQsNGQ4OGTUkHiQ1NTU1NTU1NTU1NTU1NTU1Ly82NTU1NDUtLTQ0NTU1MCwsLCw0KTU0LzU2NjMpKTQ2Kf/AABEIADEAIgMBIgACEQEDEQH/xAAaAAEAAwEBAQAAAAAAAAAAAAAABQYHBAID/8QALhAAAQMCBAMHBAMAAAAAAAAAAgABAwQFBhEhMUFRgRITIjJxsfAHYWKRFBVC/8QAGQEAAgMBAAAAAAAAAAAAAAAAAAEDBAUC/8QAIREAAgEDBAMBAAAAAAAAAAAAAAECAxExBBITISIjQQX/2gAMAwEAAhEDEQA/ANxXk5AiHtSGINzJ8lz3GvitlCdTOTCAcVl16xZU3SoMhMoof8iz65fdWaGmlXfWCOpUUMmrDVwGbCM8RE+zMbZuvqsdvzR2WSme3Xf+W8o5n3ZeX11dsn5PyVowJjUrof8AX1xN3w+Qufzbq3TuppHCHJF3RzGqnLa8l6REVMmKV9UpzhsMLA7sJF4v2yySe5OD9mPV+LvwW84osg3+xzUj6G7eF23+cfVmWAXW01Vnrnp62JwJn0LLwn6fNFt/mzi4OH0p6iLvuJ3HZi01EUEQQCTFm0YMLPtyUdg+eePFNI8RF2vFx/F392ZSGN7va7sVva0yHI0Ik0jlG46u7ZZZ77Kx/TPBdQFc1zr4ii7HkAm1bjryd9NOWee7KS/Fo/Zl3FbdV8TV0RFgF0LiuFmoboDjWU4SZ75t78H6rtRCdgISiwdaKCbvYKUBPg4gIu3UWZ1MhGEQMEYsAtswtoy9Im5OXbYrWCIiQwiIgAiIgAiIgD//2Q==</file>    </generalfeedback>
+    <defaultgrade>1.0000000</defaultgrade>
+    <penalty>1.0000000</penalty>
+    <hidden>0</hidden>
+    <answer fraction="100" format="moodle_auto_format">
+      <text>true</text>
+      <feedback format="html">
+        <text><![CDATA[<p><img src="@@PLUGINFILE@@/thumbup.jpg" alt="thumb up" width="24" height="24" /> Your answer is correct.</p>]]></text>
+<file name="thumbup.jpg" encoding="base64">/9j/4AAQSkZJRgABAQEAYABgAAD/4RDARXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAExAAIAAAAuAAAIVgEyAAIAAAAUAAAIhIdpAAQAAAABAAAImOocAAcAAAgMAAAASgAAAAAc6gAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE1pY3Jvc29mdCBXaW5kb3dzIFBob3RvIFZpZXdlciA2LjEuNzYwMC4xNjM4NQAyMDEzOjAxOjEwIDE4OjI1OjUzAAAB6hwABwAACAwAAAiqAAAAABzqAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4TG4aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEtYWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+PHhtcDpDcmVhdG9yVG9vbD5NaWNyb3NvZnQgV2luZG93cyBQaG90byBWaWV3ZXIgNi4xLjc2MDAuMTYzODU8L3htcDpDcmVhdG9yVG9vbD48L3JkZjpEZXNjcmlwdGlvbj48L3JkZjpSREY+PC94OnhtcG1ldGE+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSd3Jz8+/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgAGAAYAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A99+OX7RviD/hMdS0fQrt9O0/TpzAzwLh5WUfP83+9WHqPjz4o6Z4D0zxZJ4n1FtPv5ngiCXKeYrLu+8vlf8ATJ61fB3wssfiL8W/FVjfyTRQ/a76dXhKht32nb/ED617p4Y8IadbfA3RbOSCKaFbZLtFvtPfUQkkh3N+6T5m/wBYy/L90e1fndHDYzHValWVVqOtrO2x+w4jG5RleGw9CGHjOS5XO63TXQ8T+CP7RviE+MtN0XxBdvqWn6lOsKNcDc8bsPl+f/eoqv4x0CGy+Lfhia2SCKNbuycrbaVLp6l/tP8Azykb9aK7MFjMRhoSo1ZtuL3/AKZ4ue4HA4ypSxNCkoKcU2vmzvdY0zV/hR4/1TUrOCNo7ySSRJpi5jZZG3bf97dV3Svi5LZ+GbXRbvShPFBGsHm2t+9qwVRhMbfmH3f71FFefi8TVwdepSouy1PXwOEoZlg6dfExvKy8tvQztH8PXHxB8d6TfQ2NxaWVpIksks13LcFfLfcB5sn95v4P9miiivpsqw8MRQdSpq2/L/I+SzitOjinRp6RirL+mf/Z</file>      </feedback>
+    </answer>
+    <answer fraction="0" format="moodle_auto_format">
+      <text>false</text>
+      <feedback format="html">
+        <text><![CDATA[<p><img src="@@PLUGINFILE@@/thumbdown.jpg" alt="thumb down" width="24" height="24" /> Your answer is incorrect.</p>]]></text>
+<file name="thumbdown.jpg" encoding="base64">/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzf/wAARCAAYABgDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAQFAQMGB//EACcQAAIBAwMDBAMBAAAAAAAAAAECAwAEBQYRIRITMTJBUXEiUmKh/8QAFwEAAwEAAAAAAAAAAAAAAAAAAgQFA//EACIRAAIBAwQCAwAAAAAAAAAAAAECAwAEERIhMVEFQROh8f/aAAwDAQACEQMRAD8A9AubiTK5m5t5JpEihZlVUiaTbpO3pX5PvWy4wLR2Ml1Fc9QRS/TJAYzsPPnn2+KqsdcompsksjxoO7MAZLpoBv3P2Uf5XTX17BFpm7l7iSKI2jJhnM4DNwPyPJ9QPPipiKkgZn537q9N8kLIkfBx17+6qrd7vC5i2tZpFKzMoKoSVIY7b/e9KrchmoMtqXGS2qyKglhTZwAd+5v7fdKYtGB1BTsDtSfkY2XQzjDEb1jVGlb45Oe6sYmmincuQnJUnzx91GgsdQQ4efFrj5jBO4diYh1Ajbwer+RSlC1jGWLAkZ6/KJPLzhFQgHGOR1x7qTpfSt8MnBdX0TQxQOHAfgsR44+6UpW8ECwrpWlLq7kun1yV/9k=</file>      </feedback>
+    </answer>
+  </question>
+
+</quiz>
\ No newline at end of file
index fd5eb55..fd409c2 100644 (file)
@@ -202,9 +202,9 @@ END;
 
         $this->assertEquals(array(
                 array('text' => 'This is the first hint',
-                        'format' => FORMAT_HTML, 'files' => array()),
+                        'format' => FORMAT_HTML),
                 array('text' => 'This is the second hint',
-                        'format' => FORMAT_HTML, 'files' => array()),
+                        'format' => FORMAT_HTML),
                 ), $qo->hint);
         $this->assertFalse(isset($qo->hintclearwrong));
         $this->assertFalse(isset($qo->hintshownumcorrect));
@@ -232,9 +232,9 @@ END;
 
         $this->assertEquals(array(
                 array('text' => 'This is the first hint',
-                        'format' => FORMAT_HTML, 'files' => array()),
+                        'format' => FORMAT_HTML),
                 array('text' => 'This is the second hint',
-                        'format' => FORMAT_HTML, 'files' => array()),
+                        'format' => FORMAT_HTML),
                 ), $qo->hint);
         $this->assertEquals(array(1, 0), $qo->hintclearwrong);
         $this->assertEquals(array(0, 1), $qo->hintshownumcorrect);
@@ -360,7 +360,6 @@ END;
         $expectedq->attachments = 0;
         $expectedq->graderinfo['text'] = '';
         $expectedq->graderinfo['format'] = FORMAT_MOODLE;
-        $expectedq->graderinfo['files'] = array();
 
         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
     }
@@ -405,7 +404,6 @@ END;
         $expectedq->attachments = -1;
         $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>';
         $expectedq->graderinfo['format'] = FORMAT_HTML;
-        $expectedq->graderinfo['files'] = array();
 
         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
     }
@@ -531,12 +529,12 @@ END;
         $expectedq->questiontext = 'Match the upper and lower case letters.';
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array('text' => 'Well done.',
-                'format' => FORMAT_HTML, 'files' => array());
+                'format' => FORMAT_HTML);
         $expectedq->partiallycorrectfeedback = array('text' => 'Not entirely.',
-                'format' => FORMAT_HTML, 'files' => array());
+                'format' => FORMAT_HTML);
         $expectedq->shownumcorrect = false;
         $expectedq->incorrectfeedback = array('text' => 'Completely wrong!',
-                'format' => FORMAT_HTML, 'files' => array());
+                'format' => FORMAT_HTML);
         $expectedq->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
         $expectedq->generalfeedbackformat = FORMAT_HTML;
         $expectedq->defaultmark = 1;
@@ -544,14 +542,14 @@ END;
         $expectedq->penalty = 0.3333333;
         $expectedq->shuffleanswers = 0;
         $expectedq->subquestions = array(
-            array('text' => 'A', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => 'B', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => 'C', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()));
+            array('text' => 'A', 'format' => FORMAT_HTML),
+            array('text' => 'B', 'format' => FORMAT_HTML),
+            array('text' => 'C', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML));
         $expectedq->subanswers = array('a', 'b', 'c', 'd');
         $expectedq->hint = array(
-            array('text' => 'Hint 1', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'Hint 1', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML),
         );
         $expectedq->hintshownumcorrect = array(true, true);
         $expectedq->hintclearwrong = array(false, true);
@@ -752,18 +750,15 @@ END;
         $expectedq->questiontextformat = FORMAT_HTML;
         $expectedq->correctfeedback = array(
                 'text'   => '<p>Your answer is correct.</p>',
-                'format' => FORMAT_HTML,
-                'files'  => array());
+                'format' => FORMAT_HTML);
         $expectedq->shownumcorrect = false;
         $expectedq->partiallycorrectfeedback = array(
                 'text'   => '<p>Your answer is partially correct.</p>',
-                'format' => FORMAT_HTML,
-                'files'  => array());
+                'format' => FORMAT_HTML);
         $expectedq->shownumcorrect = true;
         $expectedq->incorrectfeedback = array(
                 'text'   => '<p>Your answer is incorrect.</p>',
-                'format' => FORMAT_HTML,
-                'files'  => array());
+                'format' => FORMAT_HTML);
         $expectedq->generalfeedback = 'The even numbers are 2 and 4.';
         $expectedq->defaultmark = 2;
         $expectedq->length = 1;
@@ -772,20 +767,20 @@ END;
         $expectedq->single = false;
 
         $expectedq->answer = array(
-            array('text' => '1', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '2', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '3', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '4', 'format' => FORMAT_HTML, 'files' => array()));
+            array('text' => '1', 'format' => FORMAT_HTML),
+            array('text' => '2', 'format' => FORMAT_HTML),
+            array('text' => '3', 'format' => FORMAT_HTML),
+            array('text' => '4', 'format' => FORMAT_HTML));
         $expectedq->fraction = array(0, 1, 0, 1);
         $expectedq->feedback = array(
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()));
+            array('text' => '', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML));
 
         $expectedq->hint = array(
-            array('text' => 'Hint 1.', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => 'Hint 2.', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'Hint 1.', 'format' => FORMAT_HTML),
+            array('text' => 'Hint 2.', 'format' => FORMAT_HTML),
         );
         $expectedq->hintshownumcorrect = array(false, false);
         $expectedq->hintclearwrong = array(false, false);
@@ -954,11 +949,11 @@ END;
         $expectedq->fraction = array(1, 0, 0);
         $expectedq->feedback = array(
             array('text' => 'Well done!',
-                    'format' => FORMAT_HTML, 'files' => array()),
+                    'format' => FORMAT_HTML),
             array('text' => 'What were you thinking?!',
-                    'format' => FORMAT_HTML, 'files' => array()),
+                    'format' => FORMAT_HTML),
             array('text' => 'Completely wrong.',
-                    'format' => FORMAT_HTML, 'files' => array()));
+                    'format' => FORMAT_HTML));
         $expectedq->tolerance = array(0.001, 1, 0);
 
         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
@@ -1090,8 +1085,8 @@ END;
         $expectedq->answer = array('Beta', '*');
         $expectedq->fraction = array(1, 0);
         $expectedq->feedback = array(
-            array('text' => 'Well done!', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => 'Doh!', 'format' => FORMAT_HTML, 'files' => array()));
+            array('text' => 'Well done!', 'format' => FORMAT_HTML),
+            array('text' => 'Doh!', 'format' => FORMAT_HTML));
 
         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
     }
@@ -1209,9 +1204,9 @@ END;
         $expectedq->penalty = 1;
 
         $expectedq->feedbacktrue = array('text' => 'Well done!',
-                'format' => FORMAT_HTML, 'files' => array());
+                'format' => FORMAT_HTML);
         $expectedq->feedbackfalse = array('text' => 'Doh!',
-                'format' => FORMAT_HTML, 'files' => array());
+                'format' => FORMAT_HTML);
         $expectedq->correctanswer = true;
 
         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
@@ -1313,8 +1308,8 @@ END;
         $expectedqa->penalty = 0.5;
 
         $expectedqa->hint = array(
-            array('text' => 'Hint 1', 'format' => FORMAT_HTML, 'files' => array()),
-            array('text' => 'Hint 2', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'Hint 1', 'format' => FORMAT_HTML),
+            array('text' => 'Hint 2', 'format' => FORMAT_HTML),
         );
 
         $sa = new stdClass();
@@ -1406,4 +1401,30 @@ END;
 
         $this->assert_same_xml($expectedxml, $xml);
     }
+
+    public function test_import_files_as_draft() {
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        $xml = <<<END
+<questiontext format="html">
+    <text><![CDATA[<p><a href="@@PLUGINFILE@@/moodle.txt">This text file</a> contains the word 'Moodle'.</p>]]></text>
+    <file name="moodle.txt" encoding="base64">TW9vZGxl</file>
+</questiontext>
+END;
+
+        $textxml = xmlize($xml);
+        $qo = new stdClass();
+
+        $importer = new qformat_xml();
+        $draftitemid = $importer->import_files_as_draft($textxml['questiontext']['#']['file']);
+        $files = file_get_drafarea_files($draftitemid);
+
+        $this->assertEquals(1, count($files->list));
+
+        $file = $files->list[0];
+        $this->assertEquals('moodle.txt', $file->filename);
+        $this->assertEquals('/',          $file->filepath);
+        $this->assertEquals(6,            $file->size);
+    }
 }
index 063446e..7b7d85e 100644 (file)
@@ -341,14 +341,16 @@ function question_preview_cron() {
             'quba.component = :qubacomponent
                     AND NOT EXISTS (
                         SELECT 1
-                          FROM {question_attempts} qa
-                          JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
-                         WHERE qa.questionusageid = quba.id
-                           AND (qa.timemodified > :qamodifiedcutoff
-                                    OR qas.timecreated > :stepcreatedcutoff)
+                          FROM {question_attempts}      subq_qa
+                          JOIN {question_attempt_steps} subq_qas ON subq_qas.questionattemptid = subq_qa.id
+                          JOIN {question_usages}        subq_qu  ON subq_qu.id = subq_qa.questionusageid
+                         WHERE subq_qa.questionusageid = quba.id
+                           AND subq_qu.component = :qubacomponent2
+                           AND (subq_qa.timemodified > :qamodifiedcutoff
+                                    OR subq_qas.timecreated > :stepcreatedcutoff)
                     )
             ',
-            array('qubacomponent' => 'core_question_preview',
+            array('qubacomponent' => 'core_question_preview', 'qubacomponent2' => 'core_question_preview',
                 'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff));
 
     question_engine::delete_questions_usage_by_activities($oldpreviews);
index 714d6a8..a90f33e 100644 (file)
@@ -481,7 +481,7 @@ abstract class question_edit_form extends question_wizard_form {
         if (is_array($extraquestionfields) && !empty($question->options)) {
             array_shift($extraquestionfields);
             foreach ($extraquestionfields as $field) {
-                if (isset($question->options->$field)) {
+                if (property_exists($question->options, $field)) {
                     $question->$field = $question->options->$field;
                 }
             }
index dac965e..10a1346 100644 (file)
@@ -80,6 +80,13 @@ class qtype_essay extends question_type {
         $question->graderinfoformat = $questiondata->options->graderinfoformat;
     }
 
+    public function delete_question($questionid, $contextid) {
+        global $DB;
+
+        $DB->delete_records('qtype_essay_options', array('questionid' => $questionid));
+        parent::delete_question($questionid, $contextid);
+    }
+
     /**
      * @return array the different response formats that the question type supports.
      * internal name => human-readable name.
index 52e42cc..e387e02 100644 (file)
@@ -454,21 +454,12 @@ class question_type {
                 $options->$questionidcolname = $question->id;
             }
             foreach ($extraquestionfields as $field) {
-                if (!isset($question->$field)) {
-                    $result = new stdClass();
-                    $result->error = "No data for field $field when saving " .
-                            $this->name() . ' question id ' . $question->id;
-                    return $result;
+                if (property_exists($question, $field)) {
+                    $options->$field = $question->$field;
                 }
-                $options->$field = $question->$field;
             }
 
-            if (!$DB->{$function}($question_extension_table, $options)) {
-                $result = new stdClass();
-                $result->error = 'Could not save question options for ' .
-                        $this->name() . ' question id ' . $question->id;
-                return $result;
-            }
+            $DB->{$function}($question_extension_table, $options);
         }
 
         $extraanswerfields = $this->extra_answer_fields();
index 7c82e66..864f356 100644 (file)
@@ -148,7 +148,8 @@ foreach ($modinfo->sections as $sectionnum=>$section) {
             $blogcell = new html_table_cell();
             $blogcell->attributes['class'] = 'blog';
             if ($blogcount = blog_get_associated_count($course->id, $cm->id)) {
-                $blogcell->text = html_writer::link('/blog/index.php?modid='.$cm->id, $blogcount);
+                $blogurl = new moodle_url('/blog/index.php', array('modid' => $cm->id));
+                $blogcell->text = html_writer::link($blogurl, $blogcount);
             } else {
                 $blogcell->text = '-';
             }
index 17cdb57..6b11cfc 100644 (file)
@@ -440,7 +440,7 @@ class repository_flickr_public extends repository {
     }
 
     public function get_link($photoid) {
-        return $this->build_photo_id($photoid);
+        return $this->build_photo_url($photoid);
     }
 
     /**
index 5508530..9314951 100644 (file)
@@ -899,7 +899,6 @@ sup {vertical-align: super;}
 
 /* Only set these options if we're showing the js container */
 .jsenabled .choosercontainer #chooseform .alloptions {
-    max-height: 550px;
     overflow-x: hidden;
     overflow-y: auto;
     max-width: 20.3em;
@@ -973,7 +972,6 @@ sup {vertical-align: super;}
     background-color: #FFFFFF;
     overflow-x: hidden;
     overflow-y: auto;
-    max-height: 550px;
     line-height: 2em;
 }
 
index d073270..12a7208 100644 (file)
@@ -47,6 +47,9 @@
 .dir-rtl.path-course-view li.activity span.autocompletion {right:-20px;left:auto;padding:0px;}
 .dir-rtl.path-course-view .completionprogress {float: none;}
 
+li.section.hidden span.commands a.editing_hide,
+li.section.hidden span.commands a.editing_show {cursor:default;}
+
 .section img.movetarget {height:16px;width:80px;}
 
 #page-course-enrol .generalbox,
index b3abbbf..bfa603d 100644 (file)
                     }
                     if ($user->maildisplay == 1 or ($user->maildisplay == 2 and ($course->id != SITEID) and !isguestuser()) or
                                 has_capability('moodle/course:viewhiddenuserfields', $context) or
-                                in_array('email', $extrafields)) {
+                                in_array('email', $extrafields) or ($user->id == $USER->id)) {
                         $row->cells[1]->text .= get_string('email').get_string('labelsep', 'langconfig').html_writer::link("mailto:$user->email", $user->email) . '<br />';
                     }
                     foreach ($extrafields as $field) {
index 53670e9..879a35f 100644 (file)
@@ -96,6 +96,9 @@ class core_user_external_testcase extends externallib_advanced_testcase {
                     array('userid' => $user1->id, 'courseid' => $course->id),
                     array('userid' => $user2->id, 'courseid' => $course->id)));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $enrolledusers = external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers);
+
         // Check we retrieve the good total number of enrolled users + no error on capability.
         $this->assertEquals(3, count($enrolledusers));
 
@@ -109,6 +112,9 @@ class core_user_external_testcase extends externallib_advanced_testcase {
                     array('userid' => $user1->id, 'courseid' => $course->id),
                     array('userid' => $user2->id, 'courseid' => $course->id)));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $enrolledusers = external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers);
+
         foreach($enrolledusers as $enrolleduser) {
             if ($enrolleduser['username'] == $user1->username) {
                 $this->assertEquals($user1->idnumber, $enrolleduser['idnumber']);
@@ -163,6 +169,9 @@ class core_user_external_testcase extends externallib_advanced_testcase {
         // Call the external function.
         $createdusers = core_user_external::create_users(array($user1));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $createdusers = external_api::clean_returnvalue(core_user_external::create_users_returns(), $createdusers);
+
         // Check we retrieve the good total number of created users + no error on capability.
         $this->assertEquals(1, count($createdusers));
 
@@ -261,6 +270,9 @@ class core_user_external_testcase extends externallib_advanced_testcase {
         $returnedusers = core_user_external::get_users_by_id(array(
                     $USER->id, $user1->id, $user2->id));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $returnedusers = external_api::clean_returnvalue(core_user_external::get_users_by_id_returns(), $returnedusers);
+
         // Check we retrieve the good total number of enrolled users + no error on capability.
         $this->assertEquals(3, count($returnedusers));
 
@@ -272,6 +284,9 @@ class core_user_external_testcase extends externallib_advanced_testcase {
         $returnedusers = core_user_external::get_users_by_id(array(
                     $USER->id, $user1->id, $user2->id));
 
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $returnedusers = external_api::clean_returnvalue(core_user_external::get_users_by_id_returns(), $returnedusers);
+
         foreach($returnedusers as $enrolleduser) {
             if ($enrolleduser['username'] == $user1->username) {
                 $this->assertEquals($user1->idnumber, $enrolleduser['idnumber']);
@@ -344,4 +359,4 @@ class core_user_external_testcase extends externallib_advanced_testcase {
         $this->setExpectedException('required_capability_exception');
         core_user_external::update_users(array($user1));
     }
-}
\ No newline at end of file
+}
index a970e61..471cb5d 100644 (file)
@@ -233,12 +233,16 @@ echo '</div>';
 
 echo '<table class="list" summary="">';
 
-//checks were performed above that ensure that if we've got to here either the user
-//is viewing their own profile ($USER->id == $user->id) or $user is enrolled in the course
+// Show email if any of the following conditions match.
+// 1. User is viewing his own profile.
+// 2. Has allowed everyone to see email
+// 3. User has allowed course members to can see email and current user is in same course
+// 4. Has either course:viewhiddenuserfields or site:viewuseridentity capability.
 if ($currentuser
-   or $user->maildisplay == 1 //allow everyone to see email address
-   or ($user->maildisplay == 2 && is_enrolled($coursecontext, $USER)) //fellow course members can see email. Already know $user is enrolled
-   or has_capability('moodle/course:useremail', $coursecontext)) {
+   or $user->maildisplay == 1
+   or ($user->maildisplay == 2 && is_enrolled($coursecontext, $USER))
+   or has_capability('moodle/course:viewhiddenuserfields', $coursecontext)
+   or has_capability('moodle/site:viewuseridentity', $coursecontext)) {
     print_row(get_string("email").":", obfuscate_mailto($user->email, ''));
 }
 
index f89d604..b53d09a 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062504.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062504.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.4 (Build: 20130114)';  // Human-friendly version name
+$release  = '2.3.4+ (Build: 20130118)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
index abd131c..45d9fd6 100644 (file)
@@ -120,7 +120,7 @@ class webservice_rest_server extends webservice_base_server {
             } else {
                 $response = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
                 $response .= '<RESPONSE>'."\n";
-                $response .= self::xmlize_result($this->returns, $this->function->returns_desc);
+                $response .= self::xmlize_result($validatedvalues, $this->function->returns_desc);
                 $response .= '</RESPONSE>'."\n";
             }
         }
@@ -248,4 +248,4 @@ class webservice_rest_test_client implements webservice_test_client_interface {
     public function simpletest($serverurl, $function, $params) {
         return download_file_content($serverurl.'&wsfunction='.$function, null, $params);
     }
-}
\ No newline at end of file
+}