From 9b57d5bc38fb4295c237f634ecb8c0960d2fd1b1 Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Wed, 11 Apr 2012 18:54:40 +1200
Subject: [PATCH 001/903] MDL-32249 completion: Make grade criteria more
 consistent

Also, round course grades and remove hardcoded string.

Note: This patch also removes the ability to update the course grade
from the completion interface
---
 course/completion.php                        |   10 ----------
 course/completion_form.php                   |    5 ++++-
 lang/en/completion.php                       |    4 +++-
 lib/completion/completion_criteria_grade.php |   25 ++++++++++++++-----------
 4 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/course/completion.php b/course/completion.php
index 3d4e17b..a25c2af 100644
--- a/course/completion.php
+++ b/course/completion.php
@@ -141,16 +141,6 @@ if ($form->is_cancelled()){
     $aggregation->setMethod($data->role_aggregation);
     $aggregation->save();
 
-    // Update course total passing grade
-    if (!empty($data->criteria_grade)) {
-        if ($grade_item = grade_category::fetch_course_category($course->id)->grade_item) {
-            $grade_item->gradepass = $data->criteria_grade_value;
-            if (method_exists($grade_item, 'update')) {
-                $grade_item->update('course/completion.php');
-            }
-        }
-    }
-
     add_to_log($course->id, 'course', 'completion updated', 'completion.php?id='.$course->id);
 
     $url = new moodle_url('/course/view.php', array('id' => $course->id));
diff --git a/course/completion_form.php b/course/completion_form.php
index 0a5b543..951776a 100644
--- a/course/completion_form.php
+++ b/course/completion_form.php
@@ -179,10 +179,13 @@ class course_completion_form extends moodleform {
         $criteria->config_form_display($mform);
 
         // Completion on course grade
-        $mform->addElement('header', 'grade', get_string('grade'));
+        $mform->addElement('header', 'grade', get_string('coursegrade', 'completion'));
 
         // Grade enable and passing grade
         $course_grade = $DB->get_field('grade_items', 'gradepass', array('courseid' => $course->id, 'itemtype' => 'course'));
+        if (!$course_grade) {
+            $course_grade = '0.00000';
+        }
         $criteria = new completion_criteria_grade($params);
         $criteria->config_form_display($mform, $course_grade);
 
diff --git a/lang/en/completion.php b/lang/en/completion.php
index 0683c79..9a9d10c 100644
--- a/lang/en/completion.php
+++ b/lang/en/completion.php
@@ -110,6 +110,7 @@ $string['courseprerequisites']='Course prerequisites';
 $string['coursesavailable']='Courses available';
 $string['coursesavailableexplaination']='<i>Course completion criteria must be set for a course to appear in this list</i>';
 $string['criteria']='Criteria';
+$string['criteriagradenote'] = 'Please note that updating the required grade here will not update the current course pass grade.';
 $string['criteriagroup']='Criteria group';
 $string['criteriarequiredall']='All criteria below are required';
 $string['criteriarequiredany']='Any criteria below are required';
@@ -124,6 +125,8 @@ $string['datepassed']='Date passed';
 $string['daysafterenrolment']='Days after enrolment';
 $string['durationafterenrolment']='Duration after enrolment';
 $string['fraction']='Fraction';
+$string['gradexrequired']='{$a} required';
+$string['graderequired']='Grade required';
 $string['inprogress']='In progress';
 $string['manualcompletionby']='Manual completion by';
 $string['manualselfcompletion']='Manual self completion';
@@ -136,7 +139,6 @@ $string['nocriteriaset']='No completion criteria set for this course';
 $string['notenroled']='You are not enrolled in this course';
 $string['notyetstarted']='Not yet started';
 $string['overallcriteriaaggregation']='Overall criteria type aggregation';
-$string['passinggrade']='Passing grade';
 $string['pending']='Pending';
 $string['periodpostenrolment']='Period post enrolment';
 $string['prerequisites']='Prerequisites';
diff --git a/lib/completion/completion_criteria_grade.php b/lib/completion/completion_criteria_grade.php
index 6bc32ed..56a4d0f 100644
--- a/lib/completion/completion_criteria_grade.php
+++ b/lib/completion/completion_criteria_grade.php
@@ -62,8 +62,9 @@ class completion_criteria_grade extends completion_criteria {
      */
     public function config_form_display(&$mform, $data = null) {
         $mform->addElement('checkbox', 'criteria_grade', get_string('enable'));
-        $mform->addElement('text', 'criteria_grade_value', get_string('passinggrade', 'completion'));
+        $mform->addElement('text', 'criteria_grade_value', get_string('graderequired', 'completion'));
         $mform->setDefault('criteria_grade_value', $data);
+        $mform->addElement('static', 'criteria_grade_value_note', '', get_string('criteriagradenote', 'completion'));
 
         if ($this->id) {
             $mform->setDefault('criteria_grade', 1);
@@ -128,7 +129,7 @@ class completion_criteria_grade extends completion_criteria {
      * @return  string
      */
     public function get_title() {
-        return get_string('grade');
+        return get_string('coursegrade', 'completion');
     }
 
     /**
@@ -137,7 +138,8 @@ class completion_criteria_grade extends completion_criteria {
      * @return string
      */
     public function get_title_detailed() {
-        return (float) $this->gradepass . '% required';
+        $graderequired = round($this->gradepass, 2).'%';
+        return get_string('gradexrequired', 'completion', $graderequired);
     }
 
     /**
@@ -156,15 +158,16 @@ class completion_criteria_grade extends completion_criteria {
      * @return string
      */
     public function get_status($completion) {
-        // Cast as floats to get rid of excess decimal places
-        $grade = (float) $this->get_grade($completion);
-        $gradepass = (float) $this->gradepass;
+        $grade = $this->get_grade($completion);
+        $graderequired = $this->get_title_detailed();
 
         if ($grade) {
-            return $grade.'% ('.$gradepass.'% to pass)';
+            $grade = round($grade, 2).'%';
         } else {
-            return $gradepass.'% to pass';
+            $grade = get_string('nograde');
         }
+
+        return $grade.' ('.$graderequired.')';
     }
 
     /**
@@ -231,11 +234,11 @@ class completion_criteria_grade extends completion_criteria {
     public function get_details($completion) {
         $details = array();
         $details['type'] = get_string('coursegrade', 'completion');
-        $details['criteria'] = get_string('passinggrade', 'completion');
-        $details['requirement'] = ((float)$this->gradepass).'%';
+        $details['criteria'] = get_string('graderequired', 'completion');
+        $details['requirement'] = round($this->gradepass, 2).'%';
         $details['status'] = '';
 
-        $grade = (float)$this->get_grade($completion);
+        $grade = round($this->get_grade($completion), 2);
         if ($grade) {
             $details['status'] = $grade.'%';
         }
-- 
1.7.9.5


From 11824b04617442f8f59fd6754ba31ba1b9bd1eaa Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Tue, 26 Jun 2012 03:40:37 +0100
Subject: [PATCH 002/903] MDL-33987_M23 theme_anomaly: amended some css values
 to style dock better also removed exclude parent
 theme stylesheet as it refered to a none existant
 file in base theme.

---
 theme/anomaly/config.php     |    2 --
 theme/anomaly/style/dock.css |   52 ++++++++++++++++++++----------------------
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/theme/anomaly/config.php b/theme/anomaly/config.php
index 6fcbaee..1f32394 100644
--- a/theme/anomaly/config.php
+++ b/theme/anomaly/config.php
@@ -21,8 +21,6 @@ $THEME->parents = array('base');  // TODO: new themes can not be based on standa
 /// is not used.
 ////////////////////////////////////////////////////////////////////////////////
 
-$THEME->parents_exclude_sheets = array('base'=>array('styles_moz'));
-
 $THEME->layouts = array(
     // Most pages - if we encounter an unknown or a missing page type, this one is used.
     'base' => array(
diff --git a/theme/anomaly/style/dock.css b/theme/anomaly/style/dock.css
index 497cf7c..31bf99e 100644
--- a/theme/anomaly/style/dock.css
+++ b/theme/anomaly/style/dock.css
@@ -2,23 +2,21 @@
 -----------------*/
 
 body.has_dock {
-    margin:0;
+    margin: 0;
 }
-
 #dock {
-    width:3%;
-    position:fixed;
-    top:0px;
-    right:0;
-    height:100%;
-    z-index:11000;
+    width: 3%;
+    position: fixed;
+    top: 0;
+    left: 0;
+    height: 100%;
+    z-index: 11000;
     background-color: #C8C9C7;
     border-right: 0 none;
 }
-
 #dock.nothingdocked {
     visibility: hidden;
-    display:none;
+    display: none;
 }
 #dock .controls {
     bottom: auto;
@@ -36,11 +34,11 @@ body.has_dock {
 #dock .dockeditem {
     background-color: #C8C9C7;
     padding: 2px;
-    padding-right: 0px;
+    padding-right: 0;
 }
 #dock .dockedtitle {
-    padding-bottom: 5px;
-    cursor:pointer;
+    padding-bottom: 8px;
+    cursor: pointer;
     background-color: #222;
     -webkit-border-top-left-radius: 10px;
     -moz-border-radius-topleft: 10px;
@@ -50,13 +48,13 @@ body.has_dock {
     border-bottom-left-radius: 10px;
 }
 #dock .dockedtitle h2 {
-    margin: 0;
-    padding: 10px 3px;
+    margin: 8px 0;
+    padding: 0 3px;
     color: #fff;
     font-family: sans-serif;
 }
 .dockedtitle.activeitem h2 {
-    color: #fff !important;
+    color: #fff;
 }
 #dock .dockedtitle.activeitem {
     background-color: #697F55;
@@ -68,7 +66,7 @@ body.has_dock {
     border-bottom-left-radius: 10px;
 }
 #dock .controls img {
-    cursor:pointer;
+    cursor: pointer;
     margin-left: 10px;
 }
 /*
@@ -81,11 +79,11 @@ Docked Item Panel
     left: 100%;
 }
 #dockeditempanel.dockitempanel_hidden {
-    display:none;
+    display: none;
 }
 #dockeditempanel .dockeditempanel_content {
     background-color: #eee;
-    margin: 0 3px;
+    margin: 0 3px 0 0;
     position: relative;
     min-height: 100px;
     border-color: #697F55;
@@ -97,7 +95,6 @@ Docked Item Panel
     -webkit-border-top-left-radius: 0;
     -moz-border-top-left-radius: 0;
     border-top-left-radius: 0;
-
 }
 #dockeditempanel .dockeditempanel_hd {
     border-color: #eee;
@@ -105,7 +102,7 @@ Docked Item Panel
     padding: 2px;
 }
 #dockeditempanel .dockeditempanel_bd .block_docked {
-    margin:10px;
+    margin: 10px;
 }
 #dockeditempanel .block_calendar_month.block_docked {
     text-align: center;
@@ -117,21 +114,22 @@ Docked Item Panel
     border-top-right-radius: 10px;
 }
 #dockeditempanel .dockeditempanel_hd h2 {
-    display:inline;
+    display: inline;
     margin: 0;
     padding-right: 2em;
     color: #000;
-    float: left;
 }
-
 #dockeditempanel .dockeditempanel_hd .commands {
-    display:inline;
+    display: inline;
 }
 #dockeditempanel .dockeditempanel_hd .commands img {
     margin-right: 3px;
     vertical-align: middle;
 }
 #dockeditempanel .dockeditempanel_bd {
-    overflow:auto;
-    width:auto; /* adds scroll to dock panel */
+    overflow: auto;
+    width: auto; /* adds scroll to dock panel */
 }
+#dockeditempanel .dockeditempanel_bd .block_navigation .block_tree li {
+    overflow: visible;
+}
\ No newline at end of file
-- 
1.7.9.5


From 896f9ae83b3eb3ebe6b1feea4182610328d50aa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Tue, 26 Jun 2012 09:12:35 +0200
Subject: [PATCH 003/903] MDL-34019 Fix response item key name

---
 lib/pluginlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index 75a8186..43de510 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -811,7 +811,7 @@ class available_update_checker {
         }
 
         if (empty($response['forbranch']) or $response['forbranch'] !== moodle_major_version(true)) {
-            throw new available_update_checker_exception('err_response_target_version', $response['target']);
+            throw new available_update_checker_exception('err_response_target_version', $response['forbranch']);
         }
     }
 
-- 
1.7.9.5


From 3d348a3cc74a16b089884724f905167362059982 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 20 Jun 2012 16:00:54 +0100
Subject: [PATCH 004/903] MDL-32062 question engine: fix re-grading attempts
 from 2.0

The code to upgrade attempts from before Moodle 2.0 to 2.1 created
attempt data that was not exactly the same as a new attempt created in
2.1+. This did not matter very much - revew and the quiz reports all
worked OK - but it broke on re-grade.

These changes detect the problem data in the re-grade code, an apply a
work-around so that the re-grade gives the correct result.
---
 question/engine/questionattempt.php |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php
index 070c4fc..54c4d9f 100644
--- a/question/engine/questionattempt.php
+++ b/question/engine/questionattempt.php
@@ -1086,15 +1086,32 @@ class question_attempt {
         $first = true;
         foreach ($oldqa->get_step_iterator() as $step) {
             $this->observer->notify_step_deleted($step, $this);
+
             if ($first) {
+                // First step of the attempt.
                 $first = false;
                 $this->start($oldqa->behaviour, $oldqa->get_variant(), $step->get_all_data(),
                         $step->get_timecreated(), $step->get_user_id(), $step->get_id());
+
+            } else if ($step->has_behaviour_var('finish') && count($step->get_submitted_data()) > 1) {
+                // This case relates to MDL-32062. The upgrade code from 2.0
+                // generates attempts where the final submit of the question
+                // data, and the finish action, are in the same step. The system
+                // cannot cope with that, so convert the single old step into
+                // two new steps.
+                $submitteddata = $step->get_submitted_data();
+                unset($submitteddata['-finish']);
+                $this->process_action($submitteddata,
+                        $step->get_timecreated(), $step->get_user_id(), $step->get_id());
+                $this->finish($step->get_timecreated(), $step->get_user_id());
+
             } else {
+                // This is the normal case. Replay the next step of the attempt.
                 $this->process_action($step->get_submitted_data(),
                         $step->get_timecreated(), $step->get_user_id(), $step->get_id());
             }
         }
+
         if ($finished) {
             $this->finish();
         }
-- 
1.7.9.5


From 225e058685ffb009e5b43ebe83c92d392fe1d5ff Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 7 Jun 2012 16:40:58 +0100
Subject: [PATCH 005/903] MDL-30883 question flags: aria attributes for
 accessibility

Also, update code to use html_writer, and fix pointer style when not
editable.
---
 question/engine/renderer.php  |   50 +++++++++++++++++++++++++++--------------
 theme/base/style/question.css |    2 +-
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/question/engine/renderer.php b/question/engine/renderer.php
index 006729a..dbb1ddd 100644
--- a/question/engine/renderer.php
+++ b/question/engine/renderer.php
@@ -207,36 +207,52 @@ class core_question_renderer extends plugin_renderer_base {
      */
     protected function question_flag(question_attempt $qa, $flagsoption) {
         global $CFG;
+
+        $divattributes = array('class' => 'questionflag');
+
         switch ($flagsoption) {
             case question_display_options::VISIBLE:
                 $flagcontent = $this->get_flag_html($qa->is_flagged());
                 break;
+
             case question_display_options::EDITABLE:
                 $id = $qa->get_flag_field_name();
-                if ($qa->is_flagged()) {
-                    $checked = 'checked="checked" ';
-                } else {
-                    $checked = '';
-                }
-                $postdata = question_flags::get_postdata($qa);
                 // The checkbox id must be different from any element name, because
                 // of a stupid IE bug:
                 // http://www.456bereastreet.com/archive/200802/beware_of_id_and_name_attribute_mixups_when_using_getelementbyid_in_internet_explorer/
-                $flagcontent = '<input type="hidden" name="' . $id . '" value="0" />' .
-                        '<input type="checkbox" id="' . $id . 'checkbox" name="' . $id .
-                                '" value="1" ' . $checked . ' />' .
-                        '<input type="hidden" value="' . s($postdata) .
-                                '" class="questionflagpostdata" />' .
-                        '<label id="' . $id . 'label" for="' . $id . 'checkbox">' .
-                                $this->get_flag_html($qa->is_flagged(), $id . 'img') .
-                                '</label>' . "\n";
+                $checkboxattributes = array(
+                    'type' => 'checkbox',
+                    'id' => $id . 'checkbox',
+                    'name' => $id,
+                    'value' => 1,
+                );
+                if ($qa->is_flagged()) {
+                    $checkboxattributes['checked'] = 'checked';
+                }
+                $postdata = question_flags::get_postdata($qa);
+
+                $flagcontent = html_writer::empty_tag('input',
+                                array('type' => 'hidden', 'name' => $id, 'value' => 0)) .
+                        html_writer::empty_tag('input', $checkboxattributes) .
+                        html_writer::empty_tag('input',
+                                array('type' => 'hidden', 'value' => $postdata, 'class' => 'questionflagpostdata')) .
+                        html_writer::tag('label', $this->get_flag_html($qa->is_flagged(), $id . 'img'),
+                                array('id' => $id . 'label', 'for' => $id . 'checkbox')) . "\n";
+
+                $divattributes = array(
+                    'class' => 'questionflag editable',
+                    'aria-atomic' => 'true',
+                    'aria-relevant' => 'text',
+                    'aria-live' => 'assertive',
+                );
+
                 break;
+
             default:
                 $flagcontent = '';
         }
-        if ($flagcontent) {
-            return '<div class="questionflag">' . $flagcontent . "</div>\n";
-        }
+
+        return html_writer::nonempty_tag('div', $flagcontent, $divattributes);
     }
 
     /**
diff --git a/theme/base/style/question.css b/theme/base/style/question.css
index 33cedb4..3d4a13c 100644
--- a/theme/base/style/question.css
+++ b/theme/base/style/question.css
@@ -46,7 +46,7 @@ body.jsenabled #qtypechoicecontainer {display: block;}
 .que h2.no {margin: 0;font-size: 0.8em;line-height: 1;}
 .que span.qno {font-size: 1.5em;font-weight:bold;}
 .que .info > div {font-size: 0.8em;margin-top: 0.7em;}
-.que .info .questionflag {cursor:pointer;}
+.que .info .questionflag.editable {cursor:pointer;}
 .que .info .editquestion img,
 .que .info .questionflag img,
 .que .info .questionflag input {vertical-align: bottom;}
-- 
1.7.9.5


From 5af6c9676ebd86e390ef71089b210b6ad4dc3de3 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 18 Jun 2012 13:21:40 +0100
Subject: [PATCH 006/903] MDL-33780 question import: strip UTF8 BOM

Previously, if there was a byte-order mark at the start of the file, the
import would just break, which was silly. Much better to just strip it
off.
---
 question/format.php |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/question/format.php b/question/format.php
index 2e3e3e2..0ccdbce 100644
--- a/question/format.php
+++ b/question/format.php
@@ -539,7 +539,10 @@ class qformat_default {
         if (is_readable($filename)) {
             $filearray = file($filename);
 
-            /// Check for Macintosh OS line returns (ie file on one line), and fix
+            // If the first line of the file starts with a UTF-8 BOM, remove it.
+            $filearray[0] = textlib::trim_utf8_bom($filearray[0]);
+
+            // Check for Macintosh OS line returns (ie file on one line), and fix.
             if (preg_match("~\r~", $filearray[0]) AND !preg_match("~\n~", $filearray[0])) {
                 return explode("\r", $filearray[0]);
             } else {
-- 
1.7.9.5


From b0cf55f1453d3d06a62afca0a944a5f955641baa Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 25 Jun 2012 15:15:20 +0100
Subject: [PATCH 007/903] MDL-34008 formslib: repeat_elements replace {no} for
 submits & buttons

---
 lib/formslib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/formslib.php b/lib/formslib.php
index ac28eb8..306c4e5 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -944,6 +944,9 @@ abstract class moodleform {
             $value = $elementclone->_text;
             $elementclone->setValue(str_replace('{no}', ($i+1), $value));
 
+        } else if (is_a($elementclone, 'HTML_QuickForm_submit') || is_a($elementclone, 'HTML_QuickForm_button')) {
+            $elementclone->setValue(str_replace('{no}', ($i+1), $elementclone->getValue()));
+
         } else {
             $value=$elementclone->getLabel();
             $elementclone->setLabel(str_replace('{no}', ($i+1), $value));
-- 
1.7.9.5


From d81d6ea2c3e792e32f59c6fb4a28cd608e03903e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Fri, 22 Jun 2012 15:22:27 +0200
Subject: [PATCH 008/903] MDL-33453 Make it clear what search_references() and
 search_references_count() are good for

Initially it was not clear enough that these two methods are supposed to
be used for looking for references to a stored_file only. So the docs
comments are improved and unittests added to illustrate the usage.

The patch also removes the unittest for get_references_by_storedfile()
as its usage is already covered in other test methods.
---
 lib/filestorage/file_storage.php            |   27 ++++++++-
 lib/filestorage/tests/file_storage_test.php |   84 +++++++++++++++++++++------
 2 files changed, 91 insertions(+), 20 deletions(-)

diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index 933c5c3..2b248d1 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -1656,6 +1656,7 @@ class file_storage {
      *
      * @param string $str
      * @param bool $cleanparams if set to true, array elements will be passed through {@link clean_param()}
+     * @throws file_reference_exception if the $str does not have the expected format
      * @return array
      */
     public static function unpack_reference($str, $cleanparams = false) {
@@ -1681,7 +1682,13 @@ class file_storage {
     }
 
     /**
-     * Returns all aliases that link to an external file identified by the given reference
+     * Returns all aliases that refer to some stored_file via the given reference
+     *
+     * All repositories that provide access to a stored_file are expected to use
+     * {@link self::pack_reference()}. This method can't be used if the given reference
+     * does not use this format or if you are looking for references to an external file
+     * (for example it can't be used to search for all aliases that refer to a given
+     * Dropbox or Box.net file).
      *
      * Aliases in user draft areas are excluded from the returned list.
      *
@@ -1695,6 +1702,10 @@ class file_storage {
             throw new coding_exception('NULL is not a valid reference to an external file');
         }
 
+        // Give {@link self::unpack_reference()} a chance to throw exception if the
+        // reference is not in a valid format.
+        self::unpack_reference($reference);
+
         $referencehash = sha1($reference);
 
         $sql = "SELECT ".self::instance_sql_fields('f', 'r')."
@@ -1714,7 +1725,13 @@ class file_storage {
     }
 
     /**
-     * Returns the number of aliases that link to an external file identified by the given reference
+     * Returns the number of aliases that refer to some stored_file via the given reference
+     *
+     * All repositories that provide access to a stored_file are expected to use
+     * {@link self::pack_reference()}. This method can't be used if the given reference
+     * does not use this format or if you are looking for references to an external file
+     * (for example it can't be used to count aliases that refer to a given Dropbox or
+     * Box.net file).
      *
      * Aliases in user draft areas are not counted.
      *
@@ -1728,6 +1745,10 @@ class file_storage {
             throw new coding_exception('NULL is not a valid reference to an external file');
         }
 
+        // Give {@link self::unpack_reference()} a chance to throw exception if the
+        // reference is not in a valid format.
+        self::unpack_reference($reference);
+
         $referencehash = sha1($reference);
 
         $sql = "SELECT COUNT(f.id)
@@ -1737,7 +1758,7 @@ class file_storage {
                  WHERE r.referencehash = ?
                        AND (f.component <> ? OR f.filearea <> ?)";
 
-        return $DB->count_records_sql($sql, array($referencehash, 'user', 'draft'));
+        return (int)$DB->count_records_sql($sql, array($referencehash, 'user', 'draft'));
     }
 
     /**
diff --git a/lib/filestorage/tests/file_storage_test.php b/lib/filestorage/tests/file_storage_test.php
index d787bba..dfc4fa0 100644
--- a/lib/filestorage/tests/file_storage_test.php
+++ b/lib/filestorage/tests/file_storage_test.php
@@ -400,16 +400,6 @@ class filestoragelib_testcase extends advanced_testcase {
         $this->assertFalse($doesntexist);
     }
 
-    public function test_get_references_by_storedfile() {
-        $user = $this->setup_three_private_files();
-        $fs = get_file_storage();
-
-        $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
-        $testfile = reset($areafiles);
-        $references = $fs->get_references_by_storedfile($testfile);
-        // TODO MDL-33368 Verify result!!
-    }
-
     public function test_get_external_files() {
         $user = $this->setup_three_private_files();
         $fs = get_file_storage();
@@ -583,15 +573,75 @@ class filestoragelib_testcase extends advanced_testcase {
     }
 
     public function test_search_references() {
+        $user = $this->setup_three_private_files();
         $fs = get_file_storage();
-        $references = $fs->search_references('testsearch');
-        // TODO MDL-33368 Verify result!!
-    }
+        $repos = repository::get_instances(array('type'=>'user'));
+        $repo = reset($repos);
 
-    public function test_search_references_count() {
-        $fs = get_file_storage();
-        $references = $fs->search_references_count('testsearch');
-        // TODO MDL-33368 Verify result!!
+        $alias1 = array(
+            'contextid' => $user->ctxid,
+            'component' => 'user',
+            'filearea'  => 'private',
+            'itemid'    => 0,
+            'filepath'  => '/aliases/',
+            'filename'  => 'alias-to-1.txt'
+        );
+
+        $alias2 = array(
+            'contextid' => $user->ctxid,
+            'component' => 'user',
+            'filearea'  => 'private',
+            'itemid'    => 0,
+            'filepath'  => '/aliases/',
+            'filename'  => 'another-alias-to-1.txt'
+        );
+
+        $reference = file_storage::pack_reference(array(
+            'contextid' => $user->ctxid,
+            'component' => 'user',
+            'filearea'  => 'private',
+            'itemid'    => 0,
+            'filepath'  => '/',
+            'filename'  => '1.txt'
+        ));
+
+        // There are no aliases now.
+        $result = $fs->search_references($reference);
+        $this->assertEquals(array(), $result);
+
+        $result = $fs->search_references_count($reference);
+        $this->assertSame($result, 0);
+
+        // Create two aliases and make sure they are returned.
+        $fs->create_file_from_reference($alias1, $repo->id, $reference);
+        $fs->create_file_from_reference($alias2, $repo->id, $reference);
+
+        $result = $fs->search_references($reference);
+        $this->assertTrue(is_array($result));
+        $this->assertEquals(count($result), 2);
+        foreach ($result as $alias) {
+            $this->assertTrue($alias instanceof stored_file);
+        }
+
+        $result = $fs->search_references_count($reference);
+        $this->assertSame($result, 2);
+
+        // The method can't be used for references to files outside the filepool
+        $exceptionthrown = false;
+        try {
+            $fs->search_references('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
+        } catch (file_reference_exception $e) {
+            $exceptionthrown = true;
+        }
+        $this->assertTrue($exceptionthrown);
+
+        $exceptionthrown = false;
+        try {
+            $fs->search_references_count('http://dl.dropbox.com/download/1234567/naked-dougiamas.jpg');
+        } catch (file_reference_exception $e) {
+            $exceptionthrown = true;
+        }
+        $this->assertTrue($exceptionthrown);
     }
 
     public function test_delete_area_files() {
-- 
1.7.9.5


From 2670a3a6849b552479469043fec3d5a0e9c9e22f Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Wed, 27 Jun 2012 10:38:24 +1200
Subject: [PATCH 009/903] MDL-34044 completion: Fix regression caused by
 MDL-26626

---
 blocks/completionstatus/block_completionstatus.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/completionstatus/block_completionstatus.php b/blocks/completionstatus/block_completionstatus.php
index 07a7b47..0daec7c 100644
--- a/blocks/completionstatus/block_completionstatus.php
+++ b/blocks/completionstatus/block_completionstatus.php
@@ -171,7 +171,7 @@ class block_completionstatus extends block_base {
             $a = new stdClass();
             $a->first = $prerequisites_complete;
             $a->second = count($prerequisites);
-            $shtml .= get_string('firstofsecond', 'block_completionstatus', $a);
+            $phtml .= get_string('firstofsecond', 'block_completionstatus', $a);
             $phtml .= '</td></tr>';
 
             $shtml = $phtml . $shtml;
-- 
1.7.9.5


From fc14c79fc9815aff333221f670da51b1d07ed5ef Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 30 Apr 2012 11:12:20 +0800
Subject: [PATCH 010/903] MDL-32605 calendar: Fixing the missing parameter for
 get_string call

---
 calendar/delete.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/calendar/delete.php b/calendar/delete.php
index 24edd48..e79e945 100644
--- a/calendar/delete.php
+++ b/calendar/delete.php
@@ -108,7 +108,7 @@ $repeatspan = '';
 if (!empty($event->eventrepeats) && $event->eventrepeats > 0) {
     $url = new moodle_url(CALENDAR_URL.'delete.php', array('id'=>$event->repeatid, 'confirm'=>true, 'repeats'=>true));
     $buttons .= $OUTPUT->single_button($url, get_string('deleteall'));
-    $repeatspan = '<br /><br /><span>'.get_string('youcandeleteallrepeats', 'calendar').'</span>';
+    $repeatspan = '<br /><br /><span>'.get_string('youcandeleteallrepeats', 'calendar', $event->eventrepeats).'</span>';
 }
 
 // And add the cancel button
-- 
1.7.9.5


From faca7084844ff3b73c44fe81c3e2e7da9ed8388b Mon Sep 17 00:00:00 2001
From: Mark Nelson <mark@moodle.com.au>
Date: Wed, 27 Jun 2012 14:31:03 +0800
Subject: [PATCH 011/903] MDL-34025 - quiz secure window: fix popup closing

---
 mod/quiz/accessmanager.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/accessmanager.php b/mod/quiz/accessmanager.php
index 9c0f148..11efebd 100644
--- a/mod/quiz/accessmanager.php
+++ b/mod/quiz/accessmanager.php
@@ -445,7 +445,7 @@ class quiz_access_manager {
      */
     public function back_to_view_page($output, $message = '') {
         if ($this->attempt_must_be_in_popup()) {
-            echo $output->close_attempt_popup($message, $this->quizobj->view_url());
+            echo $output->close_attempt_popup($this->quizobj->view_url(), $message);
             die();
         } else {
             redirect($this->quizobj->view_url(), $message);
-- 
1.7.9.5


From e5ff0d32785690bf243668a35fd2c05b3ef7b6ab Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 20 Jun 2012 23:38:05 +0100
Subject: [PATCH 012/903] MDL-33924 quiz: incorrect foreign key definition.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Thanks to Jean-Michel Vedrine for spotting this.≈
---
 mod/quiz/db/install.xml |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/db/install.xml b/mod/quiz/db/install.xml
index 0c15b60..fd12420 100644
--- a/mod/quiz/db/install.xml
+++ b/mod/quiz/db/install.xml
@@ -74,7 +74,7 @@
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="quiz"/>
         <KEY NAME="quiz" TYPE="foreign" FIELDS="quiz" REFTABLE="quiz" REFFIELDS="id" PREVIOUS="primary" NEXT="userid"/>
         <KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id" PREVIOUS="quiz" NEXT="uniqueid"/>
-        <KEY NAME="uniqueid" TYPE="foreign-unique" FIELDS="uniqueid" REFTABLE="question_attempts" REFFIELDS="id" PREVIOUS="userid"/>
+        <KEY NAME="uniqueid" TYPE="foreign-unique" FIELDS="uniqueid" REFTABLE="question_usages" REFFIELDS="id" PREVIOUS="userid"/>
       </KEYS>
       <INDEXES>
         <INDEX NAME="quiz-userid-attempt" UNIQUE="true" FIELDS="quiz, userid, attempt"/>
-- 
1.7.9.5


From a44c303d636badaedbcbd6999c0dae07d4c6c97f Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Tue, 28 Feb 2012 16:28:11 +1030
Subject: [PATCH 013/903] MDL-31802: Remove section summaries from
 navigation_cache

---
 lib/navigationlib.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 58629dd..41e5d2a 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -1924,6 +1924,8 @@ class global_navigation extends navigation_node {
         $activities = array();
 
         foreach ($sections as $key => $section) {
+            $sections[$key] = clone($section);
+            unset($sections[$key]->summary);
             $sections[$key]->hasactivites = false;
             if (!array_key_exists($section->section, $modinfo->sections)) {
                 continue;
-- 
1.7.9.5


From 37817a0cd88cebc47917d507e7017addd92ff500 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 28 Jun 2012 12:11:18 +0800
Subject: [PATCH 014/903] MDL-34077 Repositories: Flickr and Picasa can have
 custom names

---
 repository/flickr/lib.php |    2 ++
 repository/picasa/lib.php |    3 ---
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/repository/flickr/lib.php b/repository/flickr/lib.php
index 6886638..b1c5463 100644
--- a/repository/flickr/lib.php
+++ b/repository/flickr/lib.php
@@ -277,6 +277,8 @@ class repository_flickr extends repository {
             $secret = '';
         }
 
+        parent::type_config_form($mform);
+
         $strrequired = get_string('required');
         $mform->addElement('text', 'api_key', get_string('apikey', 'repository_flickr'), array('value'=>$api_key,'size' => '40'));
         $mform->addElement('text', 'secret', get_string('secret', 'repository_flickr'), array('value'=>$secret,'size' => '40'));
diff --git a/repository/picasa/lib.php b/repository/picasa/lib.php
index 7dbdf7b..642c7b3 100644
--- a/repository/picasa/lib.php
+++ b/repository/picasa/lib.php
@@ -98,9 +98,6 @@ class repository_picasa extends repository {
         return parent::logout();
     }
 
-    public function get_name() {
-        return get_string('pluginname', 'repository_picasa');
-    }
     public function supported_filetypes() {
         return array('web_image');
     }
-- 
1.7.9.5


From b574c078a6fd0e61826b15415ee8f73a3cb9c73a Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Fri, 29 Jun 2012 11:37:01 +0800
Subject: [PATCH 015/903] MDL-34096 Installation : Added 2.3 upgrade line to
 db upgrade scripts.

---
 admin/tool/customlang/db/upgrade.php            |    4 ++++
 auth/manual/db/upgrade.php                      |    4 ++++
 auth/mnet/db/upgrade.php                        |    4 ++++
 blocks/community/db/upgrade.php                 |    4 ++++
 blocks/html/db/upgrade.php                      |    4 ++++
 blocks/navigation/db/upgrade.php                |    4 ++++
 blocks/settings/db/upgrade.php                  |    4 ++++
 enrol/authorize/db/upgrade.php                  |    4 ++++
 enrol/database/db/upgrade.php                   |    4 ++++
 enrol/flatfile/db/upgrade.php                   |    4 ++++
 enrol/guest/db/upgrade.php                      |    4 ++++
 enrol/imsenterprise/db/upgrade.php              |    4 ++++
 enrol/mnet/db/upgrade.php                       |    4 ++++
 enrol/paypal/db/upgrade.php                     |    4 ++++
 filter/mediaplugin/db/upgrade.php               |    4 ++++
 filter/tex/db/upgrade.php                       |    4 ++++
 grade/grading/form/rubric/db/upgrade.php        |    4 ++++
 lib/db/upgrade.php                              |    4 ++++
 message/output/email/db/upgrade.php             |    4 ++++
 message/output/jabber/db/upgrade.php            |    4 ++++
 message/output/popup/db/upgrade.php             |    4 ++++
 mod/assign/db/upgrade.php                       |    4 ++++
 mod/assign/feedback/comments/db/upgrade.php     |    4 ++++
 mod/assign/feedback/file/db/upgrade.php         |    4 ++++
 mod/assign/submission/comments/db/upgrade.php   |    4 ++++
 mod/assign/submission/file/db/upgrade.php       |    4 ++++
 mod/assign/submission/onlinetext/db/upgrade.php |    4 ++++
 mod/assignment/db/upgrade.php                   |    4 ++++
 mod/book/db/upgrade.php                         |    4 ++++
 mod/chat/db/upgrade.php                         |    4 ++++
 mod/choice/db/upgrade.php                       |    4 ++++
 mod/data/db/upgrade.php                         |    4 ++++
 mod/feedback/db/upgrade.php                     |    4 ++++
 mod/folder/db/upgrade.php                       |    4 ++++
 mod/forum/db/upgrade.php                        |    4 ++++
 mod/glossary/db/upgrade.php                     |    4 ++++
 mod/imscp/db/upgrade.php                        |    4 ++++
 mod/label/db/upgrade.php                        |    4 ++++
 mod/lesson/db/upgrade.php                       |    4 ++++
 mod/lti/db/upgrade.php                          |    4 ++++
 mod/page/db/upgrade.php                         |    4 ++++
 mod/quiz/db/upgrade.php                         |    4 ++++
 mod/quiz/report/overview/db/upgrade.php         |    4 ++++
 mod/quiz/report/statistics/db/upgrade.php       |    4 ++++
 mod/resource/db/upgrade.php                     |    4 ++++
 mod/scorm/db/upgrade.php                        |    4 ++++
 mod/survey/db/upgrade.php                       |    4 ++++
 mod/url/db/upgrade.php                          |    4 ++++
 mod/wiki/db/upgrade.php                         |    4 ++++
 mod/workshop/db/upgrade.php                     |    4 ++++
 mod/workshop/form/accumulative/db/upgrade.php   |    4 ++++
 mod/workshop/form/comments/db/upgrade.php       |    4 ++++
 mod/workshop/form/numerrors/db/upgrade.php      |    4 ++++
 mod/workshop/form/rubric/db/upgrade.php         |    4 ++++
 portfolio/googledocs/db/upgrade.php             |    4 ++++
 portfolio/picasa/db/upgrade.php                 |    4 ++++
 question/type/calculated/db/upgrade.php         |    4 ++++
 question/type/essay/db/upgrade.php              |    4 ++++
 question/type/match/db/upgrade.php              |    4 ++++
 question/type/multianswer/db/upgrade.php        |    4 ++++
 question/type/multichoice/db/upgrade.php        |    4 ++++
 question/type/numerical/db/upgrade.php          |    4 ++++
 repository/googledocs/db/upgrade.php            |    4 ++++
 repository/picasa/db/upgrade.php                |    4 ++++
 theme/formal_white/db/upgrade.php               |    4 ++++
 65 files changed, 260 insertions(+)

diff --git a/admin/tool/customlang/db/upgrade.php b/admin/tool/customlang/db/upgrade.php
index efe645e..07c7e3b 100644
--- a/admin/tool/customlang/db/upgrade.php
+++ b/admin/tool/customlang/db/upgrade.php
@@ -30,5 +30,9 @@ function xmldb_tool_customlang_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/auth/manual/db/upgrade.php b/auth/manual/db/upgrade.php
index 82aab0a..46fd720 100644
--- a/auth/manual/db/upgrade.php
+++ b/auth/manual/db/upgrade.php
@@ -33,5 +33,9 @@ function xmldb_auth_manual_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/auth/mnet/db/upgrade.php b/auth/mnet/db/upgrade.php
index fa5d157..d10cda5 100644
--- a/auth/mnet/db/upgrade.php
+++ b/auth/mnet/db/upgrade.php
@@ -34,5 +34,9 @@ function xmldb_auth_mnet_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/blocks/community/db/upgrade.php b/blocks/community/db/upgrade.php
index e3eb9a4..53e2222 100644
--- a/blocks/community/db/upgrade.php
+++ b/blocks/community/db/upgrade.php
@@ -46,5 +46,9 @@
 function xmldb_block_community_upgrade($oldversion) {
     global $CFG, $DB;
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/blocks/html/db/upgrade.php b/blocks/html/db/upgrade.php
index 8eec672..54bb53d 100644
--- a/blocks/html/db/upgrade.php
+++ b/blocks/html/db/upgrade.php
@@ -32,5 +32,9 @@
 function xmldb_block_html_upgrade($oldversion) {
     global $CFG, $DB;
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/blocks/navigation/db/upgrade.php b/blocks/navigation/db/upgrade.php
index 4ad9818..32c5d8d 100644
--- a/blocks/navigation/db/upgrade.php
+++ b/blocks/navigation/db/upgrade.php
@@ -58,5 +58,9 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
\ No newline at end of file
diff --git a/blocks/settings/db/upgrade.php b/blocks/settings/db/upgrade.php
index 65c265c..feb241a 100644
--- a/blocks/settings/db/upgrade.php
+++ b/blocks/settings/db/upgrade.php
@@ -58,5 +58,9 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
\ No newline at end of file
diff --git a/enrol/authorize/db/upgrade.php b/enrol/authorize/db/upgrade.php
index 9a11f48..ad71ff7 100644
--- a/enrol/authorize/db/upgrade.php
+++ b/enrol/authorize/db/upgrade.php
@@ -26,5 +26,9 @@ function xmldb_enrol_authorize_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/enrol/database/db/upgrade.php b/enrol/database/db/upgrade.php
index c21880c..7aae081 100644
--- a/enrol/database/db/upgrade.php
+++ b/enrol/database/db/upgrade.php
@@ -30,5 +30,9 @@ function xmldb_enrol_database_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/enrol/flatfile/db/upgrade.php b/enrol/flatfile/db/upgrade.php
index b8e4a73..67785c2 100644
--- a/enrol/flatfile/db/upgrade.php
+++ b/enrol/flatfile/db/upgrade.php
@@ -32,5 +32,9 @@ function xmldb_enrol_flatfile_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/enrol/guest/db/upgrade.php b/enrol/guest/db/upgrade.php
index b19b5a6..b14e8f8 100644
--- a/enrol/guest/db/upgrade.php
+++ b/enrol/guest/db/upgrade.php
@@ -40,6 +40,10 @@ function xmldb_enrol_guest_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2011112901, 'enrol', 'guest');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/enrol/imsenterprise/db/upgrade.php b/enrol/imsenterprise/db/upgrade.php
index a348d69..39b8fdc 100644
--- a/enrol/imsenterprise/db/upgrade.php
+++ b/enrol/imsenterprise/db/upgrade.php
@@ -31,6 +31,10 @@ function xmldb_enrol_imsenterprise_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/enrol/mnet/db/upgrade.php b/enrol/mnet/db/upgrade.php
index 6564435..8c70236 100644
--- a/enrol/mnet/db/upgrade.php
+++ b/enrol/mnet/db/upgrade.php
@@ -32,5 +32,9 @@ function xmldb_enrol_mnet_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/enrol/paypal/db/upgrade.php b/enrol/paypal/db/upgrade.php
index b66c655..8bcb41f 100644
--- a/enrol/paypal/db/upgrade.php
+++ b/enrol/paypal/db/upgrade.php
@@ -47,5 +47,9 @@ function xmldb_enrol_paypal_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/filter/mediaplugin/db/upgrade.php b/filter/mediaplugin/db/upgrade.php
index c77415f..a9c7964 100644
--- a/filter/mediaplugin/db/upgrade.php
+++ b/filter/mediaplugin/db/upgrade.php
@@ -54,5 +54,9 @@ function xmldb_filter_mediaplugin_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2011121200, 'filter', 'mediaplugin');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/filter/tex/db/upgrade.php b/filter/tex/db/upgrade.php
index fea5c3d..74b0ef5 100644
--- a/filter/tex/db/upgrade.php
+++ b/filter/tex/db/upgrade.php
@@ -33,5 +33,9 @@ function xmldb_filter_tex_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/grade/grading/form/rubric/db/upgrade.php b/grade/grading/form/rubric/db/upgrade.php
index e60160d..7c1d214 100644
--- a/grade/grading/form/rubric/db/upgrade.php
+++ b/grade/grading/form/rubric/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_gradingform_rubric_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 3be8b80..dd52946 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -872,5 +872,9 @@ function xmldb_main_upgrade($oldversion) {
     }
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/message/output/email/db/upgrade.php b/message/output/email/db/upgrade.php
index dd79b5c..da3d22a 100644
--- a/message/output/email/db/upgrade.php
+++ b/message/output/email/db/upgrade.php
@@ -36,6 +36,10 @@ function xmldb_message_email_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/message/output/jabber/db/upgrade.php b/message/output/jabber/db/upgrade.php
index d884f25..eb78904 100644
--- a/message/output/jabber/db/upgrade.php
+++ b/message/output/jabber/db/upgrade.php
@@ -36,6 +36,10 @@ function xmldb_message_jabber_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/message/output/popup/db/upgrade.php b/message/output/popup/db/upgrade.php
index 63a4f73..ef556ee 100644
--- a/message/output/popup/db/upgrade.php
+++ b/message/output/popup/db/upgrade.php
@@ -36,6 +36,10 @@ function xmldb_message_popup_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/db/upgrade.php b/mod/assign/db/upgrade.php
index e918367..de7a154 100644
--- a/mod/assign/db/upgrade.php
+++ b/mod/assign/db/upgrade.php
@@ -47,6 +47,10 @@ function xmldb_assign_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012051700, 'assign');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/feedback/comments/db/upgrade.php b/mod/assign/feedback/comments/db/upgrade.php
index 9321ecc..97409c6 100644
--- a/mod/assign/feedback/comments/db/upgrade.php
+++ b/mod/assign/feedback/comments/db/upgrade.php
@@ -29,6 +29,10 @@
  */
 function xmldb_assignfeedback_comments_upgrade($oldversion) {
     // do the upgrades
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/feedback/file/db/upgrade.php b/mod/assign/feedback/file/db/upgrade.php
index cf6594e..e59722d 100644
--- a/mod/assign/feedback/file/db/upgrade.php
+++ b/mod/assign/feedback/file/db/upgrade.php
@@ -29,6 +29,10 @@
  */
 function xmldb_assignfeedback_file_upgrade($oldversion) {
     // do the upgrades
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/submission/comments/db/upgrade.php b/mod/assign/submission/comments/db/upgrade.php
index 6bc5bce..565fc0f 100644
--- a/mod/assign/submission/comments/db/upgrade.php
+++ b/mod/assign/submission/comments/db/upgrade.php
@@ -28,6 +28,10 @@
  * @return bool
  */
 function xmldb_assignsubmission_comments_upgrade($oldversion) {
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/submission/file/db/upgrade.php b/mod/assign/submission/file/db/upgrade.php
index b00f57b..a86a5fb 100644
--- a/mod/assign/submission/file/db/upgrade.php
+++ b/mod/assign/submission/file/db/upgrade.php
@@ -28,6 +28,10 @@
  * @return bool
  */
 function xmldb_assignsubmission_file_upgrade($oldversion) {
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assign/submission/onlinetext/db/upgrade.php b/mod/assign/submission/onlinetext/db/upgrade.php
index 183e602..056c0bb 100644
--- a/mod/assign/submission/onlinetext/db/upgrade.php
+++ b/mod/assign/submission/onlinetext/db/upgrade.php
@@ -28,6 +28,10 @@
  * @return bool
  */
 function xmldb_assignsubmission_onlinetext_upgrade($oldversion) {
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/assignment/db/upgrade.php b/mod/assignment/db/upgrade.php
index 6608b6c..d9c46ea 100644
--- a/mod/assignment/db/upgrade.php
+++ b/mod/assignment/db/upgrade.php
@@ -29,6 +29,10 @@ function xmldb_assignment_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/book/db/upgrade.php b/mod/book/db/upgrade.php
index 735116c..3fb1085 100644
--- a/mod/book/db/upgrade.php
+++ b/mod/book/db/upgrade.php
@@ -37,5 +37,9 @@ function xmldb_book_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/chat/db/upgrade.php b/mod/chat/db/upgrade.php
index 2b9ad1d..c716494 100644
--- a/mod/chat/db/upgrade.php
+++ b/mod/chat/db/upgrade.php
@@ -29,6 +29,10 @@ function xmldb_chat_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/choice/db/upgrade.php b/mod/choice/db/upgrade.php
index f86bbe4..e46ab79 100644
--- a/mod/choice/db/upgrade.php
+++ b/mod/choice/db/upgrade.php
@@ -29,6 +29,10 @@ function xmldb_choice_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/data/db/upgrade.php b/mod/data/db/upgrade.php
index a84c883..745d0cb 100644
--- a/mod/data/db/upgrade.php
+++ b/mod/data/db/upgrade.php
@@ -29,6 +29,10 @@ function xmldb_data_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/feedback/db/upgrade.php b/mod/feedback/db/upgrade.php
index c4ededd..fd0d9a5 100644
--- a/mod/feedback/db/upgrade.php
+++ b/mod/feedback/db/upgrade.php
@@ -43,6 +43,10 @@ function xmldb_feedback_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/folder/db/upgrade.php b/mod/folder/db/upgrade.php
index 7a2b6e2..d996b61 100644
--- a/mod/folder/db/upgrade.php
+++ b/mod/folder/db/upgrade.php
@@ -55,5 +55,9 @@ function xmldb_folder_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/forum/db/upgrade.php b/mod/forum/db/upgrade.php
index d493b2b..4c2f297 100644
--- a/mod/forum/db/upgrade.php
+++ b/mod/forum/db/upgrade.php
@@ -50,6 +50,10 @@ function xmldb_forum_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/glossary/db/upgrade.php b/mod/glossary/db/upgrade.php
index ccebcd2..48e85b8 100644
--- a/mod/glossary/db/upgrade.php
+++ b/mod/glossary/db/upgrade.php
@@ -44,6 +44,10 @@ function xmldb_glossary_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012022000, 'glossary');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/imscp/db/upgrade.php b/mod/imscp/db/upgrade.php
index 2b027f7..e4c4b0a 100644
--- a/mod/imscp/db/upgrade.php
+++ b/mod/imscp/db/upgrade.php
@@ -35,5 +35,9 @@ function xmldb_imscp_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/label/db/upgrade.php b/mod/label/db/upgrade.php
index 0511d0f..a083759 100644
--- a/mod/label/db/upgrade.php
+++ b/mod/label/db/upgrade.php
@@ -55,6 +55,10 @@ function xmldb_label_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/lesson/db/upgrade.php b/mod/lesson/db/upgrade.php
index 04b0b8f..0cc8e03 100644
--- a/mod/lesson/db/upgrade.php
+++ b/mod/lesson/db/upgrade.php
@@ -61,6 +61,10 @@ function xmldb_lesson_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/lti/db/upgrade.php b/mod/lti/db/upgrade.php
index 2b5f1bc..9fd4e13 100644
--- a/mod/lti/db/upgrade.php
+++ b/mod/lti/db/upgrade.php
@@ -68,6 +68,10 @@ function xmldb_lti_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/page/db/upgrade.php b/mod/page/db/upgrade.php
index 4a81df9..b1c4e91 100644
--- a/mod/page/db/upgrade.php
+++ b/mod/page/db/upgrade.php
@@ -55,5 +55,9 @@ function xmldb_page_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/quiz/db/upgrade.php b/mod/quiz/db/upgrade.php
index d3a8e72..b0a4a4f 100644
--- a/mod/quiz/db/upgrade.php
+++ b/mod/quiz/db/upgrade.php
@@ -327,6 +327,10 @@ function xmldb_quiz_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012040206, 'quiz');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/quiz/report/overview/db/upgrade.php b/mod/quiz/report/overview/db/upgrade.php
index eefc978..f8aa7c8 100644
--- a/mod/quiz/report/overview/db/upgrade.php
+++ b/mod/quiz/report/overview/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_quiz_overview_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line.
     // Put any upgrade step following this.
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/quiz/report/statistics/db/upgrade.php b/mod/quiz/report/statistics/db/upgrade.php
index f3a7871..144d95a 100644
--- a/mod/quiz/report/statistics/db/upgrade.php
+++ b/mod/quiz/report/statistics/db/upgrade.php
@@ -63,6 +63,10 @@ function xmldb_quiz_statistics_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012061801, 'quiz', 'statistics');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/resource/db/upgrade.php b/mod/resource/db/upgrade.php
index fc6245e..383e888 100644
--- a/mod/resource/db/upgrade.php
+++ b/mod/resource/db/upgrade.php
@@ -55,5 +55,9 @@ function xmldb_resource_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/scorm/db/upgrade.php b/mod/scorm/db/upgrade.php
index a7bcbd7..a85397f 100644
--- a/mod/scorm/db/upgrade.php
+++ b/mod/scorm/db/upgrade.php
@@ -60,6 +60,10 @@ function xmldb_scorm_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012032101, 'scorm');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/survey/db/upgrade.php b/mod/survey/db/upgrade.php
index 3a10f28..10c6ef8 100644
--- a/mod/survey/db/upgrade.php
+++ b/mod/survey/db/upgrade.php
@@ -29,6 +29,10 @@ function xmldb_survey_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/mod/url/db/upgrade.php b/mod/url/db/upgrade.php
index 88e0ba0..5449ecb 100644
--- a/mod/url/db/upgrade.php
+++ b/mod/url/db/upgrade.php
@@ -55,5 +55,9 @@ function xmldb_url_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/wiki/db/upgrade.php b/mod/wiki/db/upgrade.php
index c8ac218..9925711 100644
--- a/mod/wiki/db/upgrade.php
+++ b/mod/wiki/db/upgrade.php
@@ -45,5 +45,9 @@ function xmldb_wiki_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/workshop/db/upgrade.php b/mod/workshop/db/upgrade.php
index 6f848b9..061d599 100644
--- a/mod/workshop/db/upgrade.php
+++ b/mod/workshop/db/upgrade.php
@@ -87,5 +87,9 @@ function xmldb_workshop_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012041701, 'workshop');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/workshop/form/accumulative/db/upgrade.php b/mod/workshop/form/accumulative/db/upgrade.php
index 5ff3a28..fd8065d 100644
--- a/mod/workshop/form/accumulative/db/upgrade.php
+++ b/mod/workshop/form/accumulative/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_workshopform_accumulative_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/workshop/form/comments/db/upgrade.php b/mod/workshop/form/comments/db/upgrade.php
index 07100d5..a369ae9 100644
--- a/mod/workshop/form/comments/db/upgrade.php
+++ b/mod/workshop/form/comments/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_workshopform_comments_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/workshop/form/numerrors/db/upgrade.php b/mod/workshop/form/numerrors/db/upgrade.php
index 3da3066..459abbb 100644
--- a/mod/workshop/form/numerrors/db/upgrade.php
+++ b/mod/workshop/form/numerrors/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_workshopform_numerrors_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/mod/workshop/form/rubric/db/upgrade.php b/mod/workshop/form/rubric/db/upgrade.php
index 62927bf..968f8e5 100644
--- a/mod/workshop/form/rubric/db/upgrade.php
+++ b/mod/workshop/form/rubric/db/upgrade.php
@@ -38,5 +38,9 @@ function xmldb_workshopform_rubric_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/portfolio/googledocs/db/upgrade.php b/portfolio/googledocs/db/upgrade.php
index 01420b5..39164bf 100644
--- a/portfolio/googledocs/db/upgrade.php
+++ b/portfolio/googledocs/db/upgrade.php
@@ -39,6 +39,10 @@ function xmldb_portfolio_googledocs_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012053001, 'portfolio', 'googledocs');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/portfolio/picasa/db/upgrade.php b/portfolio/picasa/db/upgrade.php
index 38df9d5..cb1eeb7 100644
--- a/portfolio/picasa/db/upgrade.php
+++ b/portfolio/picasa/db/upgrade.php
@@ -39,6 +39,10 @@ function xmldb_portfolio_picasa_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012053001, 'portfolio', 'picasa');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/question/type/calculated/db/upgrade.php b/question/type/calculated/db/upgrade.php
index f141e02..3d7bc0c 100644
--- a/question/type/calculated/db/upgrade.php
+++ b/question/type/calculated/db/upgrade.php
@@ -40,6 +40,10 @@ function xmldb_qtype_calculated_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/question/type/essay/db/upgrade.php b/question/type/essay/db/upgrade.php
index 6d60323..0441751 100644
--- a/question/type/essay/db/upgrade.php
+++ b/question/type/essay/db/upgrade.php
@@ -90,6 +90,10 @@ function xmldb_qtype_essay_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2011102702, 'qtype', 'essay');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/question/type/match/db/upgrade.php b/question/type/match/db/upgrade.php
index 6277068..b99732c 100644
--- a/question/type/match/db/upgrade.php
+++ b/question/type/match/db/upgrade.php
@@ -40,5 +40,9 @@ function xmldb_qtype_match_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/question/type/multianswer/db/upgrade.php b/question/type/multianswer/db/upgrade.php
index 8c7e04e..a83470f 100644
--- a/question/type/multianswer/db/upgrade.php
+++ b/question/type/multianswer/db/upgrade.php
@@ -40,5 +40,9 @@ function xmldb_qtype_multianswer_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/question/type/multichoice/db/upgrade.php b/question/type/multichoice/db/upgrade.php
index 41b56bf..48b658f 100644
--- a/question/type/multichoice/db/upgrade.php
+++ b/question/type/multichoice/db/upgrade.php
@@ -40,5 +40,9 @@ function xmldb_qtype_multichoice_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/question/type/numerical/db/upgrade.php b/question/type/numerical/db/upgrade.php
index 43db9a6..3336f4d 100644
--- a/question/type/numerical/db/upgrade.php
+++ b/question/type/numerical/db/upgrade.php
@@ -37,5 +37,9 @@ function xmldb_qtype_numerical_upgrade($oldversion) {
     $dbman = $DB->get_manager();
 
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
diff --git a/repository/googledocs/db/upgrade.php b/repository/googledocs/db/upgrade.php
index 80a77a6..7c78301 100644
--- a/repository/googledocs/db/upgrade.php
+++ b/repository/googledocs/db/upgrade.php
@@ -42,6 +42,10 @@ function xmldb_repository_googledocs_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012053000, 'repository', 'googledocs');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/repository/picasa/db/upgrade.php b/repository/picasa/db/upgrade.php
index 1cd2f2a..3d50bba 100644
--- a/repository/picasa/db/upgrade.php
+++ b/repository/picasa/db/upgrade.php
@@ -42,6 +42,10 @@ function xmldb_repository_picasa_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012053000, 'repository', 'picasa');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
 
diff --git a/theme/formal_white/db/upgrade.php b/theme/formal_white/db/upgrade.php
index aeb58d2..fccbb15 100644
--- a/theme/formal_white/db/upgrade.php
+++ b/theme/formal_white/db/upgrade.php
@@ -76,5 +76,9 @@ function xmldb_theme_formal_white_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2012051503, 'theme', 'formal_white');
     }
 
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
     return true;
 }
\ No newline at end of file
-- 
1.7.9.5


From 3e0b5f78a28ed9950e1dd968c192e605310e9aef Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Fri, 29 Jun 2012 14:17:56 +0800
Subject: [PATCH 016/903] MDL-32297 Forms: Date Picker JS popup is not
 constraint to parent form

---
 lib/form/yui/dateselector/dateselector.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/form/yui/dateselector/dateselector.js b/lib/form/yui/dateselector/dateselector.js
index 371e82f..d403547 100644
--- a/lib/form/yui/dateselector/dateselector.js
+++ b/lib/form/yui/dateselector/dateselector.js
@@ -222,7 +222,7 @@ YUI.add('moodle-form-dateselector', function(Y) {
         },
         fix_position : function() {
             if (this.currentowner) {
-                this.panel.set('constrain', this.currentowner.get('node').ancestor('form'));
+                this.panel.set('constrain', Y.one(document.body));
                 this.panel.set('align', {
                     node:this.currentowner.get('node').one('select'),
                     points:[Y.WidgetPositionAlign.BL, Y.WidgetPositionAlign.TL]
-- 
1.7.9.5


From 263e8c144cd6ce05abfddbf131b9fa0fbbdcace7 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sat, 30 Jun 2012 00:50:34 +0100
Subject: [PATCH 017/903] MDL-34119_M23 theme_splash: removed redundant js
 call in lib.php. Added lang option to config.php +
 amended lang output in layout files. Added some css
 to style langmenu + removed redundant loginicon in
 pagelayout.css

---
 theme/splash/config.php           |   36 +++++++++++++++++++++++-------------
 theme/splash/layout/general.php   |    8 ++++++--
 theme/splash/layout/report.php    |    8 ++++++--
 theme/splash/lib.php              |   11 -----------
 theme/splash/style/pagelayout.css |    3 +--
 5 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/theme/splash/config.php b/theme/splash/config.php
index f9bca28d..fbdedaf 100644
--- a/theme/splash/config.php
+++ b/theme/splash/config.php
@@ -33,10 +33,10 @@ $THEME->sheets = array(
     'pagelayout',
     'core',
     'menus',
-    'red',
-    'green',
-    'blue',
     'orange',
+    'blue',
+    'green',
+    'red',
     'settings',
 );
 
@@ -53,48 +53,57 @@ $THEME->layouts = array(
     'standard' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     // Course page
     'course' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     // Course page
     'coursecategory' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'incourse' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'frontpage' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'admin' => array(
         'file' => 'general.php',
         'regions' => array('side-pre'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'mydashboard' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'mypublic' => array(
         'file' => 'general.php',
         'regions' => array('side-pre', 'side-post'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
     'login' => array(
         'file' => 'general.php',
-        'regions' => array()
+        'regions' => array(),
+        'options' => array('langmenu'=>true),
     ),
     // Pages that appear in pop-up windows - no navigation, no blocks, no header.
     'popup' => array(
@@ -137,7 +146,8 @@ $THEME->layouts = array(
     'report' => array(
         'file' => 'report.php',
         'regions' => array('side-pre'),
-        'defaultregion' => 'side-pre'
+        'defaultregion' => 'side-pre',
+        'options' => array('langmenu'=>true),
     ),
 );
 
diff --git a/theme/splash/layout/general.php b/theme/splash/layout/general.php
index 4763983..0b94083 100644
--- a/theme/splash/layout/general.php
+++ b/theme/splash/layout/general.php
@@ -32,7 +32,6 @@ $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 splash_check_colourswitch();
-splash_initialise_colourswitcher($PAGE);
 
 $bodyclasses = array();
 $bodyclasses[] = 'splash-'.splash_get_colour();
@@ -107,7 +106,12 @@ echo $OUTPUT->doctype() ?>
         alt="orange" /></a></li>
         </ul>
         </div>
-        <?php echo $OUTPUT->lang_menu();?>
+        <?php
+        if (!empty($PAGE->layout_options['langmenu'])) {
+            echo $OUTPUT->lang_menu();
+        }
+            echo $PAGE->headingmenu
+        ?>
         </div>
         <div id="logobox">
         <?php
diff --git a/theme/splash/layout/report.php b/theme/splash/layout/report.php
index 2602e64..20a9775 100644
--- a/theme/splash/layout/report.php
+++ b/theme/splash/layout/report.php
@@ -32,7 +32,6 @@ $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 splash_check_colourswitch();
-splash_initialise_colourswitcher($PAGE);
 
 $bodyclasses = array();
 $bodyclasses[] = 'splash-'.splash_get_colour();
@@ -107,7 +106,12 @@ echo $OUTPUT->doctype() ?>
         alt="orange" /></a></li>
         </ul>
         </div>
-        <?php echo $OUTPUT->lang_menu();?>
+        <?php
+        if (!empty($PAGE->layout_options['langmenu'])) {
+            echo $OUTPUT->lang_menu();
+        }
+        echo $PAGE->headingmenu
+        ?>
         </div>
         <div id="logobox">
         <?php
diff --git a/theme/splash/lib.php b/theme/splash/lib.php
index 191ec32..5aeb7db 100644
--- a/theme/splash/lib.php
+++ b/theme/splash/lib.php
@@ -88,17 +88,6 @@ function splash_set_customcss($css, $customcss) {
 }
 
 /**
- * Adds the JavaScript for the colour switcher to the page.
- *
- * @param moodle_page $page
- */
-function splash_initialise_colourswitcher(moodle_page $page) {
-    user_preference_allow_ajax_update('theme_splash_chosen_colour', PARAM_ALPHA);
-    $page->requires->yui_module('moodle-theme_splash-colourswitcher',
-     'M.theme_splash.initColourSwitcher', array(array('div'=>'#colourswitcher')));
-}
-
-/**
  * Gets the colour the user has selected, or the default if they have never changed
  *
  * @param string $default The default colour to use, normally red
diff --git a/theme/splash/style/pagelayout.css b/theme/splash/style/pagelayout.css
index bfb4f6e..eca577c 100644
--- a/theme/splash/style/pagelayout.css
+++ b/theme/splash/style/pagelayout.css
@@ -199,7 +199,6 @@ p.prolog a:link {
     margin:10px 0 0 15px;
 }
 .logininfo{
-    background:url([[pix:theme|loginicon]]) left no-repeat;
     color:#fff;
     margin:0;
     padding:10px 10px 10px 40px;
@@ -213,7 +212,7 @@ p.prolog a:link {
 }
 #headermenu .langmenu{
     position:relative;
-    top:35px;
+    top:30px;
     width:210px;
 }
 a,
-- 
1.7.9.5


From f8e05deb354d062b373319cb4dda6b0d50f53062 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 07:50:38 +0200
Subject: [PATCH 018/903] MDL-34045 fix invalid idnumber field type in cohort
 form

---
 cohort/edit_form.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cohort/edit_form.php b/cohort/edit_form.php
index 249212c..d449980 100644
--- a/cohort/edit_form.php
+++ b/cohort/edit_form.php
@@ -49,7 +49,7 @@ class cohort_edit_form extends moodleform {
         $mform->addElement('select', 'contextid', get_string('context', 'role'), $options);
 
         $mform->addElement('text', 'idnumber', get_string('idnumber', 'cohort'), 'maxlength="254" size="50"');
-        $mform->setType('name', PARAM_RAW); // idnumbers are plain text, must not be changed
+        $mform->setType('idnumber', PARAM_RAW); // idnumbers are plain text, must not be changed
 
         $mform->addElement('editor', 'description_editor', get_string('description', 'cohort'), null, $editoroptions);
         $mform->setType('description_editor', PARAM_RAW);
-- 
1.7.9.5


From b273b20a7cff97b5a25a9f3c276e2def44e14441 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 08:09:56 +0200
Subject: [PATCH 019/903] MDL-34115 fix sorting in blocks admin UI

Comparison of arrays is not locale aware.
---
 admin/blocks.php           |   23 +++++++++++++++--------
 lib/tests/textlib_test.php |    6 ++++++
 lib/textlib.class.php      |    2 +-
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/admin/blocks.php b/admin/blocks.php
index b1c53df..34e8e4e 100644
--- a/admin/blocks.php
+++ b/admin/blocks.php
@@ -131,12 +131,25 @@
     $table->setup();
     $tablerows = array();
 
+    // Sort blocks using current locale.
+    $blocknames = array();
     foreach ($blocks as $blockid=>$block) {
         $blockname = $block->name;
+        if (file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
+            $blocknames[$blockid] = get_string('pluginname', 'block_'.$blockname);
+        } else {
+            $blocknames[$blockid] = $blockname;
+        }
+    }
+    collatorlib::asort($blocknames);
+
+    foreach ($blocknames as $blockid=>$strblockname) {
+        $block = $blocks[$blockid];
+        $blockname = $block->name;
 
         if (!file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
             $blockobject  = false;
-            $strblockname = '<span class="notifyproblem">'.$blockname.' ('.get_string('missingfromdisk').')</span>';
+            $strblockname = '<span class="notifyproblem">'.$strblockname.' ('.get_string('missingfromdisk').')</span>';
             $plugin = new stdClass();
             $plugin->version = $block->version;
 
@@ -151,7 +164,6 @@
                 $incompatible[] = $block;
                 continue;
             }
-            $strblockname = get_string('pluginname', 'block_'.$blockname);
         }
 
         $delete = '<a href="blocks.php?delete='.$blockid.'&amp;sesskey='.sesskey().'">'.$strdelete.'</a>';
@@ -222,12 +234,7 @@
             $delete,
             $settings
         );
-        $tablerows[] = array(strip_tags($strblockname), $row); // first element will be used for sorting
-    }
-
-    collatorlib::asort($tablerows);
-    foreach ($tablerows as $row) {
-        $table->add_data($row[1]);
+        $table->add_data($row);
     }
 
     $table->print_html();
diff --git a/lib/tests/textlib_test.php b/lib/tests/textlib_test.php
index 116f313..261cfdd 100644
--- a/lib/tests/textlib_test.php
+++ b/lib/tests/textlib_test.php
@@ -471,6 +471,12 @@ class collatorlib_testcase extends basic_testcase {
         $this->assertSame(array_keys($arr), array(0, 'b', 1));
         $this->assertTrue($result);
 
+        // test sorting of array of arrays - first element should be used for actual comparison
+        $arr = array(0=>array('bb', 'z'), 1=>array('ab', 'a'), 2=>array('zz', 'x'));
+        $result = collatorlib::asort($arr, collatorlib::SORT_REGULAR);
+        $this->assertSame(array_keys($arr), array(1, 0, 2));
+        $this->assertTrue($result);
+
         $arr = array('a' => 'áb', 'b' => 'ab', 1 => 'aa', 0=>'cc', 'x' => 'Áb',);
         $result = collatorlib::asort($arr);
         $this->assertSame(array_values($arr), array('aa', 'ab', 'áb', 'Áb', 'cc'), $this->error);
diff --git a/lib/textlib.class.php b/lib/textlib.class.php
index 540e4a4..77fafc1 100644
--- a/lib/textlib.class.php
+++ b/lib/textlib.class.php
@@ -616,7 +616,7 @@ class textlib {
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class collatorlib {
-    /** @const compare items as strings, equivalent to Collator::SORT_REGULAR */
+    /** @const compare items using general PHP comparison, equivalent to Collator::SORT_REGULAR, this may bot be locale aware! */
     const SORT_REGULAR = 0;
 
     /** @const compare items as strings, equivalent to Collator::SORT_STRING */
-- 
1.7.9.5


From 4aabce216c424461cf2bcccba270708eaef6fc23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 08:42:16 +0200
Subject: [PATCH 020/903] MDL-33876 skip deleted users in enrol_database sync

---
 enrol/database/lib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/enrol/database/lib.php b/enrol/database/lib.php
index d95acb2..1755a89 100644
--- a/enrol/database/lib.php
+++ b/enrol/database/lib.php
@@ -445,8 +445,9 @@ class enrol_database_plugin extends enrol_plugin {
             $sql = $this->db_get_sql($table, array($coursefield=>$course->mapping), $sqlfields);
             if ($rs = $extdb->Execute($sql)) {
                 if (!$rs->EOF) {
+                    $usersearch = array('deleted' => 0);
                     if ($localuserfield === 'username') {
-                        $usersearch = array('mnethostid'=>$CFG->mnet_localhost_id, 'deleted' =>0);
+                        $usersearch['mnethostid'] = $CFG->mnet_localhost_id;
                     }
                     while ($fields = $rs->FetchRow()) {
                         $fields = array_change_key_case($fields, CASE_LOWER);
-- 
1.7.9.5


From 5cb477c4a11d0fa24bc535abef4364f86fe9c1dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 08:55:39 +0200
Subject: [PATCH 021/903] MDL-34120 do not try to create new passwords for
 incorrectly deleted users

There is still some code that ignores delete_user() and instead hacks the user table directly, skip the borked user records for now when sending new passwords.
---
 lib/cronlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/cronlib.php b/lib/cronlib.php
index b034760..c51fef1 100644
--- a/lib/cronlib.php
+++ b/lib/cronlib.php
@@ -212,7 +212,7 @@ function cron_run() {
                                                  p.id as prefid
                                             FROM {user} u
                                             JOIN {user_preferences} p ON u.id=p.userid
-                                           WHERE p.name='create_password' AND p.value='1' AND u.email !='' AND u.suspended = 0 AND u.auth != 'nologin'");
+                                           WHERE p.name='create_password' AND p.value='1' AND u.email !='' AND u.suspended = 0 AND u.auth != 'nologin' AND u.deleted = 0");
 
         // note: we can not send emails to suspended accounts
         foreach ($newusers as $newuser) {
-- 
1.7.9.5


From 3705a88629ce209aef8bb2dfb62c870efafe8867 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sat, 30 Jun 2012 12:02:22 +0100
Subject: [PATCH 022/903] MDL-34119_M23 theme_splash: Added colourswitcher.js
 and associated code in layout files and lib.php

---
 theme/splash/config.php                   |    2 +
 theme/splash/javascript/colourswitcher.js |   63 +++++++++++++++++++++++++++++
 theme/splash/layout/general.php           |    1 +
 theme/splash/layout/report.php            |    1 +
 theme/splash/lib.php                      |   13 ++++++
 5 files changed, 80 insertions(+)
 create mode 100644 theme/splash/javascript/colourswitcher.js

diff --git a/theme/splash/config.php b/theme/splash/config.php
index fbdedaf..c428ce5 100644
--- a/theme/splash/config.php
+++ b/theme/splash/config.php
@@ -152,3 +152,5 @@ $THEME->layouts = array(
 );
 
 $THEME->csspostprocess = 'splash_process_css';
+
+$THEME->javascripts = array('colourswitcher');
diff --git a/theme/splash/javascript/colourswitcher.js b/theme/splash/javascript/colourswitcher.js
new file mode 100644
index 0000000..578f96b
--- /dev/null
+++ b/theme/splash/javascript/colourswitcher.js
@@ -0,0 +1,63 @@
+YUI.add('moodle-theme_splash-colourswitcher', function(Y) {
+
+// Available colours
+var COLOURS = ['red','green','blue','orange'];
+
+/**
+ * Splash theme colour switcher class.
+ * Initialise this class by calling M.theme_splash.init
+ */
+var ColourSwitcher = function() {
+    ColourSwitcher.superclass.constructor.apply(this, arguments);
+};
+ColourSwitcher.prototype = {
+    /**
+     * Constructor for this class
+     * @param {object} config
+     */
+    initializer : function(config) {
+        var i, c;
+        // Attach events to the links to change colours so we can do it with
+        // JavaScript without refreshing the page
+        for (i in COLOURS) {
+            c = COLOURS[i];
+            // Check if this is the current colour
+            if (Y.one(document.body).hasClass('splash-'+c)) {
+                this.set('colour', c);
+            }
+            Y.all(config.div+' .colour-'+c).on('click', this.setColour, this, c);
+        }
+    },
+    /**
+     * Sets the colour being used for the splash theme
+     * @param {Y.Event} e The event that fired
+     * @param {string} colour The new colour
+     */
+    setColour : function(e, colour) {
+        // Prevent the event from refreshing the page
+        e.preventDefault();
+        // Switch over the CSS classes on the body
+        Y.one(document.body).replaceClass('splash-'+this.get('colour'), 'splash-'+colour);
+        // Update the current colour
+        this.set('colour', colour);
+        // Store the users selection (Uses AJAX to save to the database)
+        M.util.set_user_preference('theme_splash_chosen_colour', colour);
+    }
+};
+// Make the colour switcher a fully fledged YUI module
+Y.extend(ColourSwitcher, Y.Base, ColourSwitcher.prototype, {
+    NAME : 'Splash theme colour switcher',
+    ATTRS : {
+        colour : {
+            value : 'red'
+        }
+    }
+});
+// Our splash theme namespace
+M.theme_splash = M.theme_splash || {};
+// Initialisation function for the colour switcher
+M.theme_splash.initColourSwitcher = function(cfg) {
+    return new ColourSwitcher(cfg);
+}
+
+}, '@VERSION@', {requires:['base','node']});
diff --git a/theme/splash/layout/general.php b/theme/splash/layout/general.php
index 0b94083..3def7ed 100644
--- a/theme/splash/layout/general.php
+++ b/theme/splash/layout/general.php
@@ -32,6 +32,7 @@ $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 splash_check_colourswitch();
+splash_initialise_colourswitcher($PAGE);
 
 $bodyclasses = array();
 $bodyclasses[] = 'splash-'.splash_get_colour();
diff --git a/theme/splash/layout/report.php b/theme/splash/layout/report.php
index 20a9775..10d7390 100644
--- a/theme/splash/layout/report.php
+++ b/theme/splash/layout/report.php
@@ -32,6 +32,7 @@ $custommenu = $OUTPUT->custom_menu();
 $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 splash_check_colourswitch();
+splash_initialise_colourswitcher($PAGE);
 
 $bodyclasses = array();
 $bodyclasses[] = 'splash-'.splash_get_colour();
diff --git a/theme/splash/lib.php b/theme/splash/lib.php
index 5aeb7db..f9f1fb6 100644
--- a/theme/splash/lib.php
+++ b/theme/splash/lib.php
@@ -88,6 +88,19 @@ function splash_set_customcss($css, $customcss) {
 }
 
 /**
+ * Adds the JavaScript for the colour switcher to the page.
+ *
+ * The colour switcher is a YUI moodle module that is located in
+ *     theme/splash/yui/splash/splash.js
+ *
+ * @param moodle_page $page
+ */
+function splash_initialise_colourswitcher(moodle_page $page) {
+    user_preference_allow_ajax_update('theme_splash_chosen_colour', PARAM_ALPHA);
+    $page->requires->yui_module('moodle-theme_splash-colourswitcher', 'M.theme_splash.initColourSwitcher', array(array('div'=>'#colourswitcher')));
+}
+
+/**
  * Gets the colour the user has selected, or the default if they have never changed
  *
  * @param string $default The default colour to use, normally red
-- 
1.7.9.5


From 93fd7cb10cc9dca86b03443a9ec8661be754eecf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 13:57:55 +0200
Subject: [PATCH 023/903] MDL-34121 drop unused backup tables that were
 supposed to be dropped long ago

The backup/restore leftovers that referenced these will be dropped in 2.4
---
 lib/db/install.xml |   32 ++------------------------------
 lib/db/upgrade.php |   23 +++++++++++++++++++++++
 version.php        |    2 +-
 3 files changed, 26 insertions(+), 31 deletions(-)

diff --git a/lib/db/install.xml b/lib/db/install.xml
index 38ef87e..1d88b4d 100644
--- a/lib/db/install.xml
+++ b/lib/db/install.xml
@@ -2410,7 +2410,7 @@
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
-    <TABLE NAME="repository_instance_config" COMMENT="The config for intances" PREVIOUS="repository_instances" NEXT="backup_files">
+    <TABLE NAME="repository_instance_config" COMMENT="The config for intances" PREVIOUS="repository_instances" NEXT="backup_courses">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="instanceid"/>
         <FIELD NAME="instanceid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
@@ -2421,35 +2421,7 @@
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
-    <TABLE NAME="backup_files" COMMENT="To store and recode ids to user and course files" PREVIOUS="repository_instance_config" NEXT="backup_ids">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="backup_code"/>
-        <FIELD NAME="backup_code" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="file_type"/>
-        <FIELD NAME="file_type" TYPE="char" LENGTH="10" NOTNULL="true" SEQUENCE="false" PREVIOUS="backup_code" NEXT="path"/>
-        <FIELD NAME="path" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="file_type" NEXT="old_id"/>
-        <FIELD NAME="old_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="path" NEXT="new_id"/>
-        <FIELD NAME="new_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="old_id"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="backup_code-file_type-path"/>
-        <KEY NAME="backup_code-file_type-path" TYPE="unique" FIELDS="backup_code, file_type, path" PREVIOUS="primary"/>
-      </KEYS>
-    </TABLE>
-    <TABLE NAME="backup_ids" COMMENT="To store and convert ids in backup/restore" PREVIOUS="backup_files" NEXT="backup_courses">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="backup_code"/>
-        <FIELD NAME="backup_code" TYPE="int" LENGTH="12" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="table_name"/>
-        <FIELD NAME="table_name" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" PREVIOUS="backup_code" NEXT="old_id"/>
-        <FIELD NAME="old_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="table_name" NEXT="new_id"/>
-        <FIELD NAME="new_id" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="old_id" NEXT="info"/>
-        <FIELD NAME="info" TYPE="text" NOTNULL="true" SEQUENCE="false" PREVIOUS="new_id"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="backup_code-table_name-old_id"/>
-        <KEY NAME="backup_code-table_name-old_id" TYPE="unique" FIELDS="backup_code, table_name, old_id" PREVIOUS="primary"/>
-      </KEYS>
-    </TABLE>
-    <TABLE NAME="backup_courses" COMMENT="To store every course backup status" PREVIOUS="backup_ids" NEXT="block">
+    <TABLE NAME="backup_courses" COMMENT="To store every course backup status" PREVIOUS="repository_instance_config" NEXT="block">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="courseid"/>
         <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="laststarttime"/>
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 3be8b80..b737428 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -871,6 +871,29 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062000.01);
     }
 
+    if ($oldversion < 2012062500.01) {
+        // Drop some old backup tables, not used anymore
+
+        // Define table backup_files to be dropped
+        $table = new xmldb_table('backup_files');
+
+        // Conditionally launch drop table for backup_files
+        if ($dbman->table_exists($table)) {
+            $dbman->drop_table($table);
+        }
+
+        // Define table backup_ids to be dropped
+        $table = new xmldb_table('backup_ids');
+
+        // Conditionally launch drop table for backup_ids
+        if ($dbman->table_exists($table)) {
+            $dbman->drop_table($table);
+        }
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012062500.01);
+    }
+
 
     return true;
 }
diff --git a/version.php b/version.php
index 6739bbe..0a9d706 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062500.00;              // 2012062500    = branching date YYYYMMDD - do not modify!
+$version  = 2012062500.01;              // 2012062500    = branching date YYYYMMDD - do not modify!
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 5df5bcba99340ae837ff13a62741eda0e65e2432 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 15:39:12 +0200
Subject: [PATCH 024/903] MDL-34036 fix course role user selector

---
 user/filters/courserole.php |   15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/user/filters/courserole.php b/user/filters/courserole.php
index 49cb54c..a38fe41 100644
--- a/user/filters/courserole.php
+++ b/user/filters/courserole.php
@@ -84,7 +84,7 @@ class user_filter_courserole extends user_filter_type {
     function get_sql_filter($data) {
         global $CFG, $DB;
         static $counter = 0;
-        $name = 'ex_courserole'.$counter++;
+        $pref = 'ex_courserole'.($counter++).'_';
 
         $value      = $data['value'];
         $roleid     = $data['roleid'];
@@ -98,17 +98,16 @@ class user_filter_courserole extends user_filter_type {
 
         $where = "b.contextlevel=50";
         if ($roleid) {
-            $where .= " AND a.roleid = :roleid";
-            $params['roleid'] = $roleid;
-
+            $where .= " AND a.roleid = :{$pref}roleid";
+            $params[$pref.'roleid'] = $roleid;
         }
         if ($categoryid) {
-            $where .= " AND c.category = :categoryid";
-            $params['categoryid'] = $categoryid;
+            $where .= " AND c.category = :{$pref}categoryid";
+            $params[$pref.'categoryid'] = $categoryid;
         }
         if ($value) {
-            $where .= " AND c.shortname = :$name";
-            $params[$name] = $value;
+            $where .= " AND c.shortname = :{$pref}course";
+            $params[$pref.'course'] = $value;
         }
         return array("id IN (SELECT userid
                                FROM {role_assignments} a
-- 
1.7.9.5


From 134affd943a5f129d67c0350d48cca74b93c6a4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sat, 30 Jun 2012 20:46:04 +0200
Subject: [PATCH 025/903] MDL-34123 use user's lang when sending new emails

---
 lib/cronlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/cronlib.php b/lib/cronlib.php
index b034760..98c8f2d 100644
--- a/lib/cronlib.php
+++ b/lib/cronlib.php
@@ -208,7 +208,7 @@ function cron_run() {
     if ($DB->count_records('user_preferences', array('name'=>'create_password', 'value'=>'1'))) {
         mtrace('Creating passwords for new users...');
         $newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email, u.firstname,
-                                                 u.lastname, u.username,
+                                                 u.lastname, u.username, u.lang,
                                                  p.id as prefid
                                             FROM {user} u
                                             JOIN {user_preferences} p ON u.id=p.userid
-- 
1.7.9.5


From 8b3d60557c062bb332058abc8765ddd8ebfa9b98 Mon Sep 17 00:00:00 2001
From: Sun Zhigang <sunner@gmail.com>
Date: Tue, 22 May 2012 19:36:50 +0800
Subject: [PATCH 026/903] MDL-31201 wiki: fix a hardcoded string

---
 mod/wiki/lang/en/wiki.php              |    1 +
 mod/wiki/parser/markups/wikimarkup.php |    2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/wiki/lang/en/wiki.php b/mod/wiki/lang/en/wiki.php
index 4815ba3..9781d7b 100644
--- a/mod/wiki/lang/en/wiki.php
+++ b/mod/wiki/lang/en/wiki.php
@@ -195,6 +195,7 @@ $string['searchcontent'] = 'Search in page content';
 $string['searchresult'] = 'Search results:';
 $string['searchwikis'] = 'Search wikis';
 $string['special'] = 'Special';
+$string['tableofcontents'] = 'Table of contents';
 $string['tagsdeleted'] = 'Wiki tags have been deleted';
 $string['tagtitle'] = 'See the "{$a}" tag';
 $string['teacherrating'] = 'Teacher rating';
diff --git a/mod/wiki/parser/markups/wikimarkup.php b/mod/wiki/parser/markups/wikimarkup.php
index 30976db..cf7a2b3 100644
--- a/mod/wiki/parser/markups/wikimarkup.php
+++ b/mod/wiki/parser/markups/wikimarkup.php
@@ -239,7 +239,7 @@ abstract class wiki_markup_parser extends generic_parser {
             $i++;
         }
 
-        $this->returnvalues['toc'] = "<div class=\"wiki-toc\"><p class=\"wiki-toc-title\">Table of contents</p>$toc</div>";
+        $this->returnvalues['toc'] = "<div class=\"wiki-toc\"><p class=\"wiki-toc-title\">" . get_string('tableofcontents', 'wiki') . "</p>$toc</div>";
     }
 
     /**
-- 
1.7.9.5


From 43fb824bd23bd59661538c49f7a3e469f53198e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 10:04:54 +0200
Subject: [PATCH 027/903] MDL-34125 fix regression when deleting activity
 modules

Credit goes to Gordon Bateson.
---
 lib/adminlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/adminlib.php b/lib/adminlib.php
index 4aff653..5062c99 100644
--- a/lib/adminlib.php
+++ b/lib/adminlib.php
@@ -452,7 +452,7 @@ function get_used_table_names() {
 
         if ($loaded and $tables = $structure->getTables()) {
             foreach($tables as $table) {
-                $table_names[] = strtolower($table->name);
+                $table_names[] = strtolower($table->getName());
             }
         }
     }
-- 
1.7.9.5


From 9ee97228bdf1d7c658fe470a7d92a4221104addf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 13:30:59 +0200
Subject: [PATCH 028/903] MDL-34130 fix data inserts in recordset tests

---
 lib/dml/tests/dml_test.php |   20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index e431b91..fcbffce 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -921,12 +921,12 @@ class dml_testcase extends database_driver_testcase {
         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
         $dbman->create_table($table);
 
-        $data = array(array('id' => 1, 'course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
-            array('id' => 2, 'course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
-            array('id' => 3, 'course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
+        $data = array(array('course' => 3, 'name' => 'record1', 'onetext'=>'abc'),
+            array('course' => 3, 'name' => 'record2', 'onetext'=>'abcd'),
+            array('course' => 5, 'name' => 'record3', 'onetext'=>'abcde'));
 
-        foreach ($data as $record) {
-            $DB->insert_record($tablename, $record);
+        foreach ($data as $key=>$record) {
+            $data[$key]['id'] = $DB->insert_record($tablename, $record);
         }
 
         // standard recordset iteration
@@ -1009,11 +1009,11 @@ class dml_testcase extends database_driver_testcase {
         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
         $dbman->create_table($table);
 
-        $data = array(array('id'=> 1, 'course' => 3, 'name' => 'record1'),
-            array('id'=> 2, 'course' => 3, 'name' => 'record2'),
-            array('id'=> 3, 'course' => 5, 'name' => 'record3'));
-        foreach ($data as $record) {
-            $DB->insert_record($tablename, $record);
+        $data = array(array('course' => 3, 'name' => 'record1'),
+            array('course' => 3, 'name' => 'record2'),
+            array('course' => 5, 'name' => 'record3'));
+        foreach ($data as $key=>$record) {
+            $data[$key]['id'] = $DB->insert_record($tablename, $record);
         }
 
         // Test repeated numeric keys are returned ok
-- 
1.7.9.5


From 1cf431a3291f710c1cf17095105b0e31175b679d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 13:34:22 +0200
Subject: [PATCH 029/903] MDL-34130 test nested recordset iteration

---
 lib/dml/tests/dml_test.php |   16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index fcbffce..acecb7b 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -990,6 +990,22 @@ class dml_testcase extends database_driver_testcase {
             $this->assertEquals($e->errorcode, 'textconditionsnotallowed');
         }
 
+        // Test nested iteration.
+        $rs1 = $DB->get_recordset($tablename);
+        $i = 0;
+        foreach($rs1 as $record1) {
+            $rs2 = $DB->get_recordset($tablename);
+            $i++;
+            $j = 0;
+            foreach($rs2 as $record2) {
+                $j++;
+            }
+            $rs2->close();
+            $this->assertEquals($j, count($data));
+        }
+        $rs1->close();
+        $this->assertEquals($i, count($data));
+
         // notes:
         //  * limits are tested in test_get_recordset_sql()
         //  * where_clause() is used internally and is tested in test_get_records()
-- 
1.7.9.5


From a61e8c8ebe806433bf4e21c367779c2ec2c3d86c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 13:43:55 +0200
Subject: [PATCH 030/903] MDL-34130 test interaction of recordsets and
 transactions

---
 lib/dml/tests/dml_test.php |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index acecb7b..15b52f2 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -4144,6 +4144,42 @@ class dml_testcase extends database_driver_testcase {
         $this->assertEquals(0, $DB->count_records($tablename)); // finally rolled back
 
         $DB->delete_records($tablename);
+
+        // Test interactions of recordset and transactions - this causes problems in SQL Server.
+        $table2 = $this->get_test_table('2');
+        $tablename2 = $table2->getName();
+
+        $table2->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table2->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
+        $table2->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $dbman->create_table($table2);
+
+        $DB->insert_record($tablename, array('course'=>1));
+        $DB->insert_record($tablename, array('course'=>2));
+        $DB->insert_record($tablename, array('course'=>3));
+
+        $DB->insert_record($tablename2, array('course'=>5));
+        $DB->insert_record($tablename2, array('course'=>6));
+        $DB->insert_record($tablename2, array('course'=>7));
+        $DB->insert_record($tablename2, array('course'=>8));
+
+        $rs1 = $DB->get_recordset($tablename);
+        $i = 0;
+        foreach ($rs1 as $record1) {
+            $i++;
+            $rs2 = $DB->get_recordset($tablename2);
+            $j = 0;
+            foreach ($rs2 as $record2) {
+                $t = $DB->start_delegated_transaction();
+                $DB->set_field($tablename, 'course', $record1->course+1, array('id'=>$record1->id));
+                $DB->set_field($tablename2, 'course', $record2->course+1, array('id'=>$record2->id));
+                $t->allow_commit();
+                $j++;
+            }
+            $this->assertEquals(4, $j);
+        }
+        $rs1->close();
+        $this->assertEquals(3, $i);
     }
 
     function test_transactions_forbidden() {
-- 
1.7.9.5


From a2b8856558be1ed0f5b381a8cb6ee819f806f82b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 21:00:16 +0200
Subject: [PATCH 031/903] MDL-34130 add missing rs close

Thanks Eloy!
---
 lib/dml/tests/dml_test.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 15b52f2..652d022 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -4176,6 +4176,7 @@ class dml_testcase extends database_driver_testcase {
                 $t->allow_commit();
                 $j++;
             }
+            $rs2->close();
             $this->assertEquals(4, $j);
         }
         $rs1->close();
-- 
1.7.9.5


From d0812ba0e6989c83900fd719942cba1a6fdb4d68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 21:35:37 +0200
Subject: [PATCH 032/903] MDL-34130 test recordset data is static

We do not want recordset results to be affected by subsequent update or delete queries.
---
 lib/dml/tests/dml_test.php |   52 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 652d022..9099445 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -1011,6 +1011,58 @@ class dml_testcase extends database_driver_testcase {
         //  * where_clause() is used internally and is tested in test_get_records()
     }
 
+    public function test_get_recordset_static() {
+        $DB = $this->tdb;
+        $dbman = $DB->get_manager();
+
+        $table = $this->get_test_table();
+        $tablename = $table->getName();
+
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $dbman->create_table($table);
+
+        $DB->insert_record($tablename, array('course' => 1));
+        $DB->insert_record($tablename, array('course' => 2));
+        $DB->insert_record($tablename, array('course' => 3));
+        $DB->insert_record($tablename, array('course' => 4));
+
+        $rs = $DB->get_recordset($tablename, array(), 'id');
+
+        $DB->set_field($tablename, 'course', 666, array('course'=>1));
+        $DB->delete_records($tablename, array('course'=>2));
+
+        $i = 0;
+        foreach($rs as $record) {
+            $i++;
+            $this->assertEquals($i, $record->course);
+        }
+        $rs->close();
+        $this->assertEquals(4, $i);
+
+        // Now repeat with limits because it may use different code.
+        $DB->delete_records($tablename, array());
+
+        $DB->insert_record($tablename, array('course' => 1));
+        $DB->insert_record($tablename, array('course' => 2));
+        $DB->insert_record($tablename, array('course' => 3));
+        $DB->insert_record($tablename, array('course' => 4));
+
+        $rs = $DB->get_recordset($tablename, array(), 'id', '*', 0, 3);
+
+        $DB->set_field($tablename, 'course', 666, array('course'=>1));
+        $DB->delete_records($tablename, array('course'=>2));
+
+        $i = 0;
+        foreach($rs as $record) {
+            $i++;
+            $this->assertEquals($i, $record->course);
+        }
+        $rs->close();
+        $this->assertEquals(3, $i);
+    }
+
     public function test_get_recordset_iterator_keys() {
         $DB = $this->tdb;
         $dbman = $DB->get_manager();
-- 
1.7.9.5


From 19ba134d3bbb6e36c51da63f6292c6ddf882a519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Sun, 1 Jul 2012 21:50:36 +0200
Subject: [PATCH 033/903] MDL-34130 prevent some warning in PHPStorm

---
 lib/dml/tests/dml_test.php |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 9099445..a5ad8c2 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -308,6 +308,7 @@ class dml_testcase extends database_driver_testcase {
 
     function test_fix_sql_params() {
         $DB = $this->tdb;
+        $prefix = $DB->get_prefix();
 
         $table = $this->get_test_table();
         $tablename = $table->getName();
@@ -315,13 +316,13 @@ class dml_testcase extends database_driver_testcase {
         // Correct table placeholder substitution
         $sql = "SELECT * FROM {{$tablename}}";
         $sqlarray = $DB->fix_sql_params($sql);
-        $this->assertEquals("SELECT * FROM {$DB->get_prefix()}".$tablename, $sqlarray[0]);
+        $this->assertEquals("SELECT * FROM {$prefix}".$tablename, $sqlarray[0]);
 
         // Conversions of all param types
         $sql = array();
-        $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = :param1, course = :param2";
-        $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = ?, course = ?";
-        $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$DB->get_prefix()}testtable WHERE name = \$1, course = \$2";
+        $sql[SQL_PARAMS_NAMED]  = "SELECT * FROM {$prefix}testtable WHERE name = :param1, course = :param2";
+        $sql[SQL_PARAMS_QM]     = "SELECT * FROM {$prefix}testtable WHERE name = ?, course = ?";
+        $sql[SQL_PARAMS_DOLLAR] = "SELECT * FROM {$prefix}testtable WHERE name = \$1, course = \$2";
 
         $params = array();
         $params[SQL_PARAMS_NAMED]  = array('param1'=>'first record', 'param2'=>1);
-- 
1.7.9.5


From 1494f20da3af51ab1c6c7051ec5a888461627a0f Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Mon, 2 Jul 2012 00:54:05 +0200
Subject: [PATCH 034/903] weekly release 2.3+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 6739bbe..728ef4d 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062500.00;              // 2012062500    = branching date YYYYMMDD - do not modify!
+$version  = 2012062500.01;              // 2012062500    = branching date YYYYMMDD - do not modify!
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3 (Build: 20120625)';    // Human-friendly version name
+$release  = '2.3+ (Build: 20120701)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From e5c2bbd0f7f013982ed1a38bd55dccf5b5388f20 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Fri, 8 Jun 2012 09:59:59 +0800
Subject: [PATCH 035/903] MDL-33303 Filepicker: resized to match HTML editor
 and made resizable

---
 files/renderer.php               |   17 ++++++++++---
 lib/form/filemanager.js          |   51 ++++++++++++++++++++++++++++++++++++--
 theme/base/style/filemanager.css |    6 +++--
 3 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/files/renderer.php b/files/renderer.php
index 33a70f6..edcb585 100644
--- a/files/renderer.php
+++ b/files/renderer.php
@@ -107,7 +107,7 @@ class core_files_renderer extends plugin_renderer_base {
         $module = array(
             'name'=>'form_filemanager',
             'fullpath'=>'/lib/form/filemanager.js',
-            'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+            'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin', 'resize'),
             'strings' => array(
                 array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
                 array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
@@ -123,6 +123,7 @@ class core_files_renderer extends plugin_renderer_base {
                     array($this->filemanager_js_templates()), true, $module);
         }
         $this->page->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
+        user_preference_allow_ajax_update('filemanagerresizedto', PARAM_SEQUENCE);
 
         // non javascript file manager
         $html .= '<noscript>';
@@ -192,8 +193,17 @@ class core_files_renderer extends plugin_renderer_base {
         $strdndenabledinbox = get_string('dndenabled_inbox', 'moodle');
         $loading = get_string('loading', 'repository');
 
+        $resizedto = get_user_preferences('filemanagerresizedto', null);
+        $filemanagerstyle = '';
+        $containerstyletag = '';
+        if (!is_null($resizedto) && preg_match('#^\d+,\d+$#', $resizedto)) {
+            list($width, $height) = explode(',', $resizedto, 2);
+            $filemanagerstyle = " style='width:{$width}px;'";
+            $containerstyletag = " style='height:{$height}px;'";
+        }
+
         $html = '
-<div id="filemanager-'.$client_id.'" class="filemanager fm-loading">
+<div id="filemanager-'.$client_id.'" class="filemanager fm-loading"'.$filemanagerstyle.'>
     <div class="fp-restrictions">
         '.$restrictions.'
         <span class="dndupload-message"> - '.$strdndenabled.' </span>
@@ -216,7 +226,7 @@ class core_files_renderer extends plugin_renderer_base {
         </div>
     </div>
     <div class="filemanager-loading mdl-align">'.$icon_progress.'</div>
-    <div class="filemanager-container" >
+    <div class="filemanager-container"'.$containerstyletag.'>
         <div class="fm-content-wrapper">
             <div class="fp-content"></div>
             <div class="fm-empty-container <!--mdl-align-->">
@@ -227,6 +237,7 @@ class core_files_renderer extends plugin_renderer_base {
         </div>
         <div class="filemanager-updating">'.$icon_progress.'</div>
     </div>
+    <div class="fp-statusbar"></div>
 </div>';
         return preg_replace('/\{\!\}/', '', $html);
     }
diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index f1f88b2..ae9f048 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -83,6 +83,14 @@ M.form_filemanager.init = function(Y, options) {
             } else {
                 this.filecount = 0;
             }
+
+            this.publish('filemanager:content-changed', {
+                context : this,
+                prefix : 'filemanager',
+                preventable : false,
+                type : 'content-changed'
+            });
+
             // prepare filemanager for drag-and-drop upload
             this.filemanager = Y.one('#filemanager-'+options.client_id);
             if (this.filemanager.hasClass('filemanager-container') || !this.filemanager.one('.filemanager-container')) {
@@ -122,6 +130,44 @@ M.form_filemanager.init = function(Y, options) {
             this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
             this.filemanager.all('.fp-vb-icons').addClass('checked')
             this.refresh(this.currentpath); // MDL-31113 get latest list from server
+
+            // Make sure that the filemanager is at least shown within the constraints of the page
+            if ((this.filemanager.get('offsetWidth') + this.filemanager.getX()) > this.filemanager.get('docWidth')) {
+                this.filemanager.setStyle('width', Math.round(this.filemanager.get('docWidth') - this.filemanager.getX()));
+            }
+
+            if (Y.Resize) {
+                // We only do this is the YUI resize component is loaded
+                var resize = new Y.Resize({
+                    node: this.dndcontainer,
+                    wrap : true,
+                    handles : ['br']
+                }).plug(Y.Plugin.ResizeConstrained, {
+                    minWidth : 410,
+                    maxWidth : this.dndcontainer.ancestor('.ffilemanager').get('offsetWidth') || 1600,
+                    minHeight : 160,
+                    maxHeight : 1024
+                });
+                // When it resizes we need to correct the width and height of other elements.
+                resize.on('resize:resize', function(e) {
+                    this.filemanager.setStyle('width', e.info.offsetWidth);
+                    var fmcw = this.filemanager.one('.fp-content');
+                    if (fmcw) {
+                        fmcw.setStyle('height', this.dndcontainer.get('offsetHeight'));
+                    }
+                }, this);
+                // After resizing we update the user preference so that we always show them the file manager at the same size.
+                resize.on('resize:end', function(e){
+                    M.util.set_user_preference('filemanagerresizedto', Math.round(e.info.offsetWidth).toString()+','+Math.round(e.info.offsetHeight).toString());
+                });
+                // When content gets updated by the filemanager we need to auto-update the height of the resizeable area to include it.
+                this.on('filemanager:content-changed', function(){
+                    var fmcw = this.filemanager.one('.fp-content');
+                    if (fmcw) {
+                        fmcw.setStyle('height', this.dndcontainer.get('offsetHeight'));
+                    }
+                }, this);
+            }
         },
 
         wait: function() {
@@ -511,7 +557,7 @@ M.form_filemanager.init = function(Y, options) {
                 filenode : element_template,
                 callbackcontext : this,
                 callback : function(e, node) {
-                    if (e.preventDefault) { e.preventDefault(); }
+                    if (e.preventDefault) {e.preventDefault();}
                     if (node.type == 'folder') {
                         this.refresh(node.filepath);
                     } else {
@@ -519,7 +565,7 @@ M.form_filemanager.init = function(Y, options) {
                     }
                 },
                 rightclickcallback : function(e, node) {
-                    if (e.preventDefault) { e.preventDefault(); }
+                    if (e.preventDefault) {e.preventDefault();}
                     this.select_file(node);
                 },
                 classnamecallback : function(node) {
@@ -606,6 +652,7 @@ M.form_filemanager.init = function(Y, options) {
                 node.appendChild(Y.Node.create('<option/>').
                     set('value', list[i]).setContent(list[i]))
             }
+            this.fire('filemanager:content-changed');
         },
         update_file: function(confirmed) {
             var selectnode = this.selectnode;
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 86d0446..45eb572 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -1,7 +1,7 @@
 /**
  * File Picker and File Manager
  */
-
+.filemanager {width: 680px; min-width: 410px;}
 .filemanager, .file-picker {font-size:11px;color: #555555;letter-spacing: .2px;}
 .filemanager a, .file-picker a {color:#555555;}
 .filemanager a:hover, .file-picker a:hover {color:#555555;text-decoration: none;}
@@ -288,8 +288,10 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
-.filemanager .fp-content{overflow: auto;max-height: 472px;}
+.filemanager .fp-content{overflow: auto;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
+.filemanager.fm-loaded .fp-statusbar {background: #F2F2F2;border: 1px solid #BBB;border-top:0;min-height:2em;margin-bottom:5px;padding-right:2em;}
+.filemanager .yui3-resize-handle-inner-br {bottom:-2em;}
 
 /*
  * Icon view (File Manager only)
-- 
1.7.9.5


From abfc9e2512f0612ede44a3a24bb1470a1ee737f4 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 31 May 2012 14:51:02 +1200
Subject: [PATCH 036/903] MDL-33521 css: Fixed invalid CSS in core CSS and
 plugin styles.css files

---
 admin/tool/health/styles.css     |    8 ++++----
 blocks/community/styles.css      |    2 +-
 grade/report/grader/styles.css   |    8 ++++----
 mod/quiz/styles.css              |    6 +++---
 mod/wiki/styles.css              |    2 +-
 mod/workshop/styles.css          |    8 ++++----
 theme/base/style/admin.css       |    4 ++--
 theme/base/style/course.css      |    2 +-
 theme/base/style/filemanager.css |    3 +--
 theme/base/style/message.css     |    2 +-
 theme/standard/style/grade.css   |    2 +-
 theme/standard/style/modules.css |    2 +-
 12 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/admin/tool/health/styles.css b/admin/tool/health/styles.css
index 556b443..7994a8c 100644
--- a/admin/tool/health/styles.css
+++ b/admin/tool/health/styles.css
@@ -3,7 +3,7 @@
     width: 60%;
     margin: auto;
     padding: 1em;
-    border: 1px black solid;
+    border: 1px solid black;
     -moz-border-radius: 6px;
 }
 .path-admin-tool-health dl.healthissues {
@@ -35,15 +35,15 @@
 .path-admin-tool-health dl.healthissues dd {
     margin: 0px;
     padding: 1em;
-    border: 1px black solid;
+    border: 1px solid black;
 }
 .path-admin-tool-health dl.healthissues dt {
     font-weight: bold;
-    border-bottom: none;
+    border-bottom: 0;
     padding-bottom: 0.5em;
 }
 .path-admin-tool-health dl.healthissues dd {
-    border-top: none;
+    border-top: 0;
     padding-top: 0.5em;
     margin-bottom: 10px;
 }
diff --git a/blocks/community/styles.css b/blocks/community/styles.css
index 34f0660..97e6e1d 100644
--- a/blocks/community/styles.css
+++ b/blocks/community/styles.css
@@ -173,7 +173,7 @@
     bottom:0;
     right:0;
     opacity:0.35;
-    filter:alpha(opacity:35);
+    filter:alpha(opacity=35);
     background:#000;
 }
 
diff --git a/grade/report/grader/styles.css b/grade/report/grader/styles.css
index 4730ba5..c562c82 100644
--- a/grade/report/grader/styles.css
+++ b/grade/report/grader/styles.css
@@ -185,7 +185,7 @@ margin-right:10px;
 }
 
 table#user-grades .quickfeedback {
-border:#000 1px dashed;
+border:1px dashed #000;
 }
 
 .path-grade-report-grader #siteconfiglink {
@@ -262,7 +262,7 @@ border-width:0 1px 1px;
 }
 
 .path-grade-report-grader table td.topleft {
-border-bottom:none;
+border-bottom:0;
 }
 
 table#user-grades td.topleft {
@@ -325,12 +325,12 @@ margin: 10px 10px 0px 10px;
 }
 
 .path-grade-report-grader table#quick_edit td.fullname {
-border-left:none;
+border-left:0;
 padding-left:5px;
 }
 
 .path-grade-report-grader table#quick_edit td.picture {
-border-right:none;
+border-right:0;
 }
 
 .path-grade-report-grader table#quick_edit td.finalgrade input {
diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index d19de76..6361024 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -48,7 +48,7 @@ body.jsenabled .questionflagcheckbox {display: none;}
 .path-mod-quiz .qnbutton.incorrect .trafficlight {border-top: 3px solid #800;}
 
 .path-mod-quiz .qnbutton.free:hover {text-decoration: underline;}
-.path-mod-quiz .qnbutton.free span {cursor: pointer; cursor: hand;}
+.path-mod-quiz .qnbutton.free span {cursor: pointer;}
 
 .path-mod-quiz .othernav {clear: both; margin: 0.5em 0;}
 .path-mod-quiz .othernav a,
@@ -192,7 +192,7 @@ table#categoryquestions {width: 100%;overflow: hidden;table-layout: fixed;}
 #page-mod-quiz-edit div.quizwhenbankcollapsed {width:100%;}
 #page-mod-quiz-edit div.quizpage {display:block;clear:both;width:100%;}
 #page-mod-quiz-edit div.quizpage span.pagetitle {margin-top:0.3em;float:left;display:block;color:#006;}
-#page-mod-quiz-edit div.quizpage .pagecontent {margin-top:0.3em;display:block;float:left;position:relative;margin-left:0.3em;margin-bottom:0.2em;border-left:solid #777 thin;line-height:1.3em;-webkit-border-radius:0.6em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.6em;border-radius-bottomleft:0;border-radius-topleft:0;width:88%;padding:0.15em 0 0.3em;background-color:#d6d6d6;}
+#page-mod-quiz-edit div.quizpage .pagecontent {margin-top:0.3em;display:block;float:left;position:relative;margin-left:0.3em;margin-bottom:0.2em;border-left:thin solid #777;line-height:1.3em;-webkit-border-radius:0.6em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.6em;border-radius-bottomleft:0;border-radius-topleft:0;width:88%;padding:0.15em 0 0.3em;background-color:#d6d6d6;}
 #page-mod-quiz-edit div.quizpage .pagecontent .pagestatus {-webkit-border-radius-bottomright:0.3em;-webkit-border-radius-topright:0.3em;border-radius-bottomright:0.3em;border-radius-topright:0.3em;margin:0.3em;padding:0.1em 0.1em 0.1em 0.3em;background-color:#eee;font-weight:bold;}
 #page-mod-quiz-edit div.quizpage .pagecontent form#addquestion{background-color:#fff;}
 #page-mod-quiz-edit div.quizpage .pagecontent form.randomquestionform div {/* it is a mystery why this has to be inline-table but otherwise the layout gets screwed, even if it is "inline" */display: inline-table;}
@@ -237,7 +237,7 @@ table#categoryquestions {width: 100%;overflow: hidden;table-layout: fixed;}
 #page-mod-quiz-edit div.question div.qnum {display:block;float:left;width:1.4em;padding-right:0.3em;padding-left:0;z-index:99;text-align:right;color:#333;}
 #page-mod-quiz-edit div.question div.questioncontainer{background-color:#ffc;}
 #page-mod-quiz-edit div.editq div.question div.content{width:87%;float:left;position:relative;-webkit-border-radius:0.6em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.6em;border-radius-bottomleft:0;border-radius-topleft:0;line-height:1.4em;padding:0.5em;}
-#page-mod-quiz-edit div.question div.content div.points{top:0.5em;border-left:#FFF solid 0.4em;width:8.5em;padding:0.2em;line-height:1em;max-width:30%;position:absolute;right:50px;-webkit-border-radius:0.2em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.2em;border-radius-bottomleft:0;border-radius-topleft:0;z-index:900;display:block;margin:0;background-color:#ddf;}
+#page-mod-quiz-edit div.question div.content div.points{top:0.5em;border-left:0.4em solid #FFF;width:8.5em;padding:0.2em;line-height:1em;max-width:30%;position:absolute;right:50px;-webkit-border-radius:0.2em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.2em;border-radius-bottomleft:0;border-radius-topleft:0;z-index:900;display:block;margin:0;background-color:#ddf;}
 #page-mod-quiz-edit div.question div.content div.points input{width:2em;padding:0;}
 #page-mod-quiz-edit div.question div.content div.points input.pointssubmitbutton{width:auto;}
 #page-mod-quiz-edit div.question div.content div.qorder {line-height:1em;max-width:30%;position:absolute;right:50px;-webkit-border-radius:0.2em;-webkit-border-radius-bottomleft:0;-webkit-border-radius-topleft:0;border-radius:0.2em;border-radius-bottomleft:0;border-radius-topleft:0;z-index:900;display:block;margin:0;background-color:#ddf;}
diff --git a/mod/wiki/styles.css b/mod/wiki/styles.css
index dcfd480..74536aa 100644
--- a/mod/wiki/styles.css
+++ b/mod/wiki/styles.css
@@ -142,7 +142,7 @@
 }
 
 .wiki_modifieduser img {
-    border: thin black solid;
+    border: thin solid black;
 }
 
 .wiki_restore_yes, .wiki_deletecomment_yes {
diff --git a/mod/workshop/styles.css b/mod/workshop/styles.css
index ba99b03..6f9c014 100644
--- a/mod/workshop/styles.css
+++ b/mod/workshop/styles.css
@@ -20,12 +20,12 @@
 
 .path-mod-workshop .groupwidget {
     text-align:center;
-    margin: 0.75 auto;
+    margin: 0.75em auto;
 }
 
 .path-mod-workshop .perpagewidget {
     text-align:center;
-    margin: 0.75 auto;
+    margin: 0.75em auto;
 }
 
 /**
@@ -246,7 +246,7 @@
     color: black;
     font-size: 140%;
     border: 1px solid #ddd;
-    border-bottom: none;
+    border-bottom: 0;
     background: #e7f1c3;
 }
 
@@ -276,7 +276,7 @@
 }
 
 .path-mod-workshop .userplan td.lastcol {
-    border-right: none;
+    border-right: 0;
 }
 
 .path-mod-workshop .userplan td.active {
diff --git a/theme/base/style/admin.css b/theme/base/style/admin.css
index e22e802..049a2a8 100644
--- a/theme/base/style/admin.css
+++ b/theme/base/style/admin.css
@@ -157,7 +157,7 @@
 #adminsettings fieldset.error legend {display: block;}
 #adminsettings .form-item {clear: both;margin: 1em 0 2em 0;}
 #adminsettings .form-item .form-label {display: block;float: left;width: 12.5em;text-align: right;}
-#adminsettings .form-item .form-label .form-shortname {display:block;line-break: break;}
+#adminsettings .form-item .form-label .form-shortname {display:block;}
 #adminsettings .form-item .form-setting {display: block;margin-left: 13.5em;text-align: left;}
 #adminsettings .form-item .form-setting .form-htmlarea {width:  640px;display:inline;}
 #adminsettings .form-item .form-setting .form-htmlarea .htmlarea {width:  640px;display:block;}
@@ -181,7 +181,7 @@
 .admin_colourpicker_preview {display:none;}
 .jsenabled .admin_colourpicker_preview {display:inline;}
 .jsenabled .admin_colourpicker {display:block;height:102px;width:410px;margin-bottom:10px;}
-.admin_colourpicker .loadingicon {vertical-align:center;margin-left:auto;}
+.admin_colourpicker .loadingicon {vertical-align:middle;margin-left:auto;}
 .admin_colourpicker .colourdialogue {float:left;border:1px solid #000;}
 .admin_colourpicker .previewcolour {border:1px solid #000;margin-left:301px;}
 .admin_colourpicker .currentcolour {border:1px solid #000;margin-left:301px;border-top-width:0;}
diff --git a/theme/base/style/course.css b/theme/base/style/course.css
index 4d3039e..09dc4b2 100644
--- a/theme/base/style/course.css
+++ b/theme/base/style/course.css
@@ -168,6 +168,6 @@ input.titleeditor {
 /* Course drag and drop upload styles */
 #dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;z-index: 0;}
 .dndupload-preview {color:#909090;border:1px dashed #909090;}
-.dndupload-progress-outer {width:70px;border:solid black 1px;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
+.dndupload-progress-outer {width:70px;border:1px solid black;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
 .dndupload-progress-inner {width:0%;height:100%;background-color:green;display:inline-block;margin:0;padding:0;float:left;}
 .dndupload-hidden {display:none;}
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 86d0446..105c238 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -228,8 +228,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*
  * Lazy loading on fp-content (File Picker only)
  */
-.file-picker .fp-nextpage {clear:both;align:center;}
-.file-picker .fp-nextpage .fp-nextpage-link {align:center;}
+.file-picker .fp-nextpage {clear:both;}
 .file-picker .fp-nextpage .fp-nextpage-loading {display:none;}
 .file-picker .fp-nextpage.loading .fp-nextpage-link {display:none;}
 .file-picker .fp-nextpage.loading .fp-nextpage-loading {display:block;text-align: center;height: 100px;padding-top: 50px;}
diff --git a/theme/base/style/message.css b/theme/base/style/message.css
index 57adc20..0be514e 100644
--- a/theme/base/style/message.css
+++ b/theme/base/style/message.css
@@ -43,7 +43,7 @@ table.message .searchresults td {padding:5px;}
 .message .messagearea .messagehistory .left {padding-bottom:10px;width:50%;float:left;clear:both;}
 .message .messagearea .messagehistory .right {padding-bottom:10px;width:50%;float:right;clear:both;}
 .message .messagearea .messagehistory .notification {padding:10px;background-color:#EEEEEE;margin-top:5px;}
-.message .messagearea .messagesend {padding-top:20px;float:center;clear:both;}
+.message .messagearea .messagesend {padding-top:20px;clear:both;}
 .message .messagearea .messagesend .messagesendbox {width:100%}
 .message .messagearea .messagesend fieldset {padding:0px;margin:0;} /** bring the message send button closer to the message box */
 
diff --git a/theme/standard/style/grade.css b/theme/standard/style/grade.css
index 41bcce9..c67cd43 100644
--- a/theme/standard/style/grade.css
+++ b/theme/standard/style/grade.css
@@ -29,7 +29,7 @@ td.grade div.overridden {background-color: #DDDDDD;}
 .gradetreebox tr.category th.cell.rowspan {border-width:0; border-left:1px solid #AAA;}
 .gradetreebox tr.category th.cell.rowspan:hover {background-color: #EEE;}
 .gradetreebox td.name {border-left: 0px;}
-.gradetreebox td.colspan {border-left: 1px solid #AAA;border-bottom: 1px solid #AAA;border-top: none;background-color: #DDD;}
+.gradetreebox td.colspan {border-left: 1px solid #AAA;border-bottom: 1px solid #AAA;border-top: 0;background-color: #DDD;}
 .gradetreebox tr .cell.level1 {background-color: #F3DFD0; width: 10px;}
 .gradetreebox tr .cell.level2 {background-color: #D0DBD3; width: 10px;}
 .gradetreebox tr .cell.level3 {background-color: #D0F3D6; width: 10px;}
diff --git a/theme/standard/style/modules.css b/theme/standard/style/modules.css
index e19bfdd..6456edf 100644
--- a/theme/standard/style/modules.css
+++ b/theme/standard/style/modules.css
@@ -131,7 +131,7 @@ table.mod_index {width:90%;margin:1em auto;}
 #page-mod-glossary-import table.glossaryimportexport {text-align: center;}
 .path-mod-glossary .glossarydisplay {width: 90%;text-align:center;}
 .path-mod-glossary .entrybox {border-width: 0px 1px 1px 1px;border-style: solid;border-color: #BBB;}
-.path-mod-glossary .entrybox hr {border-left:none;border-right:none;}
+.path-mod-glossary .entrybox hr {border-left:0;border-right:0;}
 #page-mod-glossary-report table tr.teacher {background: #F0F0F0;}
 #page-mod-glossary-view table.glossarycategoryheader {background-color: #DDD;}
 #page-mod-glossary-view table.glossarycategoryheader h2 {font-size: 1em;margin: 0;}
-- 
1.7.9.5


From 786ad3511cc611aeb22f4c580c20336dd8524fe4 Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Sat, 9 Jun 2012 20:30:17 +0200
Subject: [PATCH 037/903] MDL-33627 - feedback block now show all feedbacks

---
 blocks/feedback/block_feedback.php |   18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/blocks/feedback/block_feedback.php b/blocks/feedback/block_feedback.php
index 75a5126..5d41a50 100644
--- a/blocks/feedback/block_feedback.php
+++ b/blocks/feedback/block_feedback.php
@@ -4,7 +4,7 @@ if (is_file($CFG->dirroot.'/mod/feedback/lib.php')) {
     define('FEEDBACK_BLOCK_LIB_IS_OK', true);
 }
 
-class block_feedback extends block_base {
+class block_feedback extends block_list {
 
     function init() {
         $this->title = get_string('feedback', 'block_feedback');
@@ -21,10 +21,13 @@ class block_feedback extends block_base {
             return $this->content;
         }
 
+        $this->content = new stdClass;
+        $this->content->items = array();
+        $this->content->icons = array();
+        $this->content->footer = '';
+
         if (!defined('FEEDBACK_BLOCK_LIB_IS_OK')) {
-            $this->content = new stdClass;
-            $this->content->text = get_string('missing_feedback_module', 'block_feedback');
-            $this->content->footer = '';
+            $this->content->items = array(get_string('missing_feedback_module', 'block_feedback'));
             return $this->content;
         }
 
@@ -33,9 +36,7 @@ class block_feedback extends block_base {
             $courseid = SITEID;
         }
 
-        $this->content = new stdClass;
-        $this->content->text = '';
-        $this->content->footer = '';
+        $icon = '<img src="'.$OUTPUT->pix_url('icon', 'feedback') . '" class="icon" alt="" />';
 
 
         if (empty($this->instance->pageid)) {
@@ -47,8 +48,7 @@ class block_feedback extends block_base {
             foreach ($feedbacks as $feedback) {
                 $url = new moodle_url($baseurl);
                 $url->params(array('id'=>$feedback->cmid, 'courseid'=>$courseid));
-                $icon = '<img src="'.$OUTPUT->pix_url('icon', 'feedback') . '" class="icon" alt="" />&nbsp;';
-                $this->content->text = ' <a href="'.$url->out().'">'.$icon.$feedback->name.'</a>';
+                $this->content->items[] = '<a href="'.$url->out().'">'.$icon.$feedback->name.'</a>';
             }
         }
 
-- 
1.7.9.5


From e9aa190a3735c837fb665f079ba8fc3b52a24d8f Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Thu, 21 Jun 2012 21:59:03 +0200
Subject: [PATCH 038/903] MDL-33932_master - added array_unique()

---
 mod/feedback/item/multichoice/lib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/mod/feedback/item/multichoice/lib.php b/mod/feedback/item/multichoice/lib.php
index 3e5501f..33955c1 100644
--- a/mod/feedback/item/multichoice/lib.php
+++ b/mod/feedback/item/multichoice/lib.php
@@ -561,6 +561,9 @@ class feedback_item_multichoice extends feedback_item_base {
 
     public function create_value($data) {
         $vallist = $data;
+        if (is_array($vallist)) {
+            $vallist = array_unique($vallist);
+        }
         return trim($this->item_array_to_string($vallist));
     }
 
-- 
1.7.9.5


From 789c8b8194995ae3a4cccbf4c528b0aa07b75dca Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Wed, 13 Jun 2012 11:49:13 +0700
Subject: [PATCH 039/903] MDL-33686 Repositories: we were accessing a
 non-existent variable and thus never displaying the
 maximum number of attachments

---
 files/renderer.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/files/renderer.php b/files/renderer.php
index 33a70f6..78096e2 100644
--- a/files/renderer.php
+++ b/files/renderer.php
@@ -455,10 +455,10 @@ class core_files_renderer extends plugin_renderer_base {
      */
     private function fm_print_restrictions($fm) {
         $maxbytes = display_size($fm->options->maxbytes);
-        if (empty($options->maxfiles) || $options->maxfiles == -1) {
+        if (empty($fm->options->maxfiles) || $fm->options->maxfiles == -1) {
             $maxsize = get_string('maxfilesize', 'moodle', $maxbytes);
         } else {
-            $strparam = (object)array('size' => $maxbytes, 'attachments' => $options->maxfiles);
+            $strparam = (object)array('size' => $maxbytes, 'attachments' => $fm->options->maxfiles);
             $maxsize = get_string('maxsizeandattachments', 'moodle', $strparam);
         }
         // TODO MDL-32020 also should say about 'File types accepted'
-- 
1.7.9.5


From 800fb7533e2900411b97985c96cfe6dfd4f6a68a Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Mon, 25 Jun 2012 12:22:55 +1200
Subject: [PATCH 040/903] MDL-33978 SCORM activity completion - don't tiggere
 completion update state on creation of SCORM

---
 mod/scorm/lib.php |   24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php
index 7b395f5..822d3e2 100644
--- a/mod/scorm/lib.php
+++ b/mod/scorm/lib.php
@@ -150,7 +150,7 @@ function scorm_add_instance($scorm, $mform=null) {
 
     scorm_parse($record, true);
 
-    scorm_grade_item_update($record);
+    scorm_grade_item_update($record, null, false);
 
     return $record->id;
 }
@@ -646,9 +646,10 @@ function scorm_upgrade_grades() {
  * @uses GRADE_TYPE_NONE
  * @param object $scorm object with extra cmidnumber
  * @param mixed $grades optional array/object of grade(s); 'reset' means reset grades in gradebook
+ * @param boolean $updatecompletion  set whether to update completion stuff
  * @return object grade_item
  */
-function scorm_grade_item_update($scorm, $grades=null) {
+function scorm_grade_item_update($scorm, $grades=null, $updatecompletion=true) {
     global $CFG, $DB;
     require_once($CFG->dirroot.'/mod/scorm/locallib.php');
     if (!function_exists('grade_update')) { //workaround for buggy PHP versions
@@ -680,15 +681,16 @@ function scorm_grade_item_update($scorm, $grades=null) {
     }
 
     // Update activity completion if applicable
-    // Get course info
-    $course = new object();
-    $course->id = $scorm->course;
-
-    $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id);
-    // CM will be false if this has been run from scorm_add_instance
-    if ($cm) {
-        $completion = new completion_info($course);
-        $completion->update_state($cm, COMPLETION_COMPLETE);
+    if ($updatecompletion) {
+        // Get course info
+        $course = new stdClass();
+        $course->id = $scorm->course;
+
+        $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id);
+        if (!empty($cm)) {
+            $completion = new completion_info($course);
+            $completion->update_state($cm, COMPLETION_COMPLETE);
+        }
     }
 
     return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, $grades, $params);
-- 
1.7.9.5


From 6b5ce20c169f26e3059da98f0a7761e01156d3de Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Wed, 20 Jun 2012 15:49:20 +0800
Subject: [PATCH 041/903] MDL-33776 Web services: get_categories -
 subcategories should be checked against
 visible/theme keys

---
 course/externallib.php |   23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/course/externallib.php b/course/externallib.php
index e14ce90..41c5ab4 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -904,9 +904,10 @@ class core_course_external extends external_api {
                                          '"parent" (int) the parent category id,'.
                                          '"idnumber" (string) category idnumber'.
                                          ' - user must have \'moodle/category:manage\' to search on idnumber,'.
-                                         '"visible" (int) whether the category is visible or not'.
+                                         '"visible" (int) whether the returned categories must be visible or hidden. If the key is not passed,
+                                             then the function return all categories that the user can see.'.
                                          ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
-                                         '"theme" (string) category theme'.
+                                         '"theme" (string) only return the categories having this theme'.
                                          ' - user must have \'moodle/category:manage\' to search on theme'),
                             'value' => new external_value(PARAM_RAW, 'the value to match')
                         )
@@ -1017,10 +1018,22 @@ class core_course_external extends external_api {
                 if ($categories and !empty($params['addsubcategories'])) {
                     $newcategories = array();
 
+                    // Check if we required visible/theme checks.
+                    $additionalselect = '';
+                    $additionalparams = array();
+                    if (isset($conditions['visible'])) {
+                        $additionalselect .= ' AND visible = :visible';
+                        $additionalparams['visible'] = $conditions['visible'];
+                    }
+                    if (isset($conditions['theme'])) {
+                        $additionalselect .= ' AND theme= :theme';
+                        $additionalparams['theme'] = $conditions['theme'];
+                    }
+
                     foreach ($categories as $category) {
-                        $sqllike = $DB->sql_like('path', ':path');
-                        $sqlparams = array('path' => $category->path.'/%'); // It will NOT include the specified category.
-                        $subcategories = $DB->get_records_select('course_categories', $sqllike, $sqlparams);
+                        $sqlselect = $DB->sql_like('path', ':path') . $additionalselect;
+                        $sqlparams = array('path' => $category->path.'/%') + $additionalparams; // It will NOT include the specified category.
+                        $subcategories = $DB->get_records_select('course_categories', $sqlselect, $sqlparams);
                         $newcategories = $newcategories + $subcategories;   // Both arrays have integer as keys.
                     }
                     $categories = $categories + $newcategories;
-- 
1.7.9.5


From 08641906e1078b0b969ece435ae843d819132785 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Wed, 27 Jun 2012 16:24:22 +0800
Subject: [PATCH 042/903] MDL-33995 Course external PHPunit test +
 externallib_testcase helper class

---
 course/tests/externallib_test.php |  570 +++++++++++++++++++++++++++++++++++++
 webservice/tests/helpers.php      |   82 ++++++
 2 files changed, 652 insertions(+)
 create mode 100644 course/tests/externallib_test.php
 create mode 100644 webservice/tests/helpers.php

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
new file mode 100644
index 0000000..c28a479
--- /dev/null
+++ b/course/tests/externallib_test.php
@@ -0,0 +1,570 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * External course functions unit tests
+ *
+ * @package    core_course
+ * @category   external
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+
+/**
+ * External course functions unit tests
+ *
+ * @package    core_course
+ * @category   external
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_course_external_testcase extends externallib_testcase {
+
+    /**
+     * Tests set up
+     */
+    protected function setUp() {
+        global $CFG;
+        require_once($CFG->dirroot . '/course/externallib.php');
+    }
+
+    /**
+     * Test create_categories
+     */
+    public function test_create_categories() {
+
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Set the required capabilities by the external function
+        $contextid = context_system::instance()->id;
+        $roleid = $this->assignUserCapability('moodle/category:manage', $contextid);
+
+        // Create base categories.
+        $category1 = new stdClass();
+        $category1->name = 'Root Test Category 1';
+        $category2 = new stdClass();
+        $category2->name = 'Root Test Category 2';
+        $category2->idnumber = 'rootcattest2';
+        $category2->desc = 'Description for root test category 1';
+        $category2->theme = 'base';
+        $categories = array(
+            array('name' => $category1->name, 'parent' => 0),
+            array('name' => $category2->name, 'parent' => 0, 'idnumber' => $category2->idnumber,
+                'description' => $category2->desc, 'theme' => $category2->theme)
+        );
+
+        $createdcats = core_course_external::create_categories($categories);
+
+        // Initially confirm that base data was inserted correctly.
+        $this->assertEquals($category1->name, $createdcats[0]['name']);
+        $this->assertEquals($category2->name, $createdcats[1]['name']);
+
+        // Save the ids.
+        $category1->id = $createdcats[0]['id'];
+        $category2->id = $createdcats[1]['id'];
+
+        // Create on sub category.
+        $category3 = new stdClass();
+        $category3->name = 'Sub Root Test Category 3';
+        $subcategories = array(
+            array('name' => $category3->name, 'parent' => $category1->id)
+        );
+
+        $createdsubcats = core_course_external::create_categories($subcategories);
+
+        // Confirm that sub categories were inserted correctly.
+        $this->assertEquals($category3->name, $createdsubcats[0]['name']);
+
+        // Save the ids.
+        $category3->id = $createdsubcats[0]['id'];
+
+        // Calling the ws function should provide a new sortorder to give category1,
+        // category2, category3. New course categories are ordered by id not name.
+        $category1 = $DB->get_record('course_categories', array('id' => $category1->id));
+        $category2 = $DB->get_record('course_categories', array('id' => $category2->id));
+        $category3 = $DB->get_record('course_categories', array('id' => $category3->id));
+
+        $this->assertGreaterThanOrEqual($category1->sortorder, $category3->sortorder);
+        $this->assertGreaterThanOrEqual($category2->sortorder, $category3->sortorder);
+
+        // Call without required capability
+        $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        $createdsubcats = core_course_external::create_categories($subcategories);
+
+    }
+
+    /**
+     * Test delete categories
+     */
+    public function test_delete_categories() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Set the required capabilities by the external function
+        $contextid = context_system::instance()->id;
+        $roleid = $this->assignUserCapability('moodle/category:manage', $contextid);
+
+        $category1  = self::getDataGenerator()->create_category();
+        $category2  = self::getDataGenerator()->create_category(
+                array('parent' => $category1->id));
+        $category3  = self::getDataGenerator()->create_category();
+        $category4  = self::getDataGenerator()->create_category(
+                array('parent' => $category3->id));
+        $category5  = self::getDataGenerator()->create_category(
+                array('parent' => $category4->id));
+
+        //delete category 1 and 2 + delete category 4, category 5 moved under category 3
+        core_course_external::delete_categories(array(
+            array('id' => $category1->id, 'recursive' => 1),
+            array('id' => $category4->id)
+        ));
+
+        //check $category 1 and 2 are deleted
+        $notdeletedcount = $DB->count_records_select('course_categories',
+            'id IN ( ' . $category1->id . ',' . $category2->id . ',' . $category4->id . ')');
+        $this->assertEquals(0, $notdeletedcount);
+
+        //check that $category5 as $category3 for parent
+        $dbcategory5 = $DB->get_record('course_categories', array('id' => $category5->id));
+        $this->assertEquals($dbcategory5->path, $category3->path . '/' . $category5->id);
+
+         // Call without required capability
+        $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        $createdsubcats = core_course_external::delete_categories(
+                array(array('id' => $category3->id)));
+    }
+
+    /**
+     * Test get categories
+     */
+    public function test_get_categories() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+        $category1data['idnumber'] = 'idnumbercat1';
+        $category1data['name'] = 'Category 1 for PHPunit test';
+        $category1data['description'] = 'Category 1 description';
+        $category1data['descriptionformat'] = FORMAT_MOODLE;
+        $category1  = self::getDataGenerator()->create_category($category1data);
+        $category2  = self::getDataGenerator()->create_category(
+                array('parent' => $category1->id));
+        $category6  = self::getDataGenerator()->create_category(
+                array('parent' => $category1->id, 'visible' => 0));
+        $category3  = self::getDataGenerator()->create_category();
+        $category4  = self::getDataGenerator()->create_category(
+                array('parent' => $category3->id));
+        $category5  = self::getDataGenerator()->create_category(
+                array('parent' => $category4->id));
+
+        // Set the required capabilities by the external function.
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/category:manage', $context->id);
+
+        // Retrieve category1 + sub-categories except not visible ones
+        $categories = core_course_external::get_categories(array(
+            array('key' => 'id', 'value' => $category1->id),
+            array('key' => 'visible', 'value' => 1)), 1);
+
+        // Check we retrieve the good total number of categories.
+        $this->assertEquals(2, count($categories));
+
+        // Check the return values
+        $this->assertEquals($categories[0]['id'], $category1->id);
+        $this->assertEquals($categories[0]['idnumber'], $category1->idnumber);
+        $this->assertEquals($categories[0]['name'], $category1->name);
+        $this->assertEquals($categories[0]['description'], $category1->description);
+        $this->assertEquals($categories[0]['descriptionformat'], FORMAT_HTML);
+
+        // Check different params.
+        $categories = core_course_external::get_categories(array(
+            array('key' => 'id', 'value' => $category1->id),
+            array('key' => 'idnumber', 'value' => $category1->idnumber),
+            array('key' => 'visible', 'value' => 1)), 0);
+        $this->assertEquals(1, count($categories));
+
+        // Retrieve categories from parent.
+        $categories = core_course_external::get_categories(array(
+            array('key' => 'parent', 'value' => $category3->id)), 1);
+        $this->assertEquals(2, count($categories));
+
+        // Retrieve all categories.
+        $categories = core_course_external::get_categories();
+        $this->assertEquals($DB->count_records('course_categories'), count($categories));
+
+        // Call without required capability (it will fail cause of the search on idnumber).
+        $this->unassignUserCapability('moodle/category:manage', $context->id, $roleid);
+        $this->setExpectedException('moodle_exception');
+        $categories = core_course_external::get_categories(array(
+            array('key' => 'id', 'value' => $category1->id),
+            array('key' => 'idnumber', 'value' => $category1->idnumber),
+            array('key' => 'visible', 'value' => 1)), 0);
+    }
+
+    /**
+     * Test update_categories
+     */
+    public function test_update_categories() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Set the required capabilities by the external function
+        $contextid = context_system::instance()->id;
+        $roleid = $this->assignUserCapability('moodle/category:manage', $contextid);
+
+        // Create base categories.
+        $category1data['idnumber'] = 'idnumbercat1';
+        $category1data['name'] = 'Category 1 for PHPunit test';
+        $category1data['description'] = 'Category 1 description';
+        $category1data['descriptionformat'] = FORMAT_MOODLE;
+        $category1  = self::getDataGenerator()->create_category($category1data);
+        $category2  = self::getDataGenerator()->create_category(
+                array('parent' => $category1->id));
+        $category3  = self::getDataGenerator()->create_category();
+        $category4  = self::getDataGenerator()->create_category(
+                array('parent' => $category3->id));
+        $category5  = self::getDataGenerator()->create_category(
+                array('parent' => $category4->id));
+
+        // We update all category1 attribut.
+        // Then we move cat4 and cat5 parent: cat3 => cat1
+        $categories = array(
+            array('id' => $category1->id,
+                'name' => $category1->name . '_updated',
+                'idnumber' => $category1->idnumber . '_updated',
+                'description' => $category1->description . '_updated',
+                'descriptionformat' => FORMAT_HTML,
+                'theme' => $category1->theme),
+            array('id' => $category4->id, 'parent' => $category1->id));
+
+        core_course_external::update_categories($categories);
+
+        // Check the values were updated.
+        $dbcategories = $DB->get_records_select('course_categories',
+                'id IN (' . $category1->id . ',' . $category2->id . ',' . $category2->id
+                . ',' . $category3->id . ',' . $category4->id . ',' . $category5->id .')');
+        $this->assertEquals($category1->name . '_updated',
+                $dbcategories[$category1->id]->name);
+        $this->assertEquals($category1->idnumber . '_updated',
+                $dbcategories[$category1->id]->idnumber);
+        $this->assertEquals($category1->description . '_updated',
+                $dbcategories[$category1->id]->description);
+        $this->assertEquals(FORMAT_HTML, $dbcategories[$category1->id]->descriptionformat);
+
+        // Check that category4 and category5 have been properly moved.
+        $this->assertEquals('/' . $category1->id . '/' . $category4->id,
+                $dbcategories[$category4->id]->path);
+        $this->assertEquals('/' . $category1->id . '/' . $category4->id . '/' . $category5->id,
+                $dbcategories[$category5->id]->path);
+
+        // Call without required capability.
+        $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        core_course_external::update_categories($categories);
+    }
+
+    /**
+     * Test create_courses
+     */
+    public function test_create_courses() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Set the required capabilities by the external function
+        $contextid = context_system::instance()->id;
+        $roleid = $this->assignUserCapability('moodle/course:create', $contextid);
+        $this->assignUserCapability('moodle/course:visibility', $contextid, $roleid);
+
+        $category  = self::getDataGenerator()->create_category();
+
+        // Create base categories.
+        $course1['fullname'] = 'Test course 1';
+        $course1['shortname'] = 'Testcourse1';
+        $course1['categoryid'] = $category->id;
+        $course2['fullname'] = 'Test course 2';
+        $course2['shortname'] = 'Testcourse2';
+        $course2['categoryid'] = $category->id;
+        $course2['idnumber'] = 'testcourse2idnumber';
+        $course2['summary'] = 'Description for course 2';
+        $course2['summaryformat'] = FORMAT_MOODLE;
+        $course2['format'] = 'weeks';
+        $course2['showgrades'] = 1;
+        $course2['newsitems'] = 3;
+        $course2['startdate'] = 32882306400; // 01/01/3012
+        $course2['numsections'] = 4;
+        $course2['maxbytes'] = 100000;
+        $course2['showreports'] = 1;
+        $course2['visible'] = 0;
+        $course2['hiddensections'] = 0;
+        $course2['groupmode'] = 0;
+        $course2['groupmodeforce'] = 0;
+        $course2['defaultgroupingid'] = 0;
+        $course2['enablecompletion'] = 1;
+        $course2['completionstartonenrol'] = 1;
+        $course2['completionnotify'] = 1;
+        $course2['lang'] = 'en';
+        $course2['forcetheme'] = 'base';
+        $courses = array($course1, $course2);
+
+        $createdcourses = core_course_external::create_courses($courses);
+
+        // Check that right number of courses were created.
+        $this->assertEquals(2, count($createdcourses));
+
+        // Check that the courses were correctly created.
+        foreach ($createdcourses as $createdcourse) {
+            $dbcourse = $DB->get_record('course', array('id' => $createdcourse['id']));
+
+            if ($createdcourse['shortname'] == $course2['shortname']) {
+                $this->assertEquals($dbcourse->fullname, $course2['fullname']);
+                $this->assertEquals($dbcourse->shortname, $course2['shortname']);
+                $this->assertEquals($dbcourse->category, $course2['categoryid']);
+                $this->assertEquals($dbcourse->idnumber, $course2['idnumber']);
+                $this->assertEquals($dbcourse->summary, $course2['summary']);
+                $this->assertEquals($dbcourse->summaryformat, $course2['summaryformat']);
+                $this->assertEquals($dbcourse->format, $course2['format']);
+                $this->assertEquals($dbcourse->showgrades, $course2['showgrades']);
+                $this->assertEquals($dbcourse->newsitems, $course2['newsitems']);
+                $this->assertEquals($dbcourse->startdate, $course2['startdate']);
+                $this->assertEquals($dbcourse->numsections, $course2['numsections']);
+                $this->assertEquals($dbcourse->maxbytes, $course2['maxbytes']);
+                $this->assertEquals($dbcourse->showreports, $course2['showreports']);
+                $this->assertEquals($dbcourse->visible, $course2['visible']);
+                $this->assertEquals($dbcourse->hiddensections, $course2['hiddensections']);
+                $this->assertEquals($dbcourse->groupmode, $course2['groupmode']);
+                $this->assertEquals($dbcourse->groupmodeforce, $course2['groupmodeforce']);
+                $this->assertEquals($dbcourse->defaultgroupingid, $course2['defaultgroupingid']);
+                $this->assertEquals($dbcourse->completionnotify, $course2['completionnotify']);
+                $this->assertEquals($dbcourse->lang, $course2['lang']);
+
+                if (!empty($CFG->allowcoursethemes)) {
+                    $this->assertEquals($dbcourse->theme, $course2['forcetheme']);
+                }
+
+                if (completion_info::is_enabled_for_site()) {
+                    $this->assertEquals($dbcourse->enablecompletion, $course2['enabledcompletion']);
+                    $this->assertEquals($dbcourse->completionstartonenrol, $course2['completionstartonenrol']);
+                } else {
+                    $this->assertEquals($dbcourse->enablecompletion, 0);
+                    $this->assertEquals($dbcourse->completionstartonenrol, 0);
+                }
+
+            } else if ($createdcourse['shortname'] == $course1['shortname']) {
+                $courseconfig = get_config('moodlecourse');
+                $this->assertEquals($dbcourse->fullname, $course1['fullname']);
+                $this->assertEquals($dbcourse->shortname, $course1['shortname']);
+                $this->assertEquals($dbcourse->category, $course1['categoryid']);
+                $this->assertEquals($dbcourse->summaryformat, FORMAT_HTML);
+                $this->assertEquals($dbcourse->format, $courseconfig->format);
+                $this->assertEquals($dbcourse->showgrades, $courseconfig->showgrades);
+                $this->assertEquals($dbcourse->newsitems, $courseconfig->newsitems);
+                $this->assertEquals($dbcourse->numsections, $courseconfig->numsections);
+                $this->assertEquals($dbcourse->maxbytes, $courseconfig->maxbytes);
+                $this->assertEquals($dbcourse->showreports, $courseconfig->showreports);
+                $this->assertEquals($dbcourse->hiddensections, $courseconfig->hiddensections);
+                $this->assertEquals($dbcourse->groupmode, $courseconfig->groupmode);
+                $this->assertEquals($dbcourse->groupmodeforce, $courseconfig->groupmodeforce);
+                $this->assertEquals($dbcourse->defaultgroupingid, 0);
+            } else {
+                throw moodle_exception('Unexpected shortname');
+            }
+        }
+
+        // Call without required capability
+        $this->unassignUserCapability('moodle/course:create', $contextid, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        $createdsubcats = core_course_external::create_courses($courses);
+    }
+
+    /**
+     * Test delete_courses
+     */
+    public function test_delete_courses() {
+        global $DB, $USER;
+
+        $this->resetAfterTest(true);
+
+        // Admin can delete a course.
+        $this->setAdminUser();
+        // Validate_context() will fail as the email is not set by $this->setAdminUser().
+        $USER->email = 'emailtopass@contextvalidation.me';
+
+        $course1  = self::getDataGenerator()->create_course();
+        $course2  = self::getDataGenerator()->create_course();
+        $course3  = self::getDataGenerator()->create_course();
+
+        // Delete courses.
+        core_course_external::delete_courses(array($course1->id, $course2->id));
+
+        // Check $course 1 and 2 are deleted.
+        $notdeletedcount = $DB->count_records_select('course',
+            'id IN ( ' . $course1->id . ',' . $course2->id . ')');
+        $this->assertEquals(0, $notdeletedcount);
+
+         // Fail when the user is not allow to access the course (enrolled) or is not admin.
+        $this->setGuestUser();
+        $this->setExpectedException('require_login_exception');
+        $createdsubcats = core_course_external::delete_courses(array($course3->id));
+    }
+
+    /**
+     * Test get_courses
+     */
+    public function test_get_courses () {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        $coursedata['idnumber'] = 'idnumbercourse1';
+        $coursedata['fullname'] = 'Course 1 for PHPunit test';
+        $coursedata['summary'] = 'Course 1 description';
+        $coursedata['summaryformat'] = FORMAT_MOODLE;
+        $course1  = self::getDataGenerator()->create_course($coursedata);
+        $course2  = self::getDataGenerator()->create_course();
+        $course3  = self::getDataGenerator()->create_course();
+
+        // Set the required capabilities by the external function.
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
+        $this->assignUserCapability('moodle/course:update',
+                context_course::instance($course1->id)->id, $roleid);
+        $this->assignUserCapability('moodle/course:update',
+                context_course::instance($course2->id)->id, $roleid);
+        $this->assignUserCapability('moodle/course:update',
+                context_course::instance($course3->id)->id, $roleid);
+
+        $courses = core_course_external::get_courses(array('ids' =>
+            array($course1->id, $course2->id)));
+
+        // Check we retrieve the good total number of categories.
+        $this->assertEquals(2, count($courses));
+
+        // Check the return values for course 1
+        $dbcourse = $DB->get_record('course', array('id' => $course1->id));
+        $this->assertEquals($courses[0]['id'], $dbcourse->id);
+        $this->assertEquals($courses[0]['idnumber'], $coursedata['idnumber']);
+        $this->assertEquals($courses[0]['fullname'], $coursedata['fullname']);
+        $this->assertEquals($courses[0]['summary'], $coursedata['summary']);
+        $this->assertEquals($courses[0]['summaryformat'], FORMAT_HTML);
+        $this->assertEquals($courses[0]['shortname'], $dbcourse->shortname);
+        $this->assertEquals($courses[0]['categoryid'], $dbcourse->category);
+        $this->assertEquals($courses[0]['format'], $dbcourse->format);
+        $this->assertEquals($courses[0]['showgrades'], $dbcourse->showgrades);
+        $this->assertEquals($courses[0]['newsitems'], $dbcourse->newsitems);
+        $this->assertEquals($courses[0]['startdate'], $dbcourse->startdate);
+        $this->assertEquals($courses[0]['numsections'], $dbcourse->numsections);
+        $this->assertEquals($courses[0]['maxbytes'], $dbcourse->maxbytes);
+        $this->assertEquals($courses[0]['showreports'], $dbcourse->showreports);
+        $this->assertEquals($courses[0]['visible'], $dbcourse->visible);
+        $this->assertEquals($courses[0]['hiddensections'], $dbcourse->hiddensections);
+        $this->assertEquals($courses[0]['groupmode'], $dbcourse->groupmode);
+        $this->assertEquals($courses[0]['groupmodeforce'], $dbcourse->groupmodeforce);
+        $this->assertEquals($courses[0]['defaultgroupingid'], $dbcourse->defaultgroupingid);
+        $this->assertEquals($courses[0]['completionnotify'], $dbcourse->completionnotify);
+        $this->assertEquals($courses[0]['lang'], $dbcourse->lang);
+        $this->assertEquals($courses[0]['forcetheme'], $dbcourse->theme);
+        $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
+        $this->assertEquals($courses[0]['enablecompletion'], $dbcourse->enablecompletion);
+        $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
+
+        // Get all courses in the DB
+        $courses = core_course_external::get_courses(array());
+        $this->assertEquals($DB->count_records('course'), count($courses));
+    }
+
+    /**
+     * Test get_course_contents
+     */
+    public function test_get_course_contents() {
+        $this->resetAfterTest(true);
+
+        $course  = self::getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id));
+        $forumcm = get_coursemodule_from_id('forum', $forum->cmid);
+        $forumcontext = context_module::instance($forum->cmid);
+        $data = $this->getDataGenerator()->create_module('data', array('assessed'=>1, 'scale'=>100, 'course'=>$course->id));
+        $datacontext = context_module::instance($data->cmid);
+        $datacm = get_coursemodule_from_instance('page', $data->id);
+        $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
+        $pagecontext = context_module::instance($page->cmid);
+        $pagecm = get_coursemodule_from_instance('page', $page->id);
+
+        // Set the required capabilities by the external function.
+        $context = context_course::instance($course->id);
+        $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
+        $this->assignUserCapability('moodle/course:update', $context->id, $roleid);
+
+        $courses = core_course_external::get_course_contents($course->id, array());
+
+        // Check that the course has the 3 created modules
+        $this->assertEquals(3, count($courses[0]['modules']));
+    }
+
+    /**
+     * Test duplicate_course
+     */
+    public function test_duplicate_course() {
+        $this->resetAfterTest(true);
+
+        // Create one course with three modules.
+        $course  = self::getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id));
+        $forumcm = get_coursemodule_from_id('forum', $forum->cmid);
+        $forumcontext = context_module::instance($forum->cmid);
+        $data = $this->getDataGenerator()->create_module('data', array('assessed'=>1, 'scale'=>100, 'course'=>$course->id));
+        $datacontext = context_module::instance($data->cmid);
+        $datacm = get_coursemodule_from_instance('page', $data->id);
+        $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
+        $pagecontext = context_module::instance($page->cmid);
+        $pagecm = get_coursemodule_from_instance('page', $page->id);
+
+        // Set the required capabilities by the external function.
+        $coursecontext = context_course::instance($course->id);
+        $categorycontext = context_coursecat::instance($course->category);
+        $roleid = $this->assignUserCapability('moodle/course:create', $categorycontext->id);
+        $this->assignUserCapability('moodle/course:view', $categorycontext->id, $roleid);
+        $this->assignUserCapability('moodle/restore:restorecourse', $categorycontext->id, $roleid);
+        $this->assignUserCapability('moodle/backup:backupcourse', $coursecontext->id, $roleid);
+        $this->assignUserCapability('moodle/backup:configure', $coursecontext->id, $roleid);
+        // Optional capabilities to copy user data.
+        $this->assignUserCapability('moodle/backup:userinfo', $coursecontext->id, $roleid);
+        $this->assignUserCapability('moodle/restore:userinfo', $categorycontext->id, $roleid);
+
+        $newcourse['fullname'] = 'Course duplicate';
+        $newcourse['shortname'] = 'courseduplicate';
+        $newcourse['categoryid'] = $course->category;
+        $newcourse['visible'] = true;
+        $newcourse['options'][] = array('name' => 'users', 'value' => true);
+
+        $duplicate = core_course_external::duplicate_course($course->id, $newcourse['fullname'],
+                $newcourse['shortname'], $newcourse['categoryid'], $newcourse['visible'], $newcourse['options']);
+
+        // Check that the course has been duplicated.
+        $this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
+    }
+}
diff --git a/webservice/tests/helpers.php b/webservice/tests/helpers.php
new file mode 100644
index 0000000..3a67bf3
--- /dev/null
+++ b/webservice/tests/helpers.php
@@ -0,0 +1,82 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains helper classes for testing the web service and external files.
+ *
+ * @package    core_webservice
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Helper base class for external tests. Helpfull to test capabilities.
+ *
+ * @package    core_webservice
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class externallib_testcase extends advanced_testcase {
+
+    /**
+     * Assign a capability to $USER
+     * The function creates a student $USER if $USER->id is empty
+     *
+     * @param string $capability capability name
+     * @param int $contextid
+     * @param int $roleid
+     * @return int the role id - mainly returned for creation, so calling function can reuse it
+     */
+    public static function assignUserCapability($capability, $contextid, $roleid = null) {
+        global $USER;
+
+        // Create a new student $USER if $USER doesn't exist
+        if (empty($USER->id)) {
+            $user  = self::getDataGenerator()->create_user();
+            self::setUser($user);
+        }
+
+        if (empty($roleid)) {
+            $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
+        }
+
+        assign_capability($capability, CAP_ALLOW, $roleid, $contextid);
+
+        role_assign($roleid, $USER->id, $contextid);
+
+        accesslib_clear_all_caches_for_unit_testing();
+
+        return $roleid;
+    }
+
+    /**
+     * Unassign a capability to $USER
+     *
+     * @param string $capability capability name
+     * @param int $contextid
+     * @param int $roleid
+     */
+    public static function unassignUserCapability($capability, $contextid, $roleid) {
+        global $USER;
+
+        unassign_capability($capability, $roleid, $contextid);
+
+        accesslib_clear_all_caches_for_unit_testing();
+    }
+}
+
-- 
1.7.9.5


From 419aed3539f7d67539af736f42f786f76aabe74e Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 2 Jul 2012 14:26:15 +0800
Subject: [PATCH 043/903] MDL-29969 Administration: Default value for
 numsections is set to 1 for site frontpage

---
 lib/db/install.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/db/install.php b/lib/db/install.php
index b3e9aa2..787b871 100644
--- a/lib/db/install.php
+++ b/lib/db/install.php
@@ -72,7 +72,7 @@ function xmldb_main_install() {
     $newsite->shortname    = '';
     $newsite->summary      = NULL;
     $newsite->newsitems    = 3;
-    $newsite->numsections  = 0;
+    $newsite->numsections  = 1;
     $newsite->category     = 0;
     $newsite->format       = 'site';  // Only for this course
     $newsite->timecreated  = time();
-- 
1.7.9.5


From 45353da409e52521e68c3be61982a9b6f7986e97 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 28 Jun 2012 13:53:19 +0800
Subject: [PATCH 044/903] MDL-31987 Assignment module: Assignment count
 submissions correctly. For advanced upload
 assignment, store file count of each submission
 into assignment_submissions.numfiles

When counting submissions, if the assignment is open and tracking
drafts, only submissions which has send for marking are counted.
Otherwise, submissions which has numfiles > 0 are counted.

Also change a hardcoded 'submitted' to ASSIGNMENT_STATUS_SUBMITTED.

This patch was originally written by: Sunner Sun <sunner@gmail.com>.

I made some modifation to fixed count_real_submissions() query (ref: MDL-32207) in /mod/assignment/type/upload/assignment.class.php file
---
 mod/assignment/db/upgrade.php                   |   36 +++++++++++++++++++++++
 mod/assignment/type/upload/assignment.class.php |   17 +++++++----
 mod/assignment/version.php                      |    2 +-
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/mod/assignment/db/upgrade.php b/mod/assignment/db/upgrade.php
index d9c46ea..256bda9 100644
--- a/mod/assignment/db/upgrade.php
+++ b/mod/assignment/db/upgrade.php
@@ -32,6 +32,42 @@ function xmldb_assignment_upgrade($oldversion) {
     // Moodle v2.3.0 release upgrade line
     // Put any upgrade step following this
 
+    if ($oldversion < 2012062800) {
+        // Fixed/updated numfiles field in assignment_submissions table to count the actual
+        // number of files has been uploaded.
+        upgrade_set_timeout(600);  // increase excution time for in large sites
+        $fs = get_file_storage();
+
+        $selectcount = 'SELECT COUNT(s.id), cm.id AS cmid';
+        $select      = 'SELECT s.id, cm.id AS cmid';
+        $query       = "  FROM {assignment_submissions} s
+                    INNER JOIN {course_modules} cm
+                            ON s.assignment = cm.instance
+                          JOIN {assignment} a
+                            ON a.id = s.assignment
+                         WHERE a.assignmenttype in ('upload', 'uploadsingle') AND
+                               cm.module = (SELECT id
+                                              FROM {modules}
+                                             WHERE name = 'assignment')";
+
+        $countsubmissions = $DB->count_records_sql($selectcount. $query);
+        $submissions = $DB->get_recordset_sql($select. $query);
+
+        $pbar = new progress_bar('assignmentupgradenumfiles', 500, true);
+        $i = 0;
+        foreach ($submissions as $sub) {
+            $i++;
+            if ($context = context_module::instance($sub->cmid)) {
+                $sub->numfiles = count($fs->get_area_files($context->id, 'mod_assignment', 'submission', $sub->id, 'sortorder', false));
+                $DB->update_record('assignment_submissions', $sub);
+            }
+            $pbar->update($i, $countsubmissions, "Counting files of submissions ($i/$countsubmissions)");
+        }
+        $submissions->close();
+
+        // assignment savepoint reached
+        upgrade_mod_savepoint(true, 2012062800, 'assignment');
+    }
 
     return true;
 }
diff --git a/mod/assignment/type/upload/assignment.class.php b/mod/assignment/type/upload/assignment.class.php
index 6971120..83afeb4 100644
--- a/mod/assignment/type/upload/assignment.class.php
+++ b/mod/assignment/type/upload/assignment.class.php
@@ -395,8 +395,8 @@ class assignment_upload extends assignment_base {
 
     /**
      * Counts all complete (real) assignment submissions by enrolled students. This overrides assignment_base::count_real_submissions().
-     * This is necessary for advanced file uploads where we need to check that the data2 field is equal to "submitted" to determine
-     * if a submission is complete.
+     * This is necessary for tracked advanced file uploads where we need to check that the data2 field is equal to ASSIGNMENT_STATUS_SUBMITTED
+     * to determine if a submission is complete.
      *
      * @param  int $groupid (optional) If nonzero then count is restricted to this group
      * @return int          The number of submissions
@@ -411,13 +411,19 @@ class assignment_upload extends assignment_base {
         list($enroledsql, $params) = get_enrolled_sql($context, 'mod/assignment:view', $groupid);
         $params['assignmentid'] = $this->cm->instance;
 
-        // Get ids of users enrolled in the given course.
+        $query = '';
+        if ($this->drafts_tracked() and $this->isopen()) {
+            $query = ' AND ' . $DB->sql_compare_text('s.data2') . " = '"  . ASSIGNMENT_STATUS_SUBMITTED . "'";
+        } else {
+            // Count on submissions with files actually uploaded
+            $query = " AND s.numfiles > 0";
+        }
         return $DB->count_records_sql("SELECT COUNT('x')
                                          FROM {assignment_submissions} s
                                     LEFT JOIN {assignment} a ON a.id = s.assignment
                                    INNER JOIN ($enroledsql) u ON u.id = s.userid
-                                        WHERE s.assignment = :assignmentid AND
-                                              s.data2 = 'submitted'", $params);
+                                        WHERE s.assignment = :assignmentid" .
+                                              $query, $params);
     }
 
     function print_responsefiles($userid, $return=false) {
@@ -581,6 +587,7 @@ class assignment_upload extends assignment_base {
             $formdata = file_postupdate_standard_filemanager($formdata, 'files', $options, $this->context, 'mod_assignment', 'submission', $submission->id);
             $updates = new stdClass();
             $updates->id = $submission->id;
+            $updates->numfiles = count($fs->get_area_files($this->context->id, 'mod_assignment', 'submission', $submission->id, 'sortorder', false));
             $updates->timemodified = time();
             $DB->update_record('assignment_submissions', $updates);
             add_to_log($this->course->id, 'assignment', 'upload',
diff --git a/mod/assignment/version.php b/mod/assignment/version.php
index c7c7c2d..67a72be 100644
--- a/mod/assignment/version.php
+++ b/mod/assignment/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012062800;       // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700;    // Requires this Moodle version
 $module->component = 'mod_assignment'; // Full name of the plugin (used for diagnostics)
 $module->cron      = 60;
-- 
1.7.9.5


From fb978df0f070ffcdfdc44028a24c8f9fb3aa7a4d Mon Sep 17 00:00:00 2001
From: Dan Poltawski <talktodan@gmail.com>
Date: Thu, 28 Jun 2012 14:35:37 +0800
Subject: [PATCH 045/903] MDL-31987 Assignment module: fix sql for postgres.

---
 mod/assignment/db/upgrade.php |   30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/mod/assignment/db/upgrade.php b/mod/assignment/db/upgrade.php
index 256bda9..3f87985 100644
--- a/mod/assignment/db/upgrade.php
+++ b/mod/assignment/db/upgrade.php
@@ -34,24 +34,24 @@ function xmldb_assignment_upgrade($oldversion) {
 
     if ($oldversion < 2012062800) {
         // Fixed/updated numfiles field in assignment_submissions table to count the actual
-        // number of files has been uploaded.
+        // number of files has been uploaded when sendformarking is disabled
         upgrade_set_timeout(600);  // increase excution time for in large sites
         $fs = get_file_storage();
 
-        $selectcount = 'SELECT COUNT(s.id), cm.id AS cmid';
-        $select      = 'SELECT s.id, cm.id AS cmid';
-        $query       = "  FROM {assignment_submissions} s
-                    INNER JOIN {course_modules} cm
-                            ON s.assignment = cm.instance
-                          JOIN {assignment} a
-                            ON a.id = s.assignment
-                         WHERE a.assignmenttype in ('upload', 'uploadsingle') AND
-                               cm.module = (SELECT id
-                                              FROM {modules}
-                                             WHERE name = 'assignment')";
-
-        $countsubmissions = $DB->count_records_sql($selectcount. $query);
-        $submissions = $DB->get_recordset_sql($select. $query);
+        // Fetch the moduleid for use in the course_modules table
+        $moduleid = $DB->get_field('modules', 'id', array('name' => 'assignment'), MUST_EXIST);
+
+        $selectcount = 'SELECT COUNT(s.id) ';
+        $select      = 'SELECT s.id, cm.id AS cmid ';
+        $query       = 'FROM {assignment_submissions} s
+                        JOIN {assignment} a ON a.id = s.assignment
+                        JOIN {course_modules} cm ON a.id = cm.instance AND cm.module = :moduleid
+                        WHERE assignmenttype = :assignmenttype';
+
+        $params = array('moduleid' => $moduleid, 'assignmenttype' => 'upload');
+
+        $countsubmissions = $DB->count_records_sql($selectcount.$query, $params);
+        $submissions = $DB->get_recordset_sql($select.$query, $params);
 
         $pbar = new progress_bar('assignmentupgradenumfiles', 500, true);
         $i = 0;
-- 
1.7.9.5


From 4b0e6f38fab70f9aa52371cd14b3043ee20f7562 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 2 Jul 2012 14:51:47 +0800
Subject: [PATCH 046/903] MDL-31987 Assignment module: fixed upgrade version

---
 mod/assignment/db/upgrade.php |    4 ++--
 mod/assignment/version.php    |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mod/assignment/db/upgrade.php b/mod/assignment/db/upgrade.php
index 3f87985..aa605cc 100644
--- a/mod/assignment/db/upgrade.php
+++ b/mod/assignment/db/upgrade.php
@@ -32,7 +32,7 @@ function xmldb_assignment_upgrade($oldversion) {
     // Moodle v2.3.0 release upgrade line
     // Put any upgrade step following this
 
-    if ($oldversion < 2012062800) {
+    if ($oldversion < 2012061701) {
         // Fixed/updated numfiles field in assignment_submissions table to count the actual
         // number of files has been uploaded when sendformarking is disabled
         upgrade_set_timeout(600);  // increase excution time for in large sites
@@ -66,7 +66,7 @@ function xmldb_assignment_upgrade($oldversion) {
         $submissions->close();
 
         // assignment savepoint reached
-        upgrade_mod_savepoint(true, 2012062800, 'assignment');
+        upgrade_mod_savepoint(true, 2012061701, 'assignment');
     }
 
     return true;
diff --git a/mod/assignment/version.php b/mod/assignment/version.php
index 67a72be..7d69e8f 100644
--- a/mod/assignment/version.php
+++ b/mod/assignment/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012062800;       // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700;    // Requires this Moodle version
 $module->component = 'mod_assignment'; // Full name of the plugin (used for diagnostics)
 $module->cron      = 60;
-- 
1.7.9.5


From c3f59e043c9a5134bb8b8906a86c853ebfefe788 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 2 Jul 2012 14:52:57 +0800
Subject: [PATCH 047/903] MDL-33995 - unit tests: fix class name collision

---
 course/tests/externallib_test.php |    2 +-
 webservice/tests/helpers.php      |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index c28a479..ac3c4d9 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -37,7 +37,7 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  * @copyright  2012 Jerome Mouneyrac
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class core_course_external_testcase extends externallib_testcase {
+class core_course_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Tests set up
diff --git a/webservice/tests/helpers.php b/webservice/tests/helpers.php
index 3a67bf3..161a1b7 100644
--- a/webservice/tests/helpers.php
+++ b/webservice/tests/helpers.php
@@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die();
  * @copyright  2012 Jerome Mouneyrac
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-abstract class externallib_testcase extends advanced_testcase {
+abstract class externallib_advanced_testcase extends advanced_testcase {
 
     /**
      * Assign a capability to $USER
-- 
1.7.9.5


From 564b878840fc82f0b920b06f2df9168044f3c1aa Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 29 Jun 2012 16:06:25 +0100
Subject: [PATCH 048/903] MDL-34054 quiz reports: missing context.

quiz_report_should_show_grades needs to know the context, so pass it
through.
---
 mod/quiz/report/attemptsreport_options.php |    2 +-
 mod/quiz/report/reportlib.php              |    5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/mod/quiz/report/attemptsreport_options.php b/mod/quiz/report/attemptsreport_options.php
index cca3d30..ffd4287 100644
--- a/mod/quiz/report/attemptsreport_options.php
+++ b/mod/quiz/report/attemptsreport_options.php
@@ -105,7 +105,7 @@ class mod_quiz_attempts_report_options {
         $this->cm     = $cm;
         $this->course = $course;
 
-        $this->usercanseegrades = quiz_report_should_show_grades($quiz);
+        $this->usercanseegrades = quiz_report_should_show_grades($quiz, context_module::instance($cm->id));
     }
 
     /**
diff --git a/mod/quiz/report/reportlib.php b/mod/quiz/report/reportlib.php
index 9bfa402..d3e4e99 100644
--- a/mod/quiz/report/reportlib.php
+++ b/mod/quiz/report/reportlib.php
@@ -401,9 +401,10 @@ function quiz_no_questions_message($quiz, $cm, $context) {
  * Should the grades be displayed in this report. That depends on the quiz
  * display options, and whether the quiz is graded.
  * @param object $quiz the quiz settings.
+ * @param context $context the quiz context.
  * @return bool
  */
-function quiz_report_should_show_grades($quiz) {
+function quiz_report_should_show_grades($quiz, context $context) {
     if ($quiz->timeclose && time() > $quiz->timeclose) {
         $when = mod_quiz_display_options::AFTER_CLOSE;
     } else {
@@ -413,5 +414,5 @@ function quiz_report_should_show_grades($quiz) {
 
     return quiz_has_grades($quiz) &&
             ($reviewoptions->marks >= question_display_options::MARK_AND_MAX ||
-            has_capability('moodle/grade:viewhidden', $this->context));
+            has_capability('moodle/grade:viewhidden', $context));
 }
-- 
1.7.9.5


From a8380712bb8b6bbdb4a23629a171e7e757846949 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 2 Jul 2012 15:15:58 +0800
Subject: [PATCH 049/903] MDL-33943 tool_replace: Hardcoded strings replaced
 with lang strings

---
 admin/tool/replace/index.php                |   20 ++++++++++++--------
 admin/tool/replace/lang/en/tool_replace.php |   10 ++++++++++
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/admin/tool/replace/index.php b/admin/tool/replace/index.php
index 6f3c89f..11e1068 100644
--- a/admin/tool/replace/index.php
+++ b/admin/tool/replace/index.php
@@ -38,25 +38,29 @@ $sure    = optional_param('sure', 0, PARAM_BOOL);
 ###################################################################
 echo $OUTPUT->header();
 
-echo $OUTPUT->heading('Search and replace text throughout the whole database');
+echo $OUTPUT->heading(get_string('pageheader', 'tool_replace'));
 
 if ($DB->get_dbfamily() !== 'mysql' and $DB->get_dbfamily() !== 'postgres') {
     //TODO: add $DB->text_replace() to DML drivers
-    echo $OUTPUT->notification('Sorry, this feature is implemented only for MySQL and PostgreSQL databases.');
+    echo $OUTPUT->notification(get_string('notimplemented', 'tool_replace'));
     echo $OUTPUT->footer();
     die;
 }
 
 if (!data_submitted() or !$search or !$replace or !confirm_sesskey() or !$sure) {   /// Print a form
-    echo $OUTPUT->notification('This script is not supported, always make complete backup before proceeding!<br />This operation can not be reverted!');
+    echo $OUTPUT->notification(get_string('notsupported', 'tool_replace'));
 
     echo $OUTPUT->box_start();
     echo '<div class="mdl-align">';
     echo '<form action="index.php" method="post"><div>';
     echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
-    echo '<div><label for="search">Search whole database for: </label><input id="search" type="text" name="search" size="40" /> (usually previous server URL)</div>';
-    echo '<div><label for="replace">Replace with this string: </label><input type="text" id="replace" name="replace" size="40" /> (usually new server URL)</div>';
-    echo '<div><label for="sure">I understand the risks of this operation: </label><input type="checkbox" id="sure" name="sure" value="1" /></div>';
+    echo '<div><label for="search">'.get_string('searchwholedb', 'tool_replace').
+            ' </label><input id="search" type="text" name="search" size="40" /> ('.
+            get_string('searchwholedbhelp', 'tool_replace').')</div>';
+    echo '<div><label for="replace">'.get_string('replacewith', 'tool_replace').
+            ' </label><input type="text" id="replace" name="replace" size="40" /> ('.
+            get_string('replacewithhelp', 'tool_replace').')</div>';
+    echo '<div><label for="sure">'.get_string('disclaimer', 'tool_replace').' </label><input type="checkbox" id="sure" name="sure" value="1" /></div>';
     echo '<div class="buttons"><input type="submit" class="singlebutton" value="Yes, do it now" /></div>';
     echo '</div></form>';
     echo '</div>';
@@ -70,9 +74,9 @@ db_replace($search, $replace);
 echo $OUTPUT->box_end();
 
 /// Rebuild course cache which might be incorrect now
-echo $OUTPUT->notification('Rebuilding course cache...', 'notifysuccess');
+echo $OUTPUT->notification(get_string('notifyrebuilding', 'tool_replace'), 'notifysuccess');
 rebuild_course_cache();
-echo $OUTPUT->notification('...finished', 'notifysuccess');
+echo $OUTPUT->notification(get_string('notifyfinished', 'tool_replace'), 'notifysuccess');
 
 echo $OUTPUT->continue_button(new moodle_url('/admin/index.php'));
 
diff --git a/admin/tool/replace/lang/en/tool_replace.php b/admin/tool/replace/lang/en/tool_replace.php
index f967fad..2193805 100644
--- a/admin/tool/replace/lang/en/tool_replace.php
+++ b/admin/tool/replace/lang/en/tool_replace.php
@@ -23,4 +23,14 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['disclaimer'] = 'I understand the risks of this operation:';
+$string['pageheader'] = 'Search and replace text throughout the whole database';
+$string['notifyfinished'] = '...finished';
+$string['notifyrebuilding'] = 'Rebuilding course cache...';
+$string['notimplemented'] = 'Sorry, this feature is implemented only for MySQL and PostgreSQL databases.';
+$string['notsupported'] ='This script is not supported, always make complete backup before proceeding!<br />This operation can not be reverted!';
 $string['pluginname'] = 'DB search and replace';
+$string['replacewith'] = 'Replace with this string:';
+$string['replacewithhelp'] = 'usually new server URL';
+$string['searchwholedb'] = 'Search whole database for:';
+$string['searchwholedbhelp'] = 'usually previous server URL';
\ No newline at end of file
-- 
1.7.9.5


From a6b0b36cdcf3a98684e57439823fc7d27a3a774b Mon Sep 17 00:00:00 2001
From: Mark Nielsen <mark@moodlerooms.com>
Date: Tue, 26 Jun 2012 17:56:11 +0800
Subject: [PATCH 050/903] fixed undefined variable

---
 mod/survey/view.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/survey/view.php b/mod/survey/view.php
index 6eb9551..8fe6a48 100644
--- a/mod/survey/view.php
+++ b/mod/survey/view.php
@@ -122,7 +122,7 @@ $completion->set_module_viewed($cm);
                         $table->align = array ("left");
                         $table->data[] = array(s($answer->answer1));//no html here, just plain text
                         echo html_writer::table($table);
-                        echo $OUTPUT->spacer(clone($spacer)) . '<br />';
+                        echo $OUTPUT->spacer(array('height'=>30, 'width'=>1), true);
                     }
                 }
             }
-- 
1.7.9.5


From ec70cf6ef1d47599955d935f30a13be8a5ab330b Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 26 Jun 2012 18:08:46 +0800
Subject: [PATCH 051/903] fixed the ->spacer <br> param

---
 mod/survey/view.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/survey/view.php b/mod/survey/view.php
index 8fe6a48..cfb421a 100644
--- a/mod/survey/view.php
+++ b/mod/survey/view.php
@@ -109,7 +109,7 @@ $completion->set_module_viewed($cm);
         } else {
 
             echo $OUTPUT->box(format_module_intro('survey', $survey, $cm->id), 'generalbox', 'intro');
-            echo $OUTPUT->spacer(array('height'=>30, 'width'=>1, 'br'=>true)); // should be done with CSS instead
+            echo $OUTPUT->spacer(array('height'=>30, 'width'=>1), true);  // should be done with CSS instead
 
             $questions = $DB->get_records_list("survey_questions", "id", explode(',', $survey->questions));
             $questionorder = explode(",", $survey->questions);
-- 
1.7.9.5


From d9b9bfd2889452b0a07ce3bf27e3e79c4b83d0fc Mon Sep 17 00:00:00 2001
From: Kanika Goyal <kanikagoyal999@gmail.com>
Date: Sat, 31 Mar 2012 18:51:16 +0530
Subject: [PATCH 052/903] MDL-31203 mod_forum: advanced search posts must be
 newer older than date, reverts date

---
 mod/forum/search.php |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/mod/forum/search.php b/mod/forum/search.php
index daa7bdc..ebbc99f 100644
--- a/mod/forum/search.php
+++ b/mod/forum/search.php
@@ -369,11 +369,11 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timetorestrict" type="checkbox" value="1" alt="'.get_string('searchdateto', 'forum').'" onclick="return lockoptions(\'searchform\', \'timetorestrict\', timetoitems)" ' .$datetochecked. ' /> ';
-    $selectors = html_writer::select_time('days', 'fromday', $dateto)
-               . html_writer::select_time('months', 'frommonth', $dateto)
-               . html_writer::select_time('years', 'fromyear', $dateto)
-               . html_writer::select_time('hours', 'fromhour', $dateto)
-               . html_writer::select_time('minutes', 'fromminute', $dateto);
+    $selectors = html_writer::select_time('days', 'today', $dateto)
+               . html_writer::select_time('months', 'tomonth', $dateto)
+               . html_writer::select_time('years', 'toyear', $dateto)
+               . html_writer::select_time('hours', 'tohour', $dateto)
+               . html_writer::select_time('minutes', 'tominute', $dateto);
     echo $selectors;
 
     echo '<input type="hidden" name="htoday" value="0" />';
-- 
1.7.9.5


From c7132d7c939e24143702b3b21450918b038e0d7a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 17 May 2012 16:46:54 +0800
Subject: [PATCH 053/903] MDL-9073 Glossary: uncategorised entries are
 printable

---
 mod/glossary/print.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/glossary/print.php b/mod/glossary/print.php
index 8421481..d0d08aa 100644
--- a/mod/glossary/print.php
+++ b/mod/glossary/print.php
@@ -11,7 +11,7 @@ $offset        = optional_param('offset', 0, PARAM_INT);              // number
 $displayformat = optional_param('displayformat',-1, PARAM_INT);
 
 $mode    = required_param('mode', PARAM_ALPHA);             // mode to show the entries
-$hook    = optional_param('hook','ALL', PARAM_ALPHANUM);   // what to show
+$hook    = optional_param('hook','ALL', PARAM_CLEAN);       // what to show
 $sortkey = optional_param('sortkey','UPDATE', PARAM_ALPHA); // Sorting key
 
 $url = new moodle_url('/mod/glossary/print.php', array('id'=>$id));
-- 
1.7.9.5


From 6737eda4261fd5de66850a5337cf033698e4e795 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 26 Jun 2012 11:44:56 +0700
Subject: [PATCH 054/903] MDL-25476 messages: switched some notification
 emails to come from the support contact instead of
 admin

---
 enrol/self/lib.php |    2 +-
 lib/cronlib.php    |    2 +-
 user/edit.php      |    8 +++++---
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/enrol/self/lib.php b/enrol/self/lib.php
index 2e425a6..32c9d48 100644
--- a/enrol/self/lib.php
+++ b/enrol/self/lib.php
@@ -291,7 +291,7 @@ class enrol_self_plugin extends enrol_plugin {
         if ($rusers) {
             $contact = reset($rusers);
         } else {
-            $contact = get_admin();
+            $contact = generate_email_supportuser();
         }
 
         //directly emailing welcome message rather than using messaging
diff --git a/lib/cronlib.php b/lib/cronlib.php
index b034760..bcadaeb 100644
--- a/lib/cronlib.php
+++ b/lib/cronlib.php
@@ -709,7 +709,7 @@ function notify_login_failures() {
         mtrace('Emailing admins about '. $count .' failed login attempts');
         foreach ($recip as $admin) {
             //emailing the admins directly rather than putting these through the messaging system
-            email_to_user($admin,get_admin(), $subject, $body);
+            email_to_user($admin, generate_email_supportuser(), $subject, $body);
         }
     }
 
diff --git a/user/edit.php b/user/edit.php
index ca52ed3..b3cedb2 100644
--- a/user/edit.php
+++ b/user/edit.php
@@ -181,7 +181,8 @@ if ($usernew = $userform->get_data()) {
     $email_changed_html = '';
 
     if ($CFG->emailchangeconfirmation) {
-        // Handle change of email carefully for non-trusted users
+        // Users with 'moodle/user:update' can change their email address immediately
+        // Other users require a confirmation email
         if (isset($usernew->email) and $user->email != $usernew->email && !has_capability('moodle/user:update', $systemcontext)) {
             $a = new stdClass();
             $a->newemail = $usernew->preference_newemail = $usernew->email;
@@ -235,7 +236,7 @@ if ($usernew = $userform->get_data()) {
     // save custom profile fields data
     profile_save_data($usernew);
 
-    // If email was changed, send confirmation email now
+    // If email was changed and confirmation is required, send confirmation email now
     if ($email_changed && $CFG->emailchangeconfirmation) {
         $temp_user = fullclone($user);
         $temp_user->email = $usernew->preference_newemail;
@@ -249,7 +250,8 @@ if ($usernew = $userform->get_data()) {
         $emailupdatetitle = get_string('emailupdatetitle', 'auth', $a);
 
         //email confirmation directly rather than using messaging so they will definitely get an email
-        if (!$mail_results = email_to_user($temp_user, get_admin(), $emailupdatetitle, $emailupdatemessage)) {
+        $supportuser = generate_email_supportuser();
+        if (!$mail_results = email_to_user($temp_user, $supportuser, $emailupdatetitle, $emailupdatemessage)) {
             die("could not send email!");
         }
     }
-- 
1.7.9.5


From ed8cab855e8e85278fda13f398c08767ca62c059 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 26 Jun 2012 14:36:10 +0800
Subject: [PATCH 055/903] MDL-33721 show loading icon after file has been
 selected in filepicker, prevent clicking select
 button twice

---
 theme/base/style/filemanager.css |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 86d0446..9285edc 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -252,8 +252,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 
 .file-picker.fp-select .uneditable {display:none;}
 .file-picker.fp-select .fp-select-loading {display:none;}
-.file-picker .fp-select.loading .fp-select-loading {display:block;}
-.file-picker .fp-select.loading form {display:none;}
+.file-picker.fp-select.loading .fp-select-loading {display:block;}
+.file-picker.fp-select.loading form {display:none;}
 
  /*
  * File Manager
-- 
1.7.9.5


From 7debccbdee9f8157d320d1a637b1eccf5a376090 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 20 Jun 2012 11:48:24 +1200
Subject: [PATCH 056/903] MDL-33835 Marking Guide - set currentfocus var to
 the first criteria comment to avoid JS errors.

---
 grade/grading/form/guide/js/guide.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/grading/form/guide/js/guide.js b/grade/grading/form/guide/js/guide.js
index 783ee46..1f1cd90 100644
--- a/grade/grading/form/guide/js/guide.js
+++ b/grade/grading/form/guide/js/guide.js
@@ -4,7 +4,7 @@ M.gradingform_guide = {};
  * This function is called for each guide on page.
  */
 M.gradingform_guide.init = function(Y, options) {
-    var currentfocus = null;
+    var currentfocus = Y.one('.markingguideremark');
 
     Y.all('.markingguideremark').on('blur', function(e) {
         currentfocus = e.currentTarget;
-- 
1.7.9.5


From 0ba1ee1dd25cff09c292ea3ce5e34993d5a3f723 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Fri, 22 Jun 2012 22:16:25 +1200
Subject: [PATCH 057/903] MDL-33914 SCORM show scrollbar on TOC if too long.

---
 mod/scorm/styles.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/scorm/styles.css b/mod/scorm/styles.css
index ef37f94..16080c0 100644
--- a/mod/scorm/styles.css
+++ b/mod/scorm/styles.css
@@ -28,6 +28,7 @@
 #page-mod-scorm-player.pagelayout-popup #page-content .region-content {padding: 0px; }
 #page-mod-scorm-player.pagelayout-popup #page-wrapper {width:100%;}
 #page-mod-scorm-player .yui-layout-scroll div.yui-layout-bd {overflow:visible;}
+#page-mod-scorm-player .yui-layout-unit-left div.yui-layout-bd {overflow:auto;}
 
 .path-mod-scorm.forcejavascript .scorm-center { display:none;}
 .path-mod-scorm.forcejavascript .toc { display:none;}
-- 
1.7.9.5


From 41c548bb23c40e73daaab3b042b1dd6aecd1e8cf Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 2 Jul 2012 16:20:40 +0800
Subject: [PATCH 058/903] MDL-33030 Lesson module: fixed progress bar

---
 mod/lesson/renderer.php |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/mod/lesson/renderer.php b/mod/lesson/renderer.php
index fc1c99e..765b7ca 100644
--- a/mod/lesson/renderer.php
+++ b/mod/lesson/renderer.php
@@ -510,15 +510,20 @@ class mod_lesson_renderer extends plugin_renderer_base {
                 $ntries = 0;  // may not be necessary
             }
 
-
             $viewedpageids = array();
-            if ($attempts = $lesson->get_attempts($ntries, true)) {
-                $viewedpageids = array_merge($viewedpageids, array_keys($attempts));
+            if ($attempts = $lesson->get_attempts($ntries, false)) {
+                foreach($attempts as $attempt) {
+                    $viewedpageids[$attempt->pageid] = $attempt;
+                }
             }
 
+            $viewedbranches = array();
             // collect all of the branch tables viewed
-            if ($viewedbranches = $DB->get_records("lesson_branch", array ("lessonid"=>$lesson->id, "userid"=>$USER->id, "retry"=>$ntries), 'timeseen DESC', 'id, pageid')) {
-                $viewedpageids = array_merge($viewedpageids, array_keys($viewedbranches));
+            if ($branches = $DB->get_records("lesson_branch", array ("lessonid"=>$lesson->id, "userid"=>$USER->id, "retry"=>$ntries), 'timeseen ASC', 'id, pageid')) {
+                foreach($branches as $branch) {
+                    $viewedbranches[$branch->pageid] = $branch;
+                }
+                $viewedpageids = array_merge($viewedpageids, $viewedbranches);
             }
 
             // Filter out the following pages:
-- 
1.7.9.5


From 592443f4e1f36ebc602d73b1750a914a956fa6f9 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 29 Jun 2012 11:02:30 +0100
Subject: [PATCH 059/903] MDL-34109 quiz cron: change whitespace before
 applying the fix.

This commit just changes the white-space, but does not change any of the
actual code. This is so that the commit I am about to make, which will
change the code, will be easier to understand.
---
 mod/quiz/cronlib.php |   17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/mod/quiz/cronlib.php b/mod/quiz/cronlib.php
index eab7b0f..b6a1eb0 100644
--- a/mod/quiz/cronlib.php
+++ b/mod/quiz/cronlib.php
@@ -125,10 +125,19 @@ class mod_quiz_overdue_attempt_updater {
         ) group_by_results
            JOIN {quiz_attempts} quiza ON quiza.id = group_by_results.attemptid
 
-          WHERE (state = 'inprogress' AND (:timenow1 > usertimeclose OR
-                                           :timenow2 > quiza.timestart + usertimelimit))
-             OR (state = 'overdue'    AND (:timenow3 > graceperiod + usertimeclose OR
-                                           :timenow4 > graceperiod + quiza.timestart + usertimelimit))
+          WHERE (
+                state = 'inprogress' AND (
+                    :timenow1 > usertimeclose OR
+                    :timenow2 > quiza.timestart + usertimelimit
+                )
+            )
+          OR
+            (
+                state = 'overdue' AND (
+                    :timenow3 > graceperiod + usertimeclose OR
+                    :timenow4 > graceperiod + quiza.timestart + usertimelimit
+                )
+            )
 
        ORDER BY course, quiz",
 
-- 
1.7.9.5


From 2b1b2017a648d3da571e0d6995e0b6cc7fcf04d2 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 29 Jun 2012 11:07:21 +0100
Subject: [PATCH 060/903] MDL-34109 quiz cron: timelimit are timeclose of 0
 are special.

If the timelimit or timeclose of a quiz are 0, this means 'no
restriction', rather than '1970' or '0 seconds'. We need to handle these
special cases correctly in the code that looks for quiz attempts that
might be in the wrong state.
---
 mod/quiz/cronlib.php |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mod/quiz/cronlib.php b/mod/quiz/cronlib.php
index b6a1eb0..111419c 100644
--- a/mod/quiz/cronlib.php
+++ b/mod/quiz/cronlib.php
@@ -127,15 +127,15 @@ class mod_quiz_overdue_attempt_updater {
 
           WHERE (
                 state = 'inprogress' AND (
-                    :timenow1 > usertimeclose OR
-                    :timenow2 > quiza.timestart + usertimelimit
+                    (usertimeclose > 0 AND :timenow1 > usertimeclose) OR
+                    (usertimelimit > 0 AND :timenow2 > quiza.timestart + usertimelimit)
                 )
             )
           OR
             (
                 state = 'overdue' AND (
-                    :timenow3 > graceperiod + usertimeclose OR
-                    :timenow4 > graceperiod + quiza.timestart + usertimelimit
+                    (usertimeclose > 0 AND :timenow3 > graceperiod + usertimeclose) OR
+                    (usertimelimit > 0 AND :timenow4 > graceperiod + quiza.timestart + usertimelimit)
                 )
             )
 
-- 
1.7.9.5


From 502ecc4c9ffb606d3b723fd2fe90f6a307dc62ea Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 2 Jul 2012 14:06:45 +0800
Subject: [PATCH 061/903] MDL-34117 Correctly pass accepted_types to
 dnduploader

---
 lib/form/filemanager.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index f1f88b2..d81d5d9 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -975,7 +975,7 @@ M.form_filemanager.init = function(Y, options) {
     var manager = new FileManagerHelper(options);
     var dndoptions = {
         filemanager: manager,
-        acceptedtypes: options.accepted_types,
+        acceptedtypes: options.filepicker.accepted_types,
         clientid: options.client_id,
         author: options.author,
         maxfiles: options.maxfiles,
-- 
1.7.9.5


From 5c1b768aec94e14e546d7f0a31afe435c6612b36 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 2 Jul 2012 17:29:30 +0800
Subject: [PATCH 062/903] MDL-31802 - navigation: add a comment about session
 reduction

---
 lib/navigationlib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 41e5d2a..82b3ad9 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -1924,6 +1924,7 @@ class global_navigation extends navigation_node {
         $activities = array();
 
         foreach ($sections as $key => $section) {
+            // Clone and unset summary to prevent $SESSION bloat (MDL-31802).
             $sections[$key] = clone($section);
             unset($sections[$key]->summary);
             $sections[$key]->hasactivites = false;
-- 
1.7.9.5


From 1db89f5e6a5b922e2b6c71517bc0eda8277c1767 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Wed, 20 Jun 2012 17:02:00 +0100
Subject: [PATCH 063/903] MDL-33916 Ensure that capabilities are checked for
 cached user enrolments

---
 lib/accesslib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/accesslib.php b/lib/accesslib.php
index fcd91b8..de180b4 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -1961,6 +1961,9 @@ function is_enrolled(context $context, $user = null, $withcapability = '', $only
             $coursecontext->reload_if_dirty();
             if (isset($USER->enrol['enrolled'][$coursecontext->instanceid])) {
                 if ($USER->enrol['enrolled'][$coursecontext->instanceid] > time()) {
+                    if ($withcapability and !has_capability($withcapability, $context, $userid)) {
+                        return false;
+                    }
                     return true;
                 }
             }
-- 
1.7.9.5


From 770cee969678a2197e0c4d6b82ca019e94199845 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Wed, 20 Jun 2012 20:16:13 +0100
Subject: [PATCH 064/903] MDL-33916 Add unit tests to ensure that is_enrolled
 returns correctly

---
 lib/tests/accesslib_test.php |   53 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/lib/tests/accesslib_test.php b/lib/tests/accesslib_test.php
index ac51a37..6d7bc4e 100644
--- a/lib/tests/accesslib_test.php
+++ b/lib/tests/accesslib_test.php
@@ -148,6 +148,59 @@ class accesslib_testcase extends advanced_testcase {
     }
 
     /**
+     * Test if user is enrolled in a course
+     * @return void
+     */
+    public function test_is_enrolled() {
+        global $DB;
+
+        // Generate data
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $coursecontext = context_course::instance($course->id);
+        $role = $DB->get_record('role', array('shortname'=>'student'));
+
+        // There should be a manual enrolment as part of the default install
+        $plugin = enrol_get_plugin('manual');
+        $instance = $DB->get_record('enrol', array(
+            'courseid' => $course->id,
+            'enrol' => 'manual',
+        ));
+        $this->assertNotEquals($instance, false);
+
+        // Enrol the user in the course
+        $plugin->enrol_user($instance, $user->id, $role->id);
+
+        // We'll test with the mod/assign:submit capability
+        $capability= 'mod/assign:submit';
+        $this->assertTrue($DB->record_exists('capabilities', array('name' => $capability)));
+
+        // Switch to our user
+        $this->setUser($user);
+
+        // Ensure that the user has the capability first
+        $this->assertTrue(has_capability($capability, $coursecontext, $user->id));
+
+        // We first test whether the user is enrolled on the course as this
+        // seeds the cache, then we test for the capability
+        $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
+        $this->assertTrue(is_enrolled($coursecontext, $user, $capability));
+
+        // Prevent the capability for this user role
+        assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
+        $coursecontext->mark_dirty();
+        $this->assertFalse(has_capability($capability, $coursecontext, $user->id));
+
+        // Again, we seed the cache first by checking initial enrolment,
+        // and then we test the actual capability
+        $this->assertTrue(is_enrolled($coursecontext, $user, '', true));
+        $this->assertFalse(is_enrolled($coursecontext, $user, $capability));
+
+        // We need variable states to be reset for the next test
+        $this->resetAfterTest(true);
+    }
+
+    /**
      * Test logged in test.
      * @return void
      */
-- 
1.7.9.5


From ec3fe6e123c9617971839a49085ff67cf3208e06 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 26 Jun 2012 11:40:08 +0800
Subject: [PATCH 065/903] MDL-33948 file_save_draft_area_files() validates if
 references are allowed and allows unlimited file
 size

---
 lib/filelib.php |   15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index e814fee..523c643 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -721,9 +721,16 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
     if (!isset($options['maxfiles'])) {
         $options['maxfiles'] = -1; // unlimited
     }
-    if (!isset($options['maxbytes'])) {
+    if (!isset($options['maxbytes']) || $options['maxbytes'] == USER_CAN_IGNORE_FILE_SIZE_LIMITS) {
         $options['maxbytes'] = 0; // unlimited
     }
+    $allowreferences = true;
+    if (isset($options['return_types']) && !($options['return_types'] & FILE_REFERENCE)) {
+        // we assume that if $options['return_types'] is NOT specified, we DO allow references.
+        // this is not exactly right. BUT there are many places in code where filemanager options
+        // are not passed to file_save_draft_area_files()
+        $allowreferences = false;
+    }
 
     $draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
     $oldfiles   = $fs->get_area_files($contextid, $component, $filearea, $itemid, 'id');
@@ -755,6 +762,9 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
             }
 
             if ($file->is_external_file()) {
+                if (!$allowreferences) {
+                    continue;
+                }
                 $repoid = $file->get_repository_id();
                 if (!empty($repoid)) {
                     $file_record['repositoryid'] = $repoid;
@@ -856,6 +866,9 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
             }
 
             if ($file->is_external_file()) {
+                if (!$allowreferences) {
+                    continue;
+                }
                 $repoid = $file->get_repository_id();
                 if (!empty($repoid)) {
                     $file_record['repositoryid'] = $repoid;
-- 
1.7.9.5


From dff8438e5080f3bc4a9243bdd14139cfa39e2abe Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 26 Jun 2012 11:25:57 +0800
Subject: [PATCH 066/903] MDL-33948 mod_forum correctly passes files options
 to file_save_draft_area_files()

---
 mod/forum/lib.php       |   19 ++++++++++++------
 mod/forum/post.php      |    4 ++--
 mod/forum/post_form.php |   51 ++++++++++++++++++++++++++++++++++-------------
 3 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 1f70499..812172a 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die();
 require_once($CFG->libdir.'/filelib.php');
 require_once($CFG->libdir.'/eventslib.php');
 require_once($CFG->dirroot.'/user/selector/lib.php');
+require_once($CFG->dirroot.'/mod/forum/post_form.php');
 
 /// CONSTANTS ///////////////////////////////////////////////////////////
 
@@ -99,7 +100,8 @@ function forum_add_instance($forum, $mform = null) {
             $discussion = $DB->get_record('forum_discussions', array('id'=>$discussion->id), '*', MUST_EXIST);
             $post = $DB->get_record('forum_posts', array('id'=>$discussion->firstpost), '*', MUST_EXIST);
 
-            $post->message = file_save_draft_area_files($draftid, $modcontext->id, 'mod_forum', 'post', $post->id, array('subdirs'=>true), $post->message);
+            $post->message = file_save_draft_area_files($draftid, $modcontext->id, 'mod_forum', 'post', $post->id,
+                    mod_forum_post_form::attachment_options($forum), $post->message);
             $DB->set_field('forum_posts', 'message', $post->message, array('id'=>$post->id));
         }
     }
@@ -196,7 +198,8 @@ function forum_update_instance($forum, $mform) {
             $discussion = $DB->get_record('forum_discussions', array('id'=>$discussion->id), '*', MUST_EXIST);
             $post = $DB->get_record('forum_posts', array('id'=>$discussion->firstpost), '*', MUST_EXIST);
 
-            $post->message = file_save_draft_area_files($draftid, $modcontext->id, 'mod_forum', 'post', $post->id, array('subdirs'=>true), $post->message);
+            $post->message = file_save_draft_area_files($draftid, $modcontext->id, 'mod_forum', 'post', $post->id,
+                    mod_forum_post_form::editor_options(), $post->message);
         }
 
         $post->subject       = $forum->name;
@@ -4230,7 +4233,8 @@ function forum_add_attachment($post, $forum, $cm, $mform=null, &$message=null) {
 
     $info = file_get_draft_area_info($post->attachments);
     $present = ($info['filecount']>0) ? '1' : '';
-    file_save_draft_area_files($post->attachments, $context->id, 'mod_forum', 'attachment', $post->id);
+    file_save_draft_area_files($post->attachments, $context->id, 'mod_forum', 'attachment', $post->id,
+            mod_forum_post_form::attachment_options($forum));
 
     $DB->set_field('forum_posts', 'attachment', $present, array('id'=>$post->id));
 
@@ -4262,7 +4266,8 @@ function forum_add_new_post($post, $mform, &$message) {
     $post->attachment = "";
 
     $post->id = $DB->insert_record("forum_posts", $post);
-    $post->message = file_save_draft_area_files($post->itemid, $context->id, 'mod_forum', 'post', $post->id, array('subdirs'=>true), $post->message);
+    $post->message = file_save_draft_area_files($post->itemid, $context->id, 'mod_forum', 'post', $post->id,
+            mod_forum_post_form::editor_options(), $post->message);
     $DB->set_field('forum_posts', 'message', $post->message, array('id'=>$post->id));
     forum_add_attachment($post, $forum, $cm, $mform, $message);
 
@@ -4308,7 +4313,8 @@ function forum_update_post($post, $mform, &$message) {
         $discussion->timestart = $post->timestart;
         $discussion->timeend   = $post->timeend;
     }
-    $post->message = file_save_draft_area_files($post->itemid, $context->id, 'mod_forum', 'post', $post->id, array('subdirs'=>true), $post->message);
+    $post->message = file_save_draft_area_files($post->itemid, $context->id, 'mod_forum', 'post', $post->id,
+            mod_forum_post_form::editor_options(), $post->message);
     $DB->set_field('forum_posts', 'message', $post->message, array('id'=>$post->id));
 
     $DB->update_record('forum_discussions', $discussion);
@@ -4371,7 +4377,8 @@ function forum_add_discussion($discussion, $mform=null, &$message=null, $userid=
     // TODO: Fix the calling code so that there always is a $cm when this function is called
     if (!empty($cm->id) && !empty($discussion->itemid)) {   // In "single simple discussions" this may not exist yet
         $context = get_context_instance(CONTEXT_MODULE, $cm->id);
-        $text = file_save_draft_area_files($discussion->itemid, $context->id, 'mod_forum', 'post', $post->id, array('subdirs'=>true), $post->message);
+        $text = file_save_draft_area_files($discussion->itemid, $context->id, 'mod_forum', 'post', $post->id,
+                mod_forum_post_form::editor_options(), $post->message);
         $DB->set_field('forum_posts', 'message', $text, array('id'=>$post->id));
     }
 
diff --git a/mod/forum/post.php b/mod/forum/post.php
index 15a386d..20528d0 100644
--- a/mod/forum/post.php
+++ b/mod/forum/post.php
@@ -510,7 +510,7 @@ require_once('post_form.php');
 $mform_post = new mod_forum_post_form('post.php', array('course'=>$course, 'cm'=>$cm, 'coursecontext'=>$coursecontext, 'modcontext'=>$modcontext, 'forum'=>$forum, 'post'=>$post));
 
 $draftitemid = file_get_submitted_draft_itemid('attachments');
-file_prepare_draft_area($draftitemid, $modcontext->id, 'mod_forum', 'attachment', empty($post->id)?null:$post->id);
+file_prepare_draft_area($draftitemid, $modcontext->id, 'mod_forum', 'attachment', empty($post->id)?null:$post->id, mod_forum_post_form::attachment_options($forum));
 
 //load data into form NOW!
 
@@ -550,7 +550,7 @@ if (forum_is_subscribed($USER->id, $forum->id)) {
 }
 
 $draftid_editor = file_get_submitted_draft_itemid('message');
-$currenttext = file_prepare_draft_area($draftid_editor, $modcontext->id, 'mod_forum', 'post', empty($post->id) ? null : $post->id, array('subdirs'=>true), $post->message);
+$currenttext = file_prepare_draft_area($draftid_editor, $modcontext->id, 'mod_forum', 'post', empty($post->id) ? null : $post->id, mod_forum_post_form::editor_options(), $post->message);
 $mform_post->set_data(array(        'attachments'=>$draftitemid,
                                     'general'=>$heading,
                                     'subject'=>$post->subject,
diff --git a/mod/forum/post_form.php b/mod/forum/post_form.php
index b475684..c710567 100644
--- a/mod/forum/post_form.php
+++ b/mod/forum/post_form.php
@@ -29,6 +29,41 @@ require_once($CFG->libdir.'/formslib.php');
 
 class mod_forum_post_form extends moodleform {
 
+    /**
+     * Returns the options array to use in filemanager for forum attachments
+     *
+     * @param stdClass $forum
+     * @return array
+     */
+    public static function attachment_options($forum) {
+        global $COURSE, $PAGE, $CFG;
+        $maxbytes = get_user_max_upload_file_size($PAGE->context, $CFG->maxbytes, $COURSE->maxbytes, $forum->maxbytes);
+        return array(
+            'subdirs' => 0,
+            'maxbytes' => $maxbytes,
+            'maxfiles' => $forum->maxattachments,
+            'accepted_types' => '*',
+            'return_types' => FILE_INTERNAL
+        );
+    }
+
+    /**
+     * Returns the options array to use in forum text editor
+     *
+     * @return array
+     */
+    public static function editor_options() {
+        global $COURSE, $PAGE, $CFG;
+        // TODO: add max files and max size support
+        $maxbytes = get_user_max_upload_file_size($PAGE->context, $CFG->maxbytes, $COURSE->maxbytes);
+        return array(
+            'maxfiles' => EDITOR_UNLIMITED_FILES,
+            'maxbytes' => $maxbytes,
+            'trusttext'=> true,
+            'return_types'=> FILE_INTERNAL | FILE_EXTERNAL
+        );
+    }
+
     function definition() {
 
         global $CFG;
@@ -40,13 +75,6 @@ class mod_forum_post_form extends moodleform {
         $modcontext    = $this->_customdata['modcontext'];
         $forum         = $this->_customdata['forum'];
         $post          = $this->_customdata['post'];
-        // if $forum->maxbytes == '0' means we should use $course->maxbytes
-        if ($forum->maxbytes == '0') {
-            $forum->maxbytes = $course->maxbytes;
-        }
-        // TODO: add max files and max size support
-        $editoroptions = array('maxfiles' => EDITOR_UNLIMITED_FILES, 'trusttext'=>true,
-            'context'=>$modcontext, 'return_types'=>FILE_INTERNAL | FILE_EXTERNAL);
 
         $mform->addElement('header', 'general', '');//fill in the data depending on page params later using set_data
         $mform->addElement('text', 'subject', get_string('subject', 'forum'), 'size="48"');
@@ -54,7 +82,7 @@ class mod_forum_post_form extends moodleform {
         $mform->addRule('subject', get_string('required'), 'required', null, 'client');
         $mform->addRule('subject', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
-        $mform->addElement('editor', 'message', get_string('message', 'forum'), null, $editoroptions);
+        $mform->addElement('editor', 'message', get_string('message', 'forum'), null, self::editor_options());
         $mform->setType('message', PARAM_RAW);
         $mform->addRule('message', get_string('required'), 'required', null, 'client');
 
@@ -82,12 +110,7 @@ class mod_forum_post_form extends moodleform {
             }
 
         if (!empty($forum->maxattachments) && $forum->maxbytes != 1 && has_capability('mod/forum:createattachment', $modcontext))  {  //  1 = No attachments at all
-            $mform->addElement('filemanager', 'attachments', get_string('attachment', 'forum'), null,
-                array('subdirs'=>0,
-                      'maxbytes'=>$forum->maxbytes,
-                      'maxfiles'=>$forum->maxattachments,
-                      'accepted_types'=>'*',
-                      'return_types'=>FILE_INTERNAL));
+            $mform->addElement('filemanager', 'attachments', get_string('attachment', 'forum'), null, self::attachment_options($forum));
             $mform->addHelpButton('attachments', 'attachment', 'forum');
         }
 
-- 
1.7.9.5


From 1a76bbe2e4eb7702099b071e70e64bfb5b215158 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Mon, 2 Jul 2012 18:15:47 +0200
Subject: [PATCH 067/903] MDL-34121 bump versions to efectively get the
 upgrade performed.

Conflicts:
	version.php
---
 lib/db/upgrade.php |   13 +++++++------
 version.php        |    2 +-
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 372910c..f50ae6b 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -871,7 +871,12 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062000.01);
     }
 
-    if ($oldversion < 2012062500.01) {
+
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+
+    if ($oldversion < 2012062500.02) {
         // Drop some old backup tables, not used anymore
 
         // Define table backup_files to be dropped
@@ -891,13 +896,9 @@ function xmldb_main_upgrade($oldversion) {
         }
 
         // Main savepoint reached
-        upgrade_main_savepoint(true, 2012062500.01);
+        upgrade_main_savepoint(true, 2012062500.02);
     }
 
 
-    // Moodle v2.3.0 release upgrade line
-    // Put any upgrade step following this
-
-
     return true;
 }
diff --git a/version.php b/version.php
index 728ef4d..69bc916 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062500.01;              // 2012062500    = branching date YYYYMMDD - do not modify!
+$version  = 2012062500.02;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From d9edd25111a4447ec6212c44eb44175ae4682afd Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 28 Jun 2012 14:16:55 +0800
Subject: [PATCH 068/903] MDL-34081 dml: mssql driver was using case
 insensitve sql

---
 lib/dml/mssql_native_moodle_database.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/dml/mssql_native_moodle_database.php b/lib/dml/mssql_native_moodle_database.php
index 7d134d2..323a2fe 100644
--- a/lib/dml/mssql_native_moodle_database.php
+++ b/lib/dml/mssql_native_moodle_database.php
@@ -331,7 +331,7 @@ class mssql_native_moodle_database extends moodle_database {
         }
         $this->tables = array();
         $sql = "SELECT table_name
-                  FROM information_schema.tables
+                  FROM INFORMATION_SCHEMA.TABLES
                  WHERE table_name LIKE '$this->prefix%'
                    AND table_type = 'BASE TABLE'";
         $this->query_start($sql, null, SQL_QUERY_AUX);
@@ -426,7 +426,7 @@ class mssql_native_moodle_database extends moodle_database {
                            columnproperty(object_id(quotename(table_schema) + '.' +
                                quotename(table_name)), column_name, 'IsIdentity') AS auto_increment,
                            column_default AS default_value
-                      FROM information_schema.columns
+                      FROM INFORMATION_SCHEMA.COLUMNS
                      WHERE table_name = '{" . $table . "}'
                   ORDER BY ordinal_position";
         } else { // temp table, get metadata from tempdb schema
@@ -439,7 +439,7 @@ class mssql_native_moodle_database extends moodle_database {
                            columnproperty(object_id(quotename(table_schema) + '.' +
                                quotename(table_name)), column_name, 'IsIdentity') AS auto_increment,
                            column_default AS default_value
-                      FROM tempdb.information_schema.columns
+                      FROM tempdb.INFORMATION_SCHEMA.COLUMNS
                       JOIN tempdb..sysobjects ON name = table_name
                      WHERE id = object_id('tempdb..{" . $table . "}')
                   ORDER BY ordinal_position";
-- 
1.7.9.5


From a78e4e9147d0f7af96e029206768fe7ed7cc6c65 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Thu, 28 Jun 2012 15:32:33 +0800
Subject: [PATCH 069/903] MDL-23254 Authentication : used httpswwwroot as root
 url during authentication procedure where
 $PAGE->https_required() is specified.

---
 auth/ldap/ntlmsso_attempt.php |    5 +++--
 auth/ldap/ntlmsso_magic.php   |    3 ++-
 auth/shibboleth/login.php     |    8 ++++----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/auth/ldap/ntlmsso_attempt.php b/auth/ldap/ntlmsso_attempt.php
index 8624b38..69bbd42 100644
--- a/auth/ldap/ntlmsso_attempt.php
+++ b/auth/ldap/ntlmsso_attempt.php
@@ -33,8 +33,9 @@ $PAGE->set_title("$site->fullname: $loginsite");
 $PAGE->set_heading($site->fullname);
 echo $OUTPUT->header();
 
+// $PAGE->https_required() up above takes care of what $CFG->httpswwwroot should be.
 $msg = '<p>'.get_string('ntlmsso_attempting', 'auth_ldap').'</p>'
     . '<img width="1", height="1" '
-    . ' src="' . $CFG->wwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey='
+    . ' src="' . $CFG->httpswwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey='
     . $sesskey . '" />';
-redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_finish.php', $msg, 3);
+redirect($CFG->httpswwwroot . '/auth/ldap/ntlmsso_finish.php', $msg, 3);
diff --git a/auth/ldap/ntlmsso_magic.php b/auth/ldap/ntlmsso_magic.php
index 9c74f87..f7cd208 100644
--- a/auth/ldap/ntlmsso_magic.php
+++ b/auth/ldap/ntlmsso_magic.php
@@ -29,7 +29,8 @@ $file = $CFG->dirroot.'/pix/spacer.gif';
 if ($authplugin->ntlmsso_magic($sesskey) && file_exists($file)) {
     if (!empty($authplugin->config->ntlmsso_ie_fastpath)) {
         if (check_browser_version('MSIE')) {
-            redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_finish.php');
+            // $PAGE->https_required() up above takes care of what $CFG->httpswwwroot should be.
+            redirect($CFG->httpswwwroot.'/auth/ldap/ntlmsso_finish.php');
         }
     }
 
diff --git a/auth/shibboleth/login.php b/auth/shibboleth/login.php
index 0b635ac..ee3372f 100644
--- a/auth/shibboleth/login.php
+++ b/auth/shibboleth/login.php
@@ -44,17 +44,17 @@ $PAGE->https_required();
         // Redirect to SessionInitiator with entityID as argument
         if (isset($IdPs[$selectedIdP][1]) && !empty($IdPs[$selectedIdP][1])) {
             // For Shibbolet 1.x Service Providers
-            header('Location: '.$IdPs[$selectedIdP][1].'?providerId='. urlencode($selectedIdP) .'&target='. urlencode($CFG->wwwroot.'/auth/shibboleth/index.php'));
+            header('Location: '.$IdPs[$selectedIdP][1].'?providerId='. urlencode($selectedIdP) .'&target='. urlencode($CFG->httpswwwroot.'/auth/shibboleth/index.php'));
 
             // For Shibbolet 2.x Service Providers
-            // header('Location: '.$IdPs[$selectedIdP][1].'?entityID='. urlencode($selectedIdP) .'&target='. urlencode($CFG->wwwroot.'/auth/shibboleth/index.php'));
+            // header('Location: '.$IdPs[$selectedIdP][1].'?entityID='. urlencode($selectedIdP) .'&target='. urlencode($CFG->httpswwwroot.'/auth/shibboleth/index.php'));
 
         } else {
             // For Shibbolet 1.x Service Providers
-            header('Location: /Shibboleth.sso?providerId='. urlencode($selectedIdP) .'&target='. urlencode($CFG->wwwroot.'/auth/shibboleth/index.php'));
+            header('Location: /Shibboleth.sso?providerId='. urlencode($selectedIdP) .'&target='. urlencode($CFG->httpswwwroot.'/auth/shibboleth/index.php'));
 
             // For Shibboleth 2.x Service Providers
-            // header('Location: /Shibboleth.sso/DS?entityID='. urlencode($selectedIdP) .'&target='. urlencode($CFG->wwwroot.'/auth/shibboleth/index.php'));
+            // header('Location: /Shibboleth.sso/DS?entityID='. urlencode($selectedIdP) .'&target='. urlencode($CFG->httpswwwroot.'/auth/shibboleth/index.php'));
         }
     } elseif (isset($_POST['idp']) && !isset($IdPs[$_POST['idp']]))  {
         $errormsg = get_string('auth_shibboleth_errormsg', 'auth_shibboleth');
-- 
1.7.9.5


From 15d8babd1a0b94630806835dd0dc08489537f26e Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 21 Jun 2012 22:03:09 +0100
Subject: [PATCH 070/903] MDL-23813 glossary filter: add missing YUI
 dependency

Fix found by Huy Hoang. I am just making a commit.
---
 filter/glossary/version.php                  |    2 +-
 filter/glossary/yui/autolinker/autolinker.js |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/filter/glossary/version.php b/filter/glossary/version.php
index 473e483..7ea92b6 100644
--- a/filter/glossary/version.php
+++ b/filter/glossary/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version  = 2012061700;
+$plugin->version  = 2012061701;
 $plugin->requires = 2012061700;  // Requires this Moodle version
 $plugin->component= 'filter_glossary';
 
diff --git a/filter/glossary/yui/autolinker/autolinker.js b/filter/glossary/yui/autolinker/autolinker.js
index 18677af..484c42e 100644
--- a/filter/glossary/yui/autolinker/autolinker.js
+++ b/filter/glossary/yui/autolinker/autolinker.js
@@ -130,4 +130,4 @@ YUI.add('moodle-filter_glossary-autolinker', function(Y) {
         return new AUTOLINKER(config);
     }
 
-}, '@VERSION@', {requires:['base','node','event-delegate','overlay','moodle-enrol-notification']});
+}, '@VERSION@', {requires:['base','node','io-base','json-parse','event-delegate','overlay','moodle-enrol-notification']});
-- 
1.7.9.5


From 815aecf6c72392351c043c658f8b9fc6754d843c Mon Sep 17 00:00:00 2001
From: "Matthew G. Switlik" <switlik@oakland.edu>
Date: Wed, 13 Jun 2012 15:34:50 -0400
Subject: [PATCH 071/903] MDL-28151 resource: prevent cropping of large images

---
 theme/base/style/core.css |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index e1f5f4f..a91000e 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -669,6 +669,9 @@ body.tag .managelink {padding: 5px;}
 .resourcecontent .mediaplugin_mp3 object {height:25px; width: 600px}
 .resourcecontent audio.mediaplugin_html5audio {width: 600px}
 
+/** Large resource images should avoid hidden overflow **/
+.resourceimage {max-width: 100%;}
+
 /* Audio player size in 'inline' mode (can only change width, as above) */
 .mediaplugin_mp3 object {height:15px;width:300px}
 audio.mediaplugin_html5audio {width: 300px}
-- 
1.7.9.5


From 5809f6912b807e1f8c4b06156591f2e863153db2 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Tue, 19 Jun 2012 15:59:48 +0800
Subject: [PATCH 072/903] MDL-33848: Prevent file listings in the assignment
 module having an ugly border

---
 mod/assign/styles.css |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/mod/assign/styles.css b/mod/assign/styles.css
index 840ad17..8b1b67b 100644
--- a/mod/assign/styles.css
+++ b/mod/assign/styles.css
@@ -21,6 +21,8 @@ div.gradingsummary .generaltable {
     width: 100%;
 }
 
+#page-mod-assign-view table.generaltable table td { border: 0px none; }
+
 .gradingsummarytable,
 .feedbacktable,
 .lockedsubmission,
-- 
1.7.9.5


From e068b3dbe342db5e02df3a22b45a9deb8fd5792d Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 27 Jun 2012 10:57:27 +0800
Subject: [PATCH 073/903] MDL-34033 lang - ammend configenableajax

Now better reflects its functionality.
---
 lang/en/admin.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 42dbcf3..46347d9 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -189,7 +189,7 @@ $string['configdoctonewwindow'] = 'If you enable this, then links to Moodle Docs
 $string['configeditordictionary'] = 'This value will be used if aspell doesn\'t have dictionary for users own language.';
 $string['configeditorfontlist'] = 'Select the fonts that should appear in the editor\'s drop-down list.';
 $string['configemailchangeconfirmation'] = 'Require an email confirmation step when users change their email address in their profile.';
-$string['configenableajax'] = 'This setting allows you to control the use of AJAX (advanced client/server interfaces using Javascript) across the whole site.  With this setting enabled users can still make a choice in their profile, otherwise AJAX is disabled for everybody.';
+$string['configenableajax'] = 'This setting controls the use of AJAX across the site. AJAX is required for certain functionality such as drag and drop.';
 $string['configenablecalendarexport'] = 'Enable exporting or subscribing to calendars.';
 $string['configenablecomments'] = 'Enable comments';
 $string['configenablecourserequests'] = 'This will allow any user to request a course be created.';
-- 
1.7.9.5


From eadad29dc9dc593b959ef98e0f4cae570a47d6fa Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 26 Jun 2012 11:02:37 +0800
Subject: [PATCH 074/903] MDL-34022 lang - the html editor supports all
 browsers we support

So remove misleading 'some browers only'
---
 lang/en/moodle.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 4b2b34d..853e2ee 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -838,7 +838,7 @@ $string['home'] = 'Home';
 $string['hour'] = 'hour';
 $string['hours'] = 'hours';
 $string['howtomakethemes'] = 'How to make new themes';
-$string['htmleditor'] = 'Use HTML editor (some browsers only)';
+$string['htmleditor'] = 'Use HTML editor';
 $string['htmleditoravailable'] = 'The HTML editor is available';
 $string['htmleditordisabled'] = 'You have disabled the HTML editor in your user profile';
 $string['htmleditordisabledadmin'] = 'The administrator has disabled the HTML editor on this site';
-- 
1.7.9.5


From 9ea8065f1c1c3446280f743f5473b3ec2d23562e Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 26 Jun 2012 11:17:36 +0800
Subject: [PATCH 075/903] MDL-34014 lang - fix CSS optimiser spelling errors

---
 lang/en/admin.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 46347d9..baf70f5 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -468,7 +468,7 @@ $string['enablecalendarexport'] = 'Enable calendar export';
 $string['enablecomments'] = 'Enable comments';
 $string['enablecourserequests'] = 'Enable course requests';
 $string['enablecssoptimiser'] = 'Enable CSS optimiser';
-$string['enablecssoptimiser_desc'] = 'When enabled CSS will be run through an optimisation process before being cached. The optimiser processes the CSS removing duplicate rules and styles, as well as white space removeable and reformatting. Please note turning this on at the same time as theme designer mode is aweful for performance but will help theme designers create optimised CSS.';
+$string['enablecssoptimiser_desc'] = 'When enabled CSS will be run through an optimisation process before being cached. The optimiser processes the CSS removing duplicate rules and styles, as well as white space removable and reformatting. Please note turning this on at the same time as theme designer mode is awful for performance but will help theme designers create optimised CSS.';
 $string['enabledevicedetection'] = 'Enable device detection';
 $string['enablegravatar'] = 'Enable Gravatar';
 $string['enablegravatar_help'] = 'When enabled Moodle will attempt to fetch a user profile picture from Gravatar if the user has not uploaded an image.';
-- 
1.7.9.5


From 66ff4c0a06de763e19ffa8d95604f979e128e651 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Tue, 3 Jul 2012 10:34:13 +1200
Subject: [PATCH 076/903] MDL-34014 cssoptimiser: Fixed some aweful spelling

---
 lib/csslib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/csslib.php b/lib/csslib.php
index 2408e38..d160359 100644
--- a/lib/csslib.php
+++ b/lib/csslib.php
@@ -171,7 +171,7 @@ function css_send_cached_css($csspath, $etag) {
  *
  * This function takes a raw CSS string, optimises it if required, and then
  * serves it.
- * Turning both themedesignermode and CSS optimiser on at the same time is aweful
+ * Turning both themedesignermode and CSS optimiser on at the same time is awful
  * for performance because of the optimiser running here. However it was done so
  * that theme designers could utilise the optimised output during development to
  * help them optimise their CSS... not that they should write lazy CSS.
-- 
1.7.9.5


From bed1c4a94363ba65db519516f505797a90270b9e Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 25 Jun 2012 14:26:54 +0800
Subject: [PATCH 077/903] MDL-33990 - yui2: remove 2 uncessary requirements

We no longer use yui2 logger and connection in set_user_prefs
---
 lib/ajax/ajaxlib.php          |    3 ---
 lib/outputrequirementslib.php |    1 -
 2 files changed, 4 deletions(-)

diff --git a/lib/ajax/ajaxlib.php b/lib/ajax/ajaxlib.php
index 72eba29..4c298b5 100644
--- a/lib/ajax/ajaxlib.php
+++ b/lib/ajax/ajaxlib.php
@@ -36,9 +36,6 @@
 function user_preference_allow_ajax_update($name, $paramtype) {
     global $USER, $PAGE;
 
-    // Make sure that the required JavaScript libraries are loaded.
-    $PAGE->requires->yui2_lib('connection');
-
     // Record in the session that this user_preference is allowed to updated remotely.
     $USER->ajax_updatable_user_prefs[$name] = $paramtype;
 }
diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php
index 6ad4bea..a50fcd2 100644
--- a/lib/outputrequirementslib.php
+++ b/lib/outputrequirementslib.php
@@ -326,7 +326,6 @@ class page_requirements_manager {
         );
         if (debugging('', DEBUG_DEVELOPER)) {
             $this->M_cfg['developerdebug'] = true;
-            $this->yui2_lib('logger');
         }
 
         // accessibility stuff
-- 
1.7.9.5


From 5df543a60eb0e29d44b434b1b76c3f362ba03f3a Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Sat, 16 Jun 2012 23:23:16 +0800
Subject: [PATCH 078/903] MDL-32286 - fix ambigious english string

---
 lang/en/moodle.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 853e2ee..af23c90 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1710,7 +1710,7 @@ $string['uploadcantwrite'] = 'Failed to write file to disk';
 $string['uploadedfile'] = 'File uploaded successfully';
 $string['uploadedfileto'] = 'Uploaded {$a->file} to {$a->directory}';
 $string['uploadedfiletoobig'] = 'Sorry, but that file is too big (limit is {$a} bytes)';
-$string['uploadextension'] = 'File upload stopped by extension';
+$string['uploadextension'] = 'File upload stopped by a PHP extension';
 $string['uploadfailednotrecovering'] = 'Your file upload has failed because there was a problem with one of the files, {$a->name}.<br /> Here is a log of the problems:<br />{$a->problem}<br />Not recovering.';
 $string['uploadfilelog'] = 'Upload log for file {$a}';
 $string['uploadformlimit'] = 'Uploaded file {$a} exceeded the maximum size limit set by the form';
-- 
1.7.9.5


From 3d43075cfdb16373a6b9bb97e462fdc4e3a4f0f1 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 27 Jun 2012 13:10:24 +0800
Subject: [PATCH 079/903] MDL-9214 - improve comment for custom login
 instructions

---
 lang/en/auth.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/auth.php b/lang/en/auth.php
index 3c0ada0..9e14d1d 100644
--- a/lang/en/auth.php
+++ b/lang/en/auth.php
@@ -38,7 +38,7 @@ $string['auth_changepasswordhelp_expl'] = 'Display lost password help to users w
 $string['auth_changepasswordurl'] = 'Change password URL';
 $string['auth_changepasswordurl_expl'] = 'Specify the url to send users who have lost their {$a} password. Set <strong>Use standard Change Password page</strong> to <strong>No</strong>.';
 $string['auth_changingemailaddress'] = 'You have requested a change of email address, from {$a->oldemail} to {$a->newemail}. For security reasons, we are sending you an email message at the new address to confirm that it belongs to you. Your email address will be updated as soon as you open the URL sent to you in that message.';
-$string['authinstructions'] = 'Here you can provide instructions for your users, so they know which username and password they should be using.  The text you enter here will appear on the login page.  If you leave this blank then no instructions will be printed.';
+$string['authinstructions'] = 'Leave this blank for the default login instructions to be displayed on the login page. If you want to provide custom login instructions, enter them here.';
 $string['auth_invalidnewemailkey'] = 'Error: if you are trying to confirm a change of email address, you may have made a mistake in copying the URL we sent you by email. Please copy the address and try again.';
 $string['auth_multiplehosts'] = 'Multiple hosts OR addresses can be specified (eg host1.com;host2.com;host3.com) or (eg xxx.xxx.xxx.xxx;xxx.xxx.xxx.xxx)';
 $string['auth_outofnewemailupdateattempts'] = 'You have run out of allowed attempts to update your email address. Your update request has been cancelled.';
-- 
1.7.9.5


From 5200c254a12c962c319d58ec8cba35bc620a07a2 Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Tue, 26 Jun 2012 12:05:04 +0100
Subject: [PATCH 080/903] MDL-34029 update mod/upgrade.txt to include course
 drag and drop upload

---
 mod/upgrade.txt |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/mod/upgrade.txt b/mod/upgrade.txt
index 20957dc..72411c8 100644
--- a/mod/upgrade.txt
+++ b/mod/upgrade.txt
@@ -15,6 +15,11 @@ required changes in code:
 * most resourcelib_embed_* functions are replaced with core_media_renderer;
   for an example, see mod/resource/locallib.php, resource_display_embed()
 
+optional - no changes needed:
+
+* add support for handling course drag and drop types - functions
+  xxx_dndupload_register() and xxx_dndupload_handle($uploadinfo) see:
+  http://docs.moodle.org/dev/Implementing_Course_drag_and_drop_upload_support_in_a_module
 
 === 2.2 ===
 
-- 
1.7.9.5


From bd9ecafba9ed67a6b63f64a08c6ee5f2d298d76e Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 26 Jun 2012 14:54:56 +0800
Subject: [PATCH 081/903] MDL-33796 Glossary: removed unused missing string

---
 mod/glossary/print.php |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/mod/glossary/print.php b/mod/glossary/print.php
index d0d08aa..783c220 100644
--- a/mod/glossary/print.php
+++ b/mod/glossary/print.php
@@ -164,9 +164,6 @@ include_once("sql.php");
 
 $entriesshown = 0;
 $currentpivot = '';
-if ( $hook == 'SPECIAL' ) {
-    $alphabet = explode(",", get_string("alphabet"));
-}
 
 $site = $DB->get_record("course", array("id"=>1));
 echo '<p style="text-align:right"><span style="font-size:0.75em">' . userdate(time()) . '</span></p>';
-- 
1.7.9.5


From 7523da44fc13e8435c315086d65236189de20cd6 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Fri, 25 May 2012 14:53:52 +0800
Subject: [PATCH 082/903] MDL-33814 Output renderers: table cell objects are
 only created when needed

---
 lib/outputcomponents.php |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index 4bd0673..35edf3b 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -1577,9 +1577,10 @@ class html_writer {
                     if (!($row instanceof html_table_row)) {
                         $newrow = new html_table_row();
 
-                        foreach ($row as $item) {
-                            $cell = new html_table_cell();
-                            $cell->text = $item;
+                        foreach ($row as $cell) {
+                            if (!($cell instanceof html_table_cell)) {
+                                $cell = new html_table_cell($cell);
+                            }
                             $newrow->cells[] = $cell;
                         }
                         $row = $newrow;
-- 
1.7.9.5


From 18c264790a50dcd959838651a3e8766d3d60c345 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Fri, 15 Jun 2012 15:14:06 +0800
Subject: [PATCH 083/903] MDL-33770 Web service: create_groups should not
 require enrolmentkey

---
 group/externallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/group/externallib.php b/group/externallib.php
index 080f406..79d1a27 100644
--- a/group/externallib.php
+++ b/group/externallib.php
@@ -53,7 +53,7 @@ class core_group_external extends external_api {
                             'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                             'description' => new external_value(PARAM_RAW, 'group description text'),
                             'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
-                            'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
+                            'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase', VALUE_OPTIONAL),
                         )
                     ), 'List of group object. A group has a courseid, a name, a description and an enrolment key.'
                 )
-- 
1.7.9.5


From b653107b964b19929d34b7ddb5420d6552ffe20c Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Tue, 3 Jul 2012 09:17:21 +0930
Subject: [PATCH 084/903] MDL-32057: Fix cohort enrolment css for ie7

---
 .../assets/skins/sam/quickenrolment.css            |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/enrol/cohort/yui/quickenrolment/assets/skins/sam/quickenrolment.css b/enrol/cohort/yui/quickenrolment/assets/skins/sam/quickenrolment.css
index 540ed78..9509c01 100644
--- a/enrol/cohort/yui/quickenrolment/assets/skins/sam/quickenrolment.css
+++ b/enrol/cohort/yui/quickenrolment/assets/skins/sam/quickenrolment.css
@@ -33,4 +33,7 @@
 .qce-panel .qce-search input {width:70%;}
 
 .qce-panel .qce-cohort.headings {font-weight:bold;border-width:0;}
-.qce-panel .qce-cohort.headings .qce-cohort-button {display:none;}
\ No newline at end of file
+.qe-panel .qce-cohort.headings .qce-cohort-button {display:none;}
+
+.ie7 .qce-panel .qce-cohort div,
+.ie7 .qce-panel .canenrolusers .qce-cohort .qce-cohort-name {float:left;}
-- 
1.7.9.5


From 8ad459ed586bc3d83e6143467f9336d2ccbf96f5 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Tue, 5 Jun 2012 15:30:12 +0800
Subject: [PATCH 085/903] MDL-33499: Display final grade on the grading form
 with a link to the grader report

AMOS BEGIN
 CPY [currentgrade,mod_assignment],[currentgrade,mod_assign]
AMOS END
---
 mod/assign/lang/en/assign.php |    1 +
 mod/assign/locallib.php       |   10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index bb2fc38..251cff5 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -74,6 +74,7 @@ $string['couldnotconvertsubmission'] = 'Could not convert assignment submission
 $string['couldnotcreatecoursemodule'] = 'Could not create course module.';
 $string['couldnotcreatenewassignmentinstance'] = 'Could not create new assignment instance.';
 $string['couldnotfindassignmenttoupgrade'] = 'Could not find old assignment instance to upgrade.';
+$string['currentgrade'] = 'Current grade in gradebook';
 $string['defaultplugins'] = 'Default assignment settings';
 $string['defaultplugins_help'] = 'These settings define the defaults for all new assignments.';
 $string['deletepluginareyousure'] = 'Delete assignment plugin {$a}: are you sure?';
diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 28e8830..2fef79b 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -2898,6 +2898,16 @@ class assign {
             }
         }
 
+        if (has_all_capabilities(array('gradereport/grader:view', 'moodle/grade:viewall'), $this->get_course_context())) {
+            $grade = $this->output->action_link(new moodle_url('/grade/report/grader/index.php',
+                                                              array('id'=>$this->get_course()->id)),
+                                                $gradinginfo->items[0]->grades[$userid]->str_grade);
+        } else {
+            $grade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+        }
+        $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':' ,$grade);
+
+
         $mform->addElement('static', 'progress', '', get_string('gradingstudentprogress', 'assign', array('index'=>$rownum+1, 'count'=>count($useridlist))));
 
         // plugins
-- 
1.7.9.5


From d0d407f0bb7a3996e551fb9aa4a653a5c9bd28f9 Mon Sep 17 00:00:00 2001
From: ISHIKAWA Takayuki <rechka_osaka@yahoo.co.jp>
Date: Thu, 14 Jun 2012 21:29:33 +0900
Subject: [PATCH 086/903] MDL-33757 gradebook: Adding support to sort userlist
 by email address

---
 grade/report/grader/lib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index 83d3d6c..d5dafa4 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -411,6 +411,9 @@ class grade_report_grader extends grade_report {
                 case 'firstname':
                     $sort = "u.firstname $this->sortorder, u.lastname $this->sortorder";
                     break;
+                case 'email':
+                    $sort = "u.email $this->sortorder";
+                    break;
                 case 'idnumber':
                 default:
                     $sort = "u.idnumber $this->sortorder";
-- 
1.7.9.5


From f5cd2c6ef137de088c67d4c5216325a3ea9dd745 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 27 Jun 2012 10:49:34 +0800
Subject: [PATCH 087/903] MDL-33837 picking file from server files should not
 copy 'Main file' property

---
 repository/repository_ajax.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index 6919b3e..c9863c4 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -230,6 +230,7 @@ switch ($action) {
             $record->timecreated = $now;
             $record->timemodified = $now;
             $record->userid = $USER->id;
+            $record->sortorder = 0;
 
             // If file is already a reference, set $source = file source, $repo = file repository
             if ($repo->has_moodle_files()) {
-- 
1.7.9.5


From 69b2bab32ee0a124498cfd4cf8de6c1d334de2ac Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Fri, 22 Jun 2012 10:42:10 +0800
Subject: [PATCH 088/903] MDL-33957 - Installation - Fixing field lengths so
 they are long enough for data entry, and don't
 distort page rendering

---
 install.php     |    8 ++++----
 install/css.php |    2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/install.php b/install.php
index 098e132..c737e63 100644
--- a/install.php
+++ b/install.php
@@ -410,21 +410,21 @@ if ($config->stage == INSTALL_DATABASE) {
 
     $disabled = empty($distro->dbhost) ? '' : 'disabled="disabled';
     echo '<div class="formrow"><label for="id_dbhost" class="formlabel">'.$strdbhost.'</label>';
-    echo '<input id="id_dbhost" name="dbhost" '.$disabled.' type="text" value="'.s($config->dbhost).'" size="30" class="forminput" />';
+    echo '<input id="id_dbhost" name="dbhost" '.$disabled.' type="text" value="'.s($config->dbhost).'" size="50" class="forminput" />';
     echo '</div>';
 
     echo '<div class="formrow"><label for="id_dbname" class="formlabel">'.$strdbname.'</label>';
-    echo '<input id="id_dbname" name="dbname" type="text" value="'.s($config->dbname).'" size="30" class="forminput" />';
+    echo '<input id="id_dbname" name="dbname" type="text" value="'.s($config->dbname).'" size="50" class="forminput" />';
     echo '</div>';
 
     $disabled = empty($distro->dbuser) ? '' : 'disabled="disabled';
     echo '<div class="formrow"><label for="id_dbuser" class="formlabel">'.$strdbuser.'</label>';
-    echo '<input id="id_dbuser" name="dbuser" '.$disabled.' type="text" value="'.s($config->dbuser).'" size="30" class="forminput" />';
+    echo '<input id="id_dbuser" name="dbuser" '.$disabled.' type="text" value="'.s($config->dbuser).'" size="50" class="forminput" />';
     echo '</div>';
 
     echo '<div class="formrow"><label for="id_dbpass" class="formlabel">'.$strdbpass.'</label>';
     // no password field here, the password may be visible in config.php if we can not write it to disk
-    echo '<input id="id_dbpass" name="dbpass" type="text" value="'.s($config->dbpass).'" size="30" class="forminput" />';
+    echo '<input id="id_dbpass" name="dbpass" type="text" value="'.s($config->dbpass).'" size="50" class="forminput" />';
     echo '</div>';
 
     echo '<div class="formrow"><label for="id_prefix" class="formlabel">'.$strprefix.'</label>';
diff --git a/install/css.php b/install/css.php
index 16bfaba..2bceff6 100644
--- a/install/css.php
+++ b/install/css.php
@@ -96,7 +96,7 @@ h2 {
 .formrow label.formlabel {
   display:block;
   float:left;
-  width: 260px;
+  width: 160px;
   margin-right:5px;
   text-align:right;
 }
-- 
1.7.9.5


From 9152878ed36c8e8cb2d51ef7dd8210f9f06df0aa Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 23 May 2012 16:37:36 +0800
Subject: [PATCH 089/903] MDL-30903 Accessibility: user profile page uses
 table headers

---
 theme/base/style/user.css |    1 +
 user/profile.php          |    2 +-
 user/view.php             |    2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/theme/base/style/user.css b/theme/base/style/user.css
index b23d734..64f88e0 100644
--- a/theme/base/style/user.css
+++ b/theme/base/style/user.css
@@ -3,6 +3,7 @@
 .userprofile .fullprofilelink {text-align:center; margin:10px;}
 .userprofile .profilepicture {float:left; margin-right:20px;}
 .userprofile .description {margin-bottom:20px;}
+.userprofile .label {font-weight:normal;text-align:left;}
 
 .user-box {margin:8px;width:115px;height:160px;text-align:center;float:left;clear: none;}
 
diff --git a/user/profile.php b/user/profile.php
index 80dcdd9..9dafdd9 100644
--- a/user/profile.php
+++ b/user/profile.php
@@ -377,5 +377,5 @@ echo $OUTPUT->footer();
 
 
 function print_row($left, $right) {
-    echo "\n<tr><td class=\"label c0\">$left</td><td class=\"info c1\">$right</td></tr>\n";
+    echo "\n<tr><th class=\"label c0\">$left</th><td class=\"info c1\">$right</td></tr>\n";
 }
diff --git a/user/view.php b/user/view.php
index 66728b7..68d36ac 100644
--- a/user/view.php
+++ b/user/view.php
@@ -354,7 +354,7 @@ echo $OUTPUT->footer();
 /// Functions ///////
 
 function print_row($left, $right) {
-    echo "\n<tr><td class=\"label c0\">$left</td><td class=\"info c1\">$right</td></tr>\n";
+    echo "\n<tr><th class=\"label c0\">$left</th><td class=\"info c1\">$right</td></tr>\n";
 }
 
 
-- 
1.7.9.5


From a1a00aeee7c9291b51266d9bd3de89a7b89a636c Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Fri, 4 May 2012 11:52:09 +0800
Subject: [PATCH 090/903] MDL-30912 - lib - A tidy up of the submit url jump
 functions for greater ease with accessability.

---
 lib/javascript-static.js |   27 +++++++++++++++------------
 lib/outputrenderers.php  |    2 +-
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 6bf2e28..ed9aaba 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -381,26 +381,26 @@ M.util.init_select_autosubmit = function(Y, formid, selectid, nothing) {
                     if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
                         //prevent event bubbling and detach handlers to prevent multiple submissions caused by double clicking
                         e.halt();
-                        paramobject.eventkeypress.detach();
-                        paramobject.eventblur.detach();
                         paramobject.eventchangeorblur.detach();
-
                         this.submit();
                     }
                 };
-                // Attach the change event to the keypress, blur, and click actions.
+
+                var changedown = function(e, paramobject) {
+                    if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
+                        if(e.keyCode == 13) {
+                            form.submit();
+                        }
+                    }
+                }
+
+                // Attach the change event to the keydown and click actions.
                 // We don't use the change event because IE fires it on every arrow up/down
                 // event.... usability
                 var paramobject = new Object();
                 paramobject.lastindex = select.get('selectedIndex');
-                paramobject.eventkeypress = Y.on('key', processchange, select, 'press:13', form, paramobject);
-                paramobject.eventblur = select.on('blur', processchange, form, paramobject);
-                //little hack for chrome that need onChange event instead of onClick - see MDL-23224
-                if (Y.UA.webkit) {
-                    paramobject.eventchangeorblur = select.on('change', processchange, form, paramobject);
-                } else {
-                    paramobject.eventchangeorblur = select.on('click', processchange, form, paramobject);
-                }
+                paramobject.eventchangeorblur = select.on('click', processchange, form, paramobject);
+                paramobject.eventkeypress = Y.on('keydown', changedown, select, '', form, paramobject);
             }
         }
     });
@@ -408,6 +408,9 @@ M.util.init_select_autosubmit = function(Y, formid, selectid, nothing) {
 
 /**
  * Attach handler to url_select
+ * Deprecated from 2.3 onwards.
+ * Please use @see init_select_autosubmit() for redirecting to a url (above).
+ * This function has accessability issues and also does not use the formid passed through as a parameter.
  */
 M.util.init_url_select = function(Y, formid, selectid, nothing) {
     YUI(M.yui.loader).use('node', function(Y) {
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 697ca6f..1d16603 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1472,7 +1472,7 @@ class core_renderer extends renderer_base {
             $go = html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('go')));
             $output .= html_writer::tag('noscript', html_writer::tag('div', $go), array('style'=>'inline'));
             $nothing = empty($select->nothing) ? false : key($select->nothing);
-            $output .= $this->page->requires->js_init_call('M.util.init_url_select', array($select->formid, $select->attributes['id'], $nothing));
+            $output .= $this->page->requires->js_init_call('M.util.init_select_autosubmit', array($select->formid, $select->attributes['id'], $nothing));
         } else {
             $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>$select->showbutton));
         }
-- 
1.7.9.5


From 60a72a03b25a87e1df8bfe8e8ce0f67cddbafe53 Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Thu, 21 Jun 2012 16:24:40 +0100
Subject: [PATCH 091/903] MDL-33937 Paged course view: Allows view of sections
 that are not visible

---
 course/view.php    |   14 ++++++++++++--
 lib/modinfolib.php |   12 ++++++++++--
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/course/view.php b/course/view.php
index e4a18cd..ad495dd 100644
--- a/course/view.php
+++ b/course/view.php
@@ -99,8 +99,18 @@
     $infoid = $course->id;
     if(!empty($section)) {
         $loglabel = 'view section';
-        $sectionparams = array('course' => $course->id, 'section' => $section);
-        $coursesections = $DB->get_record('course_sections', $sectionparams, 'id', MUST_EXIST);
+
+        // Get section details and check it exists.
+        $modinfo = get_fast_modinfo($course);
+        $coursesections = $modinfo->get_section_info($section, MUST_EXIST);
+
+        // Check user is allowed to see it.
+        if (!$coursesections->uservisible) {
+            // Note: We actually already know they don't have this capability
+            // or uservisible would have been true; this is just to get the
+            // correct error message shown.
+            require_capability('moodle/course:viewhiddensections', $context);
+        }
         $infoid = $coursesections->id;
         $logparam .= '&sectionid='. $infoid;
     }
diff --git a/lib/modinfolib.php b/lib/modinfolib.php
index bcbb7ec..f22f697 100644
--- a/lib/modinfolib.php
+++ b/lib/modinfolib.php
@@ -202,9 +202,17 @@ class course_modinfo extends stdClass {
     /**
      * Gets data about specific numbered section.
      * @param int $sectionnumber Number (not id) of section
-     * @return section_info Information for numbered section
+     * @param int $strictness Use MUST_EXIST to throw exception if it doesn't
+     * @return section_info Information for numbered section or null if not found
      */
-    public function get_section_info($sectionnumber) {
+    public function get_section_info($sectionnumber, $strictness = IGNORE_MISSING) {
+        if (!array_key_exists($sectionnumber, $this->sectioninfo)) {
+            if ($strictness === MUST_EXIST) {
+                throw new moodle_exception('sectionnotexist');
+            } else {
+                return null;
+            }
+        }
         return $this->sectioninfo[$sectionnumber];
     }
 
-- 
1.7.9.5


From 3e1648723ffd71c4340d84ed53c420945305671c Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 26 Jun 2012 17:28:03 +0800
Subject: [PATCH 092/903] MDL-33828 Portfolio: prevent notices while exporting
 to portfolios

---
 lib/portfolio/exporter.php        |   21 ++++++++++++---------
 mod/assign/portfolio_callback.php |    4 +++-
 portfolio/boxnet/lib.php          |    5 +++--
 3 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/lib/portfolio/exporter.php b/lib/portfolio/exporter.php
index 3baf0b5..79bfc8f 100644
--- a/lib/portfolio/exporter.php
+++ b/lib/portfolio/exporter.php
@@ -722,15 +722,18 @@ class portfolio_exporter {
         if ($this->get('user')->id != $USER->id) { // make sure it belongs to the right user
             throw new portfolio_exception('notyours', 'portfolio');
         }
-        if (!$readonly && $this->get('instance') && !$this->get('instance')->allows_multiple_exports()
-            && ($already = portfolio_existing_exports($this->get('user')->id, $this->get('instance')->get('plugin')))
-            && array_shift(array_keys($already)) != $this->get('id')
-        ) {
-            $a = (object)array(
-                'plugin'  => $this->get('instance')->get('plugin'),
-                'link'    => $CFG->wwwroot . '/user/portfoliologs.php',
-            );
-            throw new portfolio_exception('nomultipleexports', 'portfolio', '', $a);
+        if (!$readonly && $this->get('instance') && !$this->get('instance')->allows_multiple_exports()) {
+            $already = portfolio_existing_exports($this->get('user')->id, $this->get('instance')->get('plugin'));
+            $already = array_keys($already);
+
+            if (array_shift($already) != $this->get('id')) {
+
+                $a = (object)array(
+                    'plugin'  => $this->get('instance')->get('plugin'),
+                    'link'    => $CFG->wwwroot . '/user/portfoliologs.php',
+                );
+                throw new portfolio_exception('nomultipleexports', 'portfolio', '', $a);
+            }
         }
         if (!$this->caller->check_permissions()) { // recall the caller permission check
             throw new portfolio_caller_exception('nopermissions', 'portfolio', $this->caller->get_return_url());
diff --git a/mod/assign/portfolio_callback.php b/mod/assign/portfolio_callback.php
index cee75bc..71e6d82 100644
--- a/mod/assign/portfolio_callback.php
+++ b/mod/assign/portfolio_callback.php
@@ -45,6 +45,9 @@ class assign_portfolio_caller extends portfolio_module_caller_base {
     /** @var int callback arg - the id of submission we export */
     protected $sid;
 
+    /** @var string component of the submission files we export*/
+    protected $component;
+
     /** @var string callback arg - the area of submission files we export */
     protected $area;
 
@@ -60,7 +63,6 @@ class assign_portfolio_caller extends portfolio_module_caller_base {
     /** @var string callback arg - the name of the editor field we export */
     protected $editor;
 
-
    /**
     * callback arg for a single file export
     */
diff --git a/portfolio/boxnet/lib.php b/portfolio/boxnet/lib.php
index 120f61e..a793767 100644
--- a/portfolio/boxnet/lib.php
+++ b/portfolio/boxnet/lib.php
@@ -37,8 +37,9 @@ class portfolio_plugin_boxnet extends portfolio_plugin_push_base {
                 )
             );
             if (array_key_exists('status', $return) && $return['status'] == 'upload_ok'
-                && array_key_exists('id', $return) && count($return['id']) == 1) {
-                $this->rename_file($return['id'][array_pop(array_keys($return['id']))], $file->get_filename());
+                    && array_key_exists('id', $return) && count($return['id']) == 1) {
+                $returnid = array_keys($return['id']);
+                $this->rename_file($return['id'][array_pop($returnid)], $file->get_filename());
                 // if this fails, the file was sent but not renamed - this triggers a warning but is not fatal.
             }
         }
-- 
1.7.9.5


From 28f23328c54f12740897ac5d02f2063f10bc021c Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 15 May 2012 21:53:09 +0400
Subject: [PATCH 093/903] MDL-32787 user: rule required for custom profile
 fields applies to all users editing own profile

---
 user/edit.php              |    3 ++-
 user/edit_form.php         |   27 ++++++++++++++++-----------
 user/editadvanced.php      |    3 ++-
 user/editadvanced_form.php |   24 ++++++++++++++----------
 user/profile/lib.php       |    8 +++++---
 5 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/user/edit.php b/user/edit.php
index ca52ed3..7644861 100644
--- a/user/edit.php
+++ b/user/edit.php
@@ -165,7 +165,8 @@ $user->imagefile = $draftitemid;
 //create form
 $userform = new user_edit_form(null, array(
     'editoroptions' => $editoroptions,
-    'filemanageroptions' => $filemanageroptions));
+    'filemanageroptions' => $filemanageroptions,
+    'userid' => $user->id));
 if (empty($user->country)) {
     // MDL-16308 - we must unset the value here so $CFG->country can be used as default one
     unset($user->country);
diff --git a/user/edit_form.php b/user/edit_form.php
index e53672f..b077a0c 100644
--- a/user/edit_form.php
+++ b/user/edit_form.php
@@ -10,18 +10,23 @@ class user_edit_form extends moodleform {
 
     // Define the form
     function definition () {
-        global $CFG, $COURSE;
+        global $CFG, $COURSE, $USER;
 
         $mform =& $this->_form;
-        if (is_array($this->_customdata) && array_key_exists('editoroptions', $this->_customdata)) {
-            $editoroptions = $this->_customdata['editoroptions'];
-        } else {
-            $editoroptions = null;
-        }
-        if (is_array($this->_customdata) && array_key_exists('filemanageroptions', $this->_customdata)) {
-            $filemanageroptions = $this->_customdata['filemanageroptions'];
-        } else {
-            $filemanageroptions = null;
+        $editoroptions = null;
+        $filemanageroptions = null;
+        $userid = $USER->id;
+
+        if (is_array($this->_customdata)) {
+            if (array_key_exists('editoroptions', $this->_customdata)) {
+                $editoroptions = $this->_customdata['editoroptions'];
+            }
+            if (array_key_exists('filemanageroptions', $this->_customdata)) {
+                $filemanageroptions = $this->_customdata['filemanageroptions'];
+            }
+            if (array_key_exists('userid', $this->_customdata)) {
+                $userid = $this->_customdata['userid'];
+            }
         }
         //Accessibility: "Required" is bad legend text.
         $strgeneral  = get_string('general');
@@ -47,7 +52,7 @@ class user_edit_form extends moodleform {
         }
 
         /// Next the customisable profile fields
-        profile_definition($mform);
+        profile_definition($mform, $userid);
 
         $this->add_action_buttons(false, get_string('updatemyprofile'));
     }
diff --git a/user/editadvanced.php b/user/editadvanced.php
index 5226c0a..cdf03bd 100644
--- a/user/editadvanced.php
+++ b/user/editadvanced.php
@@ -146,7 +146,8 @@ $user->imagefile = $draftitemid;
 //create form
 $userform = new user_editadvanced_form(null, array(
     'editoroptions' => $editoroptions,
-    'filemanageroptions' => $filemanageroptions));
+    'filemanageroptions' => $filemanageroptions,
+    'userid' => $user->id));
 $userform->set_data($user);
 
 if ($usernew = $userform->get_data()) {
diff --git a/user/editadvanced_form.php b/user/editadvanced_form.php
index 7092f02..dbe6d82 100644
--- a/user/editadvanced_form.php
+++ b/user/editadvanced_form.php
@@ -13,16 +13,20 @@ class user_editadvanced_form extends moodleform {
         global $USER, $CFG, $COURSE;
 
         $mform =& $this->_form;
+        $editoroptions = null;
+        $filemanageroptions = null;
+        $userid = $USER->id;
 
-        if (is_array($this->_customdata) && array_key_exists('editoroptions', $this->_customdata)) {
-            $editoroptions = $this->_customdata['editoroptions'];
-        } else {
-            $editoroptions = null;
-        }
-        if (is_array($this->_customdata) && array_key_exists('filemanageroptions', $this->_customdata)) {
-            $filemanageroptions = $this->_customdata['filemanageroptions'];
-        } else {
-            $filemanageroptions = null;
+        if (is_array($this->_customdata)) {
+            if (array_key_exists('editoroptions', $this->_customdata)) {
+                $editoroptions = $this->_customdata['editoroptions'];
+            }
+            if (array_key_exists('filemanageroptions', $this->_customdata)) {
+                $filemanageroptions = $this->_customdata['filemanageroptions'];
+            }
+            if (array_key_exists('userid', $this->_customdata)) {
+                $userid = $this->_customdata['userid'];
+            }
         }
 
         //Accessibility: "Required" is bad legend text.
@@ -66,7 +70,7 @@ class user_editadvanced_form extends moodleform {
         useredit_shared_definition($mform, $editoroptions, $filemanageroptions);
 
         /// Next the customisable profile fields
-        profile_definition($mform);
+        profile_definition($mform, $userid);
 
         $this->add_action_buttons(false, get_string('updatemyprofile'));
     }
diff --git a/user/profile/lib.php b/user/profile/lib.php
index 54649d7..fd30d58 100644
--- a/user/profile/lib.php
+++ b/user/profile/lib.php
@@ -169,7 +169,8 @@ class profile_field_base {
      * @param   object   instance of the moodleform class
      */
     function edit_field_set_required($mform) {
-        if ($this->is_required() and !has_capability('moodle/user:update', get_context_instance(CONTEXT_SYSTEM))) {
+        global $USER;
+        if ($this->is_required() && ($this->userid == $USER->id)) {
             $mform->addRule($this->inputname, get_string('required'), 'required', null, 'client');
         }
     }
@@ -352,8 +353,9 @@ function profile_load_data($user) {
 /**
  * Print out the customisable categories and fields for a users profile
  * @param  object   instance of the moodleform class
+ * @param int $userid id of user whose profile is being edited.
  */
-function profile_definition($mform) {
+function profile_definition($mform, $userid = 0) {
     global $CFG, $DB;
 
     // if user is "admin" fields are displayed regardless
@@ -377,7 +379,7 @@ function profile_definition($mform) {
                     foreach ($fields as $field) {
                         require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
                         $newfield = 'profile_field_'.$field->datatype;
-                        $formfield = new $newfield($field->id);
+                        $formfield = new $newfield($field->id, $userid);
                         $formfield->edit_field($mform);
                     }
                 }
-- 
1.7.9.5


From a5f68fb2c2149b30d32f81373e3ef17e3733f5f5 Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Wed, 13 Jun 2012 16:45:42 +0100
Subject: [PATCH 094/903] MDL-33426 Completion: Multilang activity names wrong
 in alt/title

---
 course/lib.php            |   10 +++++-----
 report/progress/index.php |    3 ++-
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index 82f2b8c..374b309 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1470,9 +1470,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
             // 2. the activity has dates set which do not include current, or
             // 3. the activity has any other conditions set (regardless of whether
             //    current user meets them)
-            $canviewhidden = has_capability(
-                'moodle/course:viewhiddenactivities',
-                get_context_instance(CONTEXT_MODULE, $mod->id));
+            $modcontext = context_module::instance($mod->id);
+            $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext);
             $accessiblebutdim = false;
             if ($canviewhidden) {
                 $accessiblebutdim = !$mod->visible;
@@ -1684,9 +1683,10 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                 }
                 if ($completionicon) {
                     $imgsrc = $OUTPUT->pix_url('i/completion-'.$completionicon);
-                    $imgalt = s(get_string('completion-alt-'.$completionicon, 'completion', $mod->name));
+                    $formattedname = format_string($mod->name, true, array('context' => $modcontext));
+                    $imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname);
                     if ($completion == COMPLETION_TRACKING_MANUAL && !$isediting) {
-                        $imgtitle = s(get_string('completion-title-'.$completionicon, 'completion', $mod->name));
+                        $imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname);
                         $newstate =
                             $completiondata->completionstate==COMPLETION_COMPLETE
                             ? COMPLETION_INCOMPLETE
diff --git a/report/progress/index.php b/report/progress/index.php
index 318903d..7192f2f 100644
--- a/report/progress/index.php
+++ b/report/progress/index.php
@@ -386,12 +386,13 @@ foreach($progress as $user) {
             ($activity->completion==COMPLETION_TRACKING_AUTOMATIC ? 'auto' : 'manual').
             '-'.$completiontype;
 
+        $modcontext = context_module::instance($activity->id);
         $describe = get_string('completion-' . $completiontype, 'completion');
         $a=new StdClass;
         $a->state=$describe;
         $a->date=$date;
         $a->user=fullname($user);
-        $a->activity=strip_tags($activity->name);
+        $a->activity = format_string($activity->name, true, array('context' => $modcontext));
         $fulldescribe=get_string('progress-title','completion',$a);
 
         if ($csv) {
-- 
1.7.9.5


From e3f4094ac826f3f3016b22b95ba84daee20dbc91 Mon Sep 17 00:00:00 2001
From: Kevin Wiliarty <kevin.wiliarty@gmail.com>
Date: Tue, 19 Jun 2012 14:14:49 -0400
Subject: [PATCH 095/903] MDL-33749 follow redirects for URL downloader

---
 repository/url/lib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/repository/url/lib.php b/repository/url/lib.php
index 20725c8..ba247ff 100644
--- a/repository/url/lib.php
+++ b/repository/url/lib.php
@@ -127,6 +127,7 @@ EOD;
         }
         $this->processedfiles[] = $url;
         $curl = new curl;
+        $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => true, 'CURLOPT_MAXREDIRS' => 3));
         $msg = $curl->head($url);
         $info = $curl->get_info();
         if ($info['http_code'] != 200) {
-- 
1.7.9.5


From 3bcca35591b11e0ecc4d4ca4e9e63b7be55cf045 Mon Sep 17 00:00:00 2001
From: Jonathan Harker <jonathan@catalyst.net.nz>
Date: Wed, 20 Jun 2012 15:45:47 +1200
Subject: [PATCH 096/903] MDL-27125 better manage file handles when
 downloading multiple files.

Based on Dongsheng Cai's branch: s11_MDL-27125_curl_file_handler_master
---
 lib/filelib.php             |   49 ++++++++++++++++++++++++++++++++++++-------
 repository/alfresco/lib.php |    1 +
 repository/flickr/lib.php   |    1 +
 3 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index 523c643..f1e44f3 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -3006,14 +3006,36 @@ class curl {
      * Calls {@link multi()} with specific download headers
      *
      * <code>
-     * $c = new curl;
+     * $c = new curl();
+     * $file1 = fopen('a', 'wb');
+     * $file2 = fopen('b', 'wb');
      * $c->download(array(
-     *              array('url'=>'http://localhost/', 'file'=>fopen('a', 'wb')),
-     *              array('url'=>'http://localhost/20/', 'file'=>fopen('b', 'wb'))
+     *     array('url'=>'http://localhost/', 'file'=>$file1),
+     *     array('url'=>'http://localhost/20/', 'file'=>$file2)
+     * ));
+     * fclose($file1);
+     * fclose($file2);
+     * </code>
+     *
+     * or
+     *
+     * <code>
+     * $c = new curl();
+     * $c->download(array(
+     *              array('url'=>'http://localhost/', 'filepath'=>'/tmp/file1.tmp'),
+     *              array('url'=>'http://localhost/20/', 'filepath'=>'/tmp/file2.tmp')
      *              ));
      * </code>
      *
-     * @param array $requests An array of files to request
+     * @param array $requests An array of files to request {
+     *                  url => url to download the file [required]
+     *                  file => file handler, or
+     *                  filepath => file path
+     * }
+     * If 'file' and 'filepath' parameters are both specified in one request, the
+     * open file handle in the 'file' parameter will take precedence and 'filepath'
+     * will be ignored.
+     *
      * @param array $options An array of options to set
      * @return array An array of results
      */
@@ -3037,11 +3059,15 @@ class curl {
         $results = array();
         $main    = curl_multi_init();
         for ($i = 0; $i < $count; $i++) {
-            $url = $requests[$i];
-            foreach($url as $n=>$v){
-                $options[$n] = $url[$n];
+            if (!empty($requests[$i]['filepath']) and empty($requests[$i]['file'])) {
+                // open file
+                $requests[$i]['file'] = fopen($requests[$i]['filepath'], 'w');
+                $requests[$i]['auto-handle'] = true;
+            }
+            foreach($requests[$i] as $n=>$v){
+                $options[$n] = $v;
             }
-            $handles[$i] = curl_init($url['url']);
+            $handles[$i] = curl_init($requests[$i]['url']);
             $this->apply_opt($handles[$i], $options);
             curl_multi_add_handle($main, $handles[$i]);
         }
@@ -3058,6 +3084,13 @@ class curl {
             curl_multi_remove_handle($main, $handles[$i]);
         }
         curl_multi_close($main);
+
+        for ($i = 0; $i < $count; $i++) {
+            if (!empty($requests[$i]['filepath']) and !empty($requests[$i]['auto-handle'])) {
+                // close file handler if file is opened in this function
+                fclose($requests[$i]['file']);
+            }
+        }
         return $results;
     }
 
diff --git a/repository/alfresco/lib.php b/repository/alfresco/lib.php
index 705e6e9..b5a871f 100644
--- a/repository/alfresco/lib.php
+++ b/repository/alfresco/lib.php
@@ -206,6 +206,7 @@ class repository_alfresco extends repository {
         $fp = fopen($path, 'w');
         $c = new curl;
         $c->download(array(array('url'=>$url, 'file'=>$fp)));
+        fclose($fp);
         return array('path'=>$path, 'url'=>$url);
     }
 
diff --git a/repository/flickr/lib.php b/repository/flickr/lib.php
index 6886638..7d3dcd6 100644
--- a/repository/flickr/lib.php
+++ b/repository/flickr/lib.php
@@ -258,6 +258,7 @@ class repository_flickr extends repository {
         $c->download(array(
             array('url'=>$url, 'file'=>$fp)
         ));
+        fclose($fp);
         return array('path'=>$path, 'url'=>$url);
     }
 
-- 
1.7.9.5


From 8530aac4a8e249a12eb033ec5285077ac8f5254e Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Sun, 27 May 2012 12:49:10 +0800
Subject: [PATCH 097/903] MDL-33466: Group restriction should hide activity
 even with 'show availability' option

This is a modified version of fix by Luke Tucker at NetSpot - thanks.
---
 lib/modinfolib.php |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/modinfolib.php b/lib/modinfolib.php
index f22f697..db9b7f6 100644
--- a/lib/modinfolib.php
+++ b/lib/modinfolib.php
@@ -1086,18 +1086,24 @@ class cm_info extends stdClass {
         $modcontext = get_context_instance(CONTEXT_MODULE, $this->id);
         $userid = $this->modinfo->get_user_id();
         $this->uservisible = true;
+        // Check visibility/availability conditions.
         if ((!$this->visible or !$this->available) and
                 !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
             // If the activity is hidden or unavailable, and you don't have viewhiddenactivities,
-            // set it so that user can't see or access it
+            // set it so that user can't see or access it.
             $this->uservisible = false;
-        } else if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
+        }
+        // Check group membership. The grouping option makes the activity
+        // completely invisible as it does not apply to the user at all.
+        if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
                 and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
             // If the activity has 'group members only' and you don't have accessallgroups...
             $groups = $this->modinfo->get_groups($this->groupingid);
             if (empty($groups)) {
                 // ...and you don't belong to a group, then set it so you can't see/access it
                 $this->uservisible = false;
+                // Ensure activity is completely hidden from user.
+                $this->showavailability = 0;
             }
         }
     }
-- 
1.7.9.5


From 9f6f18d2c24a8e191c13ab99425956c9759cfb2c Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 22 Jun 2012 14:42:20 +0800
Subject: [PATCH 098/903] MDL-31692 mod_lti - ensure that various mforms are
 used properly

* typesettings.php and instructor_edit_tool_type.php are tided
   up properly to ensure proper use for form data
* An incorrect PARAM type is corrected for typename
---
 mod/lti/edit_form.php                 |    2 +-
 mod/lti/instructor_edit_tool_type.php |    9 +--
 mod/lti/typessettings.php             |  131 ++++++++-------------------------
 3 files changed, 34 insertions(+), 108 deletions(-)

diff --git a/mod/lti/edit_form.php b/mod/lti/edit_form.php
index 3cf2ef8..fec78ee 100644
--- a/mod/lti/edit_form.php
+++ b/mod/lti/edit_form.php
@@ -62,7 +62,7 @@ class mod_lti_edit_types_form extends moodleform{
         $mform->addElement('header', 'setup', get_string('tool_settings', 'lti'));
 
         $mform->addElement('text', 'lti_typename', get_string('typename', 'lti'));
-        $mform->setType('lti_typename', PARAM_INT);
+        $mform->setType('lti_typename', PARAM_TEXT);
         $mform->addHelpButton('lti_typename', 'typename', 'lti');
         $mform->addRule('lti_typename', null, 'required', null, 'client');
 
diff --git a/mod/lti/instructor_edit_tool_type.php b/mod/lti/instructor_edit_tool_type.php
index b0fe496..c65b3f4 100644
--- a/mod/lti/instructor_edit_tool_type.php
+++ b/mod/lti/instructor_edit_tool_type.php
@@ -47,9 +47,8 @@ if (!empty($typeid)) {
     }
 }
 
-$data = data_submitted();
-
-if (isset($data->submitbutton) && confirm_sesskey()) {
+$form = new mod_lti_edit_types_form();
+if ($data = $form->get_data()) {
     $type = new stdClass();
 
     if (!empty($typeid)) {
@@ -96,7 +95,7 @@ if (isset($data->submitbutton) && confirm_sesskey()) {
 
         die;
     }
-} else if (isset($data->cancel)) {
+} else if ($form->is_cancelled()) {
     $script = "
         <html>
             <script type=\"text/javascript\">
@@ -120,10 +119,8 @@ echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('toolsetup', 'lti'));
 
 if ($action == 'add') {
-    $form = new mod_lti_edit_types_form();
     $form->display();
 } else if ($action == 'edit') {
-    $form = new mod_lti_edit_types_form();
     $type = lti_get_type_type_config($typeid);
     $form->set_data($type);
     $form->display();
diff --git a/mod/lti/typessettings.php b/mod/lti/typessettings.php
index d6d2d18..f88cb5e 100644
--- a/mod/lti/typessettings.php
+++ b/mod/lti/typessettings.php
@@ -53,41 +53,42 @@ require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->dirroot.'/mod/lti/edit_form.php');
 require_once($CFG->dirroot.'/mod/lti/locallib.php');
 
-$section      = 'modsettinglti';
-$return       = optional_param('return', '', PARAM_ALPHA);
-$adminediting = optional_param('adminedit', -1, PARAM_BOOL);
 $action       = optional_param('action', null, PARAM_ACTION);
 $id           = optional_param('id', null, PARAM_INT);
-$useexisting  = optional_param('useexisting', null, PARAM_INT);
-$definenew    = optional_param('definenew', null, PARAM_INT);
+$tab          = optional_param('tab', '', PARAM_ALPHAEXT);
 
 // no guest autologin
 require_login(0, false);
+
 $pageurl = new moodle_url('/mod/lti/typessettings.php');
+if (!empty($id)) {
+    $pageurl->param('id', $id);
+}
 $PAGE->set_url($pageurl);
 
 admin_externalpage_setup('managemodules'); // Hacky solution for printing the admin page
 
-$tab = optional_param('tab', '', PARAM_ALPHAEXT);
 $redirect = "$CFG->wwwroot/$CFG->admin/settings.php?section=modsettinglti&tab={$tab}";
 
-// WRITING SUBMITTED DATA (IF ANY)
-
-$statusmsg = '';
-$errormsg  = '';
-$focus = '';
+require_sesskey();
 
-$data = data_submitted();
-
-// Any posted data & any action
-if (!empty($data) || !empty($action)) {
-    require_sesskey();
+if ($action == 'accept') {
+    lti_set_state_for_type($id, LTI_TOOL_STATE_CONFIGURED);
+    redirect($redirect);
+} else if ($action == 'reject') {
+    lti_set_state_for_type($id, LTI_TOOL_STATE_REJECTED);
+    redirect($redirect);
+} else if ($action == 'delete') {
+    lti_delete_type($id);
+    redirect($redirect);
 }
 
-if (isset($data->submitbutton)) {
+$form = new mod_lti_edit_types_form($pageurl, (object)array('isadmin' => true));
+
+if ($data = $form->get_data()) {
     $type = new stdClass();
 
-    if (isset($id)) {
+    if (!empty($id)) {
         $type->id = $id;
 
         lti_update_type($type, $data);
@@ -100,94 +101,22 @@ if (isset($data->submitbutton)) {
 
         redirect($redirect);
     }
-
-} else if (isset($data->cancel)) {
-    redirect($redirect);
-
-} else if ($action == 'accept') {
-    lti_set_state_for_type($id, LTI_TOOL_STATE_CONFIGURED);
-    redirect($redirect);
-
-} else if ($action == 'reject') {
-    lti_set_state_for_type($id, LTI_TOOL_STATE_REJECTED);
-    redirect($redirect);
-
-} else if ($action == 'delete') {
-    lti_delete_type($id);
+} else if ($form->is_cancelled()) {
     redirect($redirect);
 }
 
-// print header stuff
-$PAGE->set_focuscontrol($focus);
-if (empty($SITE->fullname)) {
-    $PAGE->set_title($settingspage->visiblename);
-    $PAGE->set_heading($settingspage->visiblename);
-
-    $PAGE->navbar->add(get_string('lti_administration', 'lti'), $CFG->wwwroot.'/admin/settings.php?section=modsettinglti');
-
-    echo $OUTPUT->header();
-
-    echo $OUTPUT->box(get_string('configintrosite', 'admin'));
-
-    if ($errormsg !== '') {
-        echo $OUTPUT->notification($errormsg);
-
-    } else if ($statusmsg !== '') {
-        echo $OUTPUT->notification($statusmsg, 'notifysuccess');
-    }
-
-    echo '<form action="typesettings.php" method="post" id="'.$id.'" >';
-    echo '<div class="settingsform clearfix">';
-    echo html_writer::input_hidden_params($PAGE->url);
-    echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
-    echo '<input type="hidden" name="return" value="'.$return.'" />';
-
-    echo $settingspage->output_html();
-
-    echo '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges', 'admin').'" /></div>';
-
-    echo '</div>';
-    echo '</form>';
-
-} else {
-    if ($PAGE->user_allowed_editing()) {
-        $url = clone($PAGE->url);
-        if ($PAGE->user_is_editing()) {
-            $caption = get_string('blockseditoff');
-            $url->param('adminedit', 'off');
-        } else {
-            $caption = get_string('blocksediton');
-            $url->param('adminedit', 'on');
-        }
-        $buttons = $OUTPUT->single_button($url, $caption, 'get');
-    }
-
-    $PAGE->set_title("$SITE->shortname: " . get_string('toolsetup', 'lti'));
-
-    $PAGE->navbar->add(get_string('lti_administration', 'lti'), $CFG->wwwroot.'/admin/settings.php?section=modsettinglti');
+$PAGE->set_title("$SITE->shortname: " . get_string('toolsetup', 'lti'));
+$PAGE->navbar->add(get_string('lti_administration', 'lti'), $CFG->wwwroot.'/admin/settings.php?section=modsettinglti');
 
-    echo $OUTPUT->header();
-
-    if ($errormsg !== '') {
-        echo $OUTPUT->notification($errormsg);
-
-    } else if ($statusmsg !== '') {
-        echo $OUTPUT->notification($statusmsg, 'notifysuccess');
-    }
-
-    echo $OUTPUT->heading(get_string('toolsetup', 'lti'));
-    echo $OUTPUT->box_start('generalbox');
-    if ($action == 'add') {
-        $form = new mod_lti_edit_types_form($pageurl, (object)array('isadmin' => true));
-        $form->display();
-    } else if ($action == 'update') {
-        $form = new mod_lti_edit_types_form('typessettings.php?id='.$id, (object)array('isadmin' => true));
-        $type = lti_get_type_type_config($id);
-        $form->set_data($type);
-        $form->display();
-    }
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('toolsetup', 'lti'));
+echo $OUTPUT->box_start('generalbox');
 
-    echo $OUTPUT->box_end();
+if ($action == 'update') {
+    $type = lti_get_type_type_config($id);
+    $form->set_data($type);
 }
 
+$form->display();
+echo $OUTPUT->box_end();
 echo $OUTPUT->footer();
-- 
1.7.9.5


From f2b7928df7b043b5f895b76b2b988ff82d8906a5 Mon Sep 17 00:00:00 2001
From: Chris Scribner <scriby@gmail.com>
Date: Wed, 13 Jun 2012 14:19:35 -0400
Subject: [PATCH 099/903] MDL-32614: Removing code which disassociated LTI
 instances from their tool types upon restore.

---
 mod/lti/backup/moodle2/restore_lti_stepslib.php |   18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/mod/lti/backup/moodle2/restore_lti_stepslib.php b/mod/lti/backup/moodle2/restore_lti_stepslib.php
index 8589e2e..2866918 100644
--- a/mod/lti/backup/moodle2/restore_lti_stepslib.php
+++ b/mod/lti/backup/moodle2/restore_lti_stepslib.php
@@ -74,29 +74,11 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
 
         $newitemid = lti_add_instance($data, null);
 
-        // insert the basiclti record
-        //$newitemid = $DB->insert_record('lti', $data);
         // immediately after inserting "activity" record, call this
         $this->apply_activity_instance($newitemid);
     }
 
     protected function after_execute() {
-        global $DB;
-
-        $basicltis = $DB->get_records('lti');
-        foreach ($basicltis as $basiclti) {
-            if (!$DB->get_record('lti_types_config',
-                array('typeid' => $basiclti->typeid, 'name' => 'toolurl', 'value' => $basiclti->toolurl))) {
-
-                $basiclti->typeid = 0;
-            }
-
-            $basiclti->placementsecret = uniqid('', true);
-            $basiclti->timeplacementsecret = time();
-
-            $DB->update_record('lti', $basiclti);
-        }
-
         // Add basiclti related files, no need to match by itemname (just internally handled context)
         $this->add_related_files('mod_lti', 'intro', null);
     }
-- 
1.7.9.5


From ccef7fe8d0db11a40472219bb8a9ef8a107ad2ce Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 4 Jul 2012 02:01:21 +0200
Subject: [PATCH 100/903] MDL-32614 lti: on restore, clean any typeid to
 convert the tool to selfcontained.

This is known to be imperfect, awaiting for MDL-34161 to fix the whole thing. Also,
unrelated, there are some basiclti => lti replacements.
---
 mod/lti/backup/moodle2/backup_lti_stepslib.php  |   12 +++++++-----
 mod/lti/backup/moodle2/restore_lti_stepslib.php |    9 +++++++--
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/mod/lti/backup/moodle2/backup_lti_stepslib.php b/mod/lti/backup/moodle2/backup_lti_stepslib.php
index c9c2a24..b728116 100644
--- a/mod/lti/backup/moodle2/backup_lti_stepslib.php
+++ b/mod/lti/backup/moodle2/backup_lti_stepslib.php
@@ -56,11 +56,13 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
 
     protected function define_structure() {
 
+        // TODO: MDL-34161 - Fix restore to support course/site tools & submissions.
+
         // To know if we are including userinfo
         $userinfo = $this->get_setting_value('userinfo');
 
         // Define each element separated
-        $basiclti = new backup_nested_element('lti', array('id'), array(
+        $lti = new backup_nested_element('lti', array('id'), array(
             'name',
             'intro',
             'introformat',
@@ -86,15 +88,15 @@ class backup_lti_activity_structure_step extends backup_activity_structure_step
         // (none)
 
         // Define sources
-        $basiclti->set_source_table('lti', array('id' => backup::VAR_ACTIVITYID));
+        $lti->set_source_table('lti', array('id' => backup::VAR_ACTIVITYID));
 
         // Define id annotations
         // (none)
 
         // Define file annotations
-        $basiclti->annotate_files('mod_lti', 'intro', null); // This file areas haven't itemid
+        $lti->annotate_files('mod_lti', 'intro', null); // This file areas haven't itemid
 
-        // Return the root element (basiclti), wrapped into standard activity structure
-        return $this->prepare_activity_structure($basiclti);
+        // Return the root element (lti), wrapped into standard activity structure
+        return $this->prepare_activity_structure($lti);
     }
 }
diff --git a/mod/lti/backup/moodle2/restore_lti_stepslib.php b/mod/lti/backup/moodle2/restore_lti_stepslib.php
index 2866918..544955a 100644
--- a/mod/lti/backup/moodle2/restore_lti_stepslib.php
+++ b/mod/lti/backup/moodle2/restore_lti_stepslib.php
@@ -50,7 +50,7 @@
 defined('MOODLE_INTERNAL') || die;
 
 /**
- * Structure step to restore one basiclti activity
+ * Structure step to restore one lti activity
  */
 class restore_lti_activity_structure_step extends restore_activity_structure_step {
 
@@ -71,6 +71,11 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
         $data->course = $this->get_courseid();
 
         require_once($CFG->dirroot.'/mod/lti/lib.php');
+        // Clean any course or site typeid. All modules
+        // are restored as self-contained. Note this is
+        // an interim solution until the issue below is implemented.
+        // TODO: MDL-34161 - Fix restore to support course/site tools & submissions.
+        $data->typeid = 0;
 
         $newitemid = lti_add_instance($data, null);
 
@@ -79,7 +84,7 @@ class restore_lti_activity_structure_step extends restore_activity_structure_ste
     }
 
     protected function after_execute() {
-        // Add basiclti related files, no need to match by itemname (just internally handled context)
+        // Add lti related files, no need to match by itemname (just internally handled context)
         $this->add_related_files('mod_lti', 'intro', null);
     }
 }
-- 
1.7.9.5


From 9d5ced06c174df71cc1ef3c5748448b315a7fc4a Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 27 Jun 2012 10:05:12 +0800
Subject: [PATCH 101/903] MDL-34047 repository URL downloader must say that it
 returns only images

---
 repository/url/lib.php |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/repository/url/lib.php b/repository/url/lib.php
index ba247ff..1255570 100644
--- a/repository/url/lib.php
+++ b/repository/url/lib.php
@@ -228,5 +228,13 @@ EOD;
     public function get_file_source_info($url) {
         return $url;
     }
-}
 
+    /**
+     * file types supported by url downloader plugin
+     *
+     * @return array
+     */
+    public function supported_filetypes() {
+        return array('web_image');
+    }
+}
-- 
1.7.9.5


From a2c2ab3e1a51d8b8ddcd5ab451ccbcd5ba5557f1 Mon Sep 17 00:00:00 2001
From: Barbara Ramiro <barbara@moodle.com>
Date: Wed, 4 Jul 2012 10:11:48 +0800
Subject: [PATCH 102/903] MDL-33542, MDL-33542 Select dialogue details aligned

And loading gif smaller
---
 files/renderer.php               |   20 ++++++++------------
 theme/base/style/filemanager.css |    7 +++++--
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/files/renderer.php b/files/renderer.php
index 390ea95..d869270 100644
--- a/files/renderer.php
+++ b/files/renderer.php
@@ -229,7 +229,7 @@ class core_files_renderer extends plugin_renderer_base {
     <div class="filemanager-container"'.$containerstyletag.'>
         <div class="fm-content-wrapper">
             <div class="fp-content"></div>
-            <div class="fm-empty-container <!--mdl-align-->">
+            <div class="fm-empty-container">
                 <span class="dndupload-message">'.$strdndenabledinbox.'<br/><span class="dndupload-arrow"></span></span>
             </div>
             <div class="dndupload-target">'.$strdroptoupload.'<br/><span class="dndupload-arrow"></span></div>
@@ -379,8 +379,7 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <div class="filemanager fp-select">
     <div class="fp-select-loading">
-        <img src="'.$this->pix_url('i/loading').'" />
-        <p>'.get_string('loading', 'repository').'</p>
+        <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
     <form>
         <button class="{!}fp-file-download">'.get_string('download').'</button>
@@ -633,8 +632,7 @@ class core_files_renderer extends plugin_renderer_base {
 <div class="{!}fp-nextpage">
     <div class="fp-nextpage-link"><a href="#">'.get_string('more').'</a></div>
     <div class="fp-nextpage-loading">
-        <img src="'.$this->pix_url('i/loading').'" />
-        <p>'.get_string('loading', 'repository').'</p>
+        <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
 </div>';
         return preg_replace('/\{\!\}/', '', $rv);
@@ -672,19 +670,18 @@ class core_files_renderer extends plugin_renderer_base {
         $rv = '
 <div class="file-picker fp-select">
     <div class="fp-select-loading">
-        <img src="'.$this->pix_url('i/loading').'" />
-        <p>'.get_string('loading', 'repository').'</p>
+        <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
     <form>
         <table>
             <tr class="{!}fp-linktype-2">
-                <td></td>
+                <td class="mdl-right"></td>
                 <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefileinternal', 'repository').'</label></td></tr>
             <tr class="{!}fp-linktype-1">
-                <td></td>
+                <td class="mdl-right"></td>
                 <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefilelink', 'repository').'</label></td></tr>
             <tr class="{!}fp-linktype-4">
-                <td></td>
+                <td class="mdl-right"></td>
                 <td class="mdl-left"><input type="radio"/><label>&nbsp;'.get_string('makefilereference', 'repository').'</label></td></tr>
             <tr class="{!}fp-saveas">
                 <td class="mdl-right"><label>'.get_string('saveas', 'repository').'</label>:</td>
@@ -770,8 +767,7 @@ class core_files_renderer extends plugin_renderer_base {
         return '
 <div class="fp-content-loading">
     <div class="fp-content-center">
-        <img src="'.$this->pix_url('i/loading').'" />
-        <p>'.get_string('loading', 'repository').'</p>
+        <img src="'.$this->pix_url('i/loading_small').'" />
     </div>
 </div>';
     }
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index b9905b0..5c8c2e5 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -241,6 +241,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .fp-select .fp-select-loading {text-align: center;margin-top: 20px;}
 .fp-select .fp-hr {clear: both;height: 1px; background-color: #FFFFFF;border-bottom: 1px solid #BBBBBB;width: auto; margin: 10px 0;}
 .fp-select table {padding: 0 0 10px;}
+.fp-select table .mdl-right {min-width: 84px;}
+.fp-select .fp-reflist .mdl-right {vertical-align: top;}
 .fp-select .fp-select-buttons {float: right;}
 .fp-select .fp-info {display: block;clear: both;padding: 1px 20px 0;}
 .fp-select .fp-thumbnail {float:left;min-width:110px;min-height:110px;line-height: 110px;text-align: center;margin: 10px 20px 0 0;background: #FFFFFF;border: 1px solid #DDDDDD;-webkit-box-shadow: inset 0 0 10px 0 #CCCCCC;-moz-box-shadow: inset 0 0 10px 0 #CCCCCC;box-shadow: inset 0 0 10px 0 #CCCCCC;}
@@ -253,6 +255,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .file-picker.fp-select .fp-select-loading {display:none;}
 .file-picker.fp-select.loading .fp-select-loading {display:block;}
 .file-picker.fp-select.loading form {display:none;}
+.fp-select .fp-dimensions.fp-unknown {display: none;}
 
  /*
  * File Manager
@@ -269,7 +272,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager .fm-empty-container {display:none;}
 .filemanager.fm-noitems .filemanager-container .fp-content {display:none;}
 .filemanager .filemanager-updating {display:none;text-align:center;}
-.filemanager.fm-updating .filemanager-updating {display:block;}
+.filemanager.fm-updating .filemanager-updating {display:block;margin-top: 37px;}
 .filemanager.fm-updating .fm-content-wrapper {display:none;}
 .filemanager.fm-nomkdir .fp-btn-mkdir {display:none;}
 
@@ -368,7 +371,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager.fp-select .fp-reflist .fp-reflistloading {display:none;}
 .filemanager.fp-select .fp-refcount {max-width: 265px;}
 .filemanager.fp-select .fp-reflist.fp-loading .fp-reflistloading {display:inline;}
-.filemanager.fp-select .fp-reflist .fp-value {background: #FFFFFF;border: 1px solid #BBBBBB;padding: 8px 7px;margin: 0px;max-width: 265px;max-height: 75px;overflow:auto;}
+.filemanager.fp-select .fp-reflist .fp-value {background: #F9F9F9;border: 1px solid #BBBBBB;padding: 8px 7px;margin: 0px;max-width: 265px;max-height: 75px;overflow:auto;}
 .filemanager.fp-select .fp-reflist .fp-value li {padding-bottom: 7px;}
 
 /*
-- 
1.7.9.5


From b86a48c5b96cd2d41931585c65cb16dfbe99390f Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 26 Jun 2012 18:15:44 +0100
Subject: [PATCH 103/903] MDL-34035 help links: allow other types of URL for
 plugins.

For third-parth plugins, in can be helpful if the 'More help' links in
help pop-ups (the ones that come from $string['..._link'] string in the
language file) can go to other places.

This change support two other sorts of URL in addition to the standard
'course/editing' type of link that goes to MoodelDocs.

You can use absolute URLs, starting http:// or https:///

You can use a link starting %%WWWROOT%%, and that token is replaced by
$CFG->wwwroot to make the link.
---
 lib/setuplib.php            |   45 +++++++++++++++++++++-----
 lib/tests/setuplib_test.php |   74 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 8 deletions(-)
 create mode 100644 lib/tests/setuplib_test.php

diff --git a/lib/setuplib.php b/lib/setuplib.php
index 4fec92d..d19b13a 100644
--- a/lib/setuplib.php
+++ b/lib/setuplib.php
@@ -565,20 +565,49 @@ function get_exception_info($ex) {
 }
 
 /**
- * Returns the Moodle Docs URL in the users language
+ * Returns the Moodle Docs URL in the users language for a given 'More help' link.
  *
- * @global object
- * @param string $path the end of the URL.
- * @return string The MoodleDocs URL in the user's language. for example {@link http://docs.moodle.org/en/ http://docs.moodle.org/en/$path}
+ * There are three cases:
+ *
+ * 1. In the normal case, $path will be a short relative path 'component/thing',
+ * like 'mod/folder/view' 'group/import'. This gets turned into an link to
+ * MoodleDocs in the user's language, and for the appropriate Moodle version.
+ * E.g. 'group/import' may become 'http://docs.moodle.org/2x/en/group/import'.
+ * The 'http://docs.moodle.org' bit comes from $CFG->docroot.
+ *
+ * This is the only option that should be used in standard Moodle code. The other
+ * two options have been implemented because they are useful for third-party plugins.
+ *
+ * 2. $path may be an absolute URL, starting http:// or http://. In this case,
+ * the link is used as is.
+ *
+ * 3. $path may start %%WWWROOT%%, in which case that is replaced by
+ * $CFG->wwwroot to make the link.
+ *
+ * @param string $path the place to link to. See above for details.
+ * @return string The MoodleDocs URL in the user's language. for example @link http://docs.moodle.org/2x/en/$path}
  */
-function get_docs_url($path=null) {
+function get_docs_url($path = null) {
     global $CFG;
+
+    // Absolute URLs are used unmodified.
+    if (substr($path, 0, 7) === 'http://' || substr($path, 0, 8) === 'https://') {
+        return $path;
+    }
+
+    // Paths starting %%WWWROOT%% have that replaced by $CFG->wwwroot.
+    if (substr($path, 0, 11) === '%%WWWROOT%%') {
+        return $CFG->wwwroot . substr($path, 11);
+    }
+
+    // Otherwise we do the normal case, and construct a MoodleDocs URL relative to $CFG->docroot.
+
     // Check that $CFG->branch has been set up, during installation it won't be.
     if (empty($CFG->branch)) {
-        // It's not there yet so look at version.php
+        // It's not there yet so look at version.php.
         include($CFG->dirroot.'/version.php');
     } else {
-        // We can use $CFG->branch and avoid having to include version.php
+        // We can use $CFG->branch and avoid having to include version.php.
         $branch = $CFG->branch;
     }
     // ensure branch is valid.
@@ -592,7 +621,7 @@ function get_docs_url($path=null) {
     if (!empty($CFG->docroot)) {
         return $CFG->docroot . '/' . $branch . '/' . current_language() . '/' . $path;
     } else {
-        return 'http://docs.moodle.org/'. $branch . '/en/' . $path;
+        return 'http://docs.moodle.org/'. $branch . '/' . current_language() . '/' . $path;
     }
 }
 
diff --git a/lib/tests/setuplib_test.php b/lib/tests/setuplib_test.php
new file mode 100644
index 0000000..7008e58
--- /dev/null
+++ b/lib/tests/setuplib_test.php
@@ -0,0 +1,74 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for setuplib.php
+ *
+ * @package   core_phpunit
+ * @copyright 2012 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Unit tests for setuplib.php
+ *
+ * @copyright 2012 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_setuplib_testcase extends basic_testcase {
+
+    /**
+     * Test get_docs_url_standard in the normal case when we should link to Moodle docs.
+     */
+    public function test_get_docs_url_standard() {
+        global $CFG;
+        if (empty($CFG->docroot)) {
+            $docroot = 'http://docs.moodle.org/';
+        } else {
+            $docroot = $CFG->docroot;
+        }
+        $this->assertRegExp('~^' . preg_quote($docroot, '') . '/2\d/' . current_language() . '/course/editing$~',
+                get_docs_url('course/editing'));
+    }
+
+    /**
+     * Test get_docs_url_standard in the special case of an absolute HTTP URL.
+     */
+    public function test_get_docs_url_http() {
+        $url = 'http://moodle.org/';
+        $this->assertEquals($url, get_docs_url($url));
+    }
+
+    /**
+     * Test get_docs_url_standard in the special case of an absolute HTTPS URL.
+     */
+    public function test_get_docs_url_https() {
+        $url = 'https://moodle.org/';
+        $this->assertEquals($url, get_docs_url($url));
+    }
+
+    /**
+     * Test get_docs_url_standard in the special case of a link relative to wwwroot.
+     */
+    public function test_get_docs_url_wwwroot() {
+        global $CFG;
+        $this->assertEquals($CFG->wwwroot . '/lib/tests/setuplib_test.php',
+                get_docs_url('%%WWWROOT%%/lib/tests/setuplib_test.php'));
+    }
+}
-- 
1.7.9.5


From 617d260dd73f66a96bf6e021044bea1848e59ac5 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 4 Jul 2012 10:37:47 +0800
Subject: [PATCH 104/903] MDL-34035 - fix typo in comment

Thanks Sam!
---
 lib/setuplib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/setuplib.php b/lib/setuplib.php
index d19b13a..51f8d82 100644
--- a/lib/setuplib.php
+++ b/lib/setuplib.php
@@ -578,7 +578,7 @@ function get_exception_info($ex) {
  * This is the only option that should be used in standard Moodle code. The other
  * two options have been implemented because they are useful for third-party plugins.
  *
- * 2. $path may be an absolute URL, starting http:// or http://. In this case,
+ * 2. $path may be an absolute URL, starting http:// or https://. In this case,
  * the link is used as is.
  *
  * 3. $path may start %%WWWROOT%%, in which case that is replaced by
-- 
1.7.9.5


From c57fa60f3dae0ccdc5fffe49115229efe52d6043 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 4 Jul 2012 10:47:03 +0100
Subject: [PATCH 105/903] MDL-32062 question engine: fixup tests that this
 change broke.

The test data was wrong, and was triggering the work-around code that
MDL-32062 introduced. I fixed the test data.

Also, I fixed one of the tests, that had been broken.
---
 question/engine/tests/unitofwork_test.php |   12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/question/engine/tests/unitofwork_test.php b/question/engine/tests/unitofwork_test.php
index d44e9b9..aa68a57 100644
--- a/question/engine/tests/unitofwork_test.php
+++ b/question/engine/tests/unitofwork_test.php
@@ -126,7 +126,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233720, 1, '-_triesleft', 1),
         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 3, 2, 'todo',             null, 1256233740, 1, '-tryagain',   1),
         array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 3, 'gradedright',      null, 1256233790, 1, 'answer',     'frog'),
-        array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 3, 'gradedright', 1.0000000, 1256233790, 1, '-finish',     1),
+        array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 1.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 3, 'gradedright', 1.0000000, 1256233790, 1, '-submit',     1),
         );
     }
 
@@ -196,13 +196,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
     public function test_regrade_same_steps() {
 
         // Change the question in a minor way and regrade.
-        if (!isset($this->quba->get_question($this->slot)->answer)) {
-            $this->quba->get_question($this->slot)->answer = array();
-        }
-        if (!isset($this->quba->get_question($this->slot)->answer[14])) {
-            $this->quba->get_question($this->slot)->answer[14] = new stdClass();
-        }
-        $this->quba->get_question($this->slot)->answer[14]->fraction = 0.5;
+        $this->quba->get_question($this->slot)->answers[14]->fraction = 0.5;
         $this->quba->regrade_all_questions();
 
         // Here, the qa, and all the steps, should be marked as updated.
@@ -258,7 +252,7 @@ class question_engine_unit_of_work_test extends data_loading_method_test_base {
         $this->assertEquals(array('-tryagain' => 1), $firstdeletedstep->get_all_data());
 
         $seconddeletedstep = end($deletedsteps);
-        $this->assertEquals(array('answer' => 'frog', '-finish' => 1),
+        $this->assertEquals(array('answer' => 'frog', '-submit' => 1),
                 $seconddeletedstep->get_all_data());
     }
 
-- 
1.7.9.5


From 1e9130ae6ed9d37513541ad2f7757c47e4582a00 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 5 Jul 2012 09:22:12 +1200
Subject: [PATCH 106/903] MDL-33770 webservices: Fixed error with
 core_group_create_groups when no enrolment key
 provided

---
 group/externallib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/group/externallib.php b/group/externallib.php
index 79d1a27..39db087 100644
--- a/group/externallib.php
+++ b/group/externallib.php
@@ -105,6 +105,9 @@ class core_group_external extends external_api {
 
             // finally create the group
             $group->id = groups_create_group($group, false);
+            if (!isset($group->enrolmentkey)) {
+                $group->enrolmentkey = '';
+            }
             $groups[] = (array)$group;
         }
 
-- 
1.7.9.5


From 684806305e4fe794c1a0fb3afe596102ba02840a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 28 Jun 2012 09:32:47 +0800
Subject: [PATCH 107/903] MDL-29470 Backup: unit tests for next automated
 backup date

---
 lib/tests/backup_test.php |  184 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 184 insertions(+)
 create mode 100644 lib/tests/backup_test.php

diff --git a/lib/tests/backup_test.php b/lib/tests/backup_test.php
new file mode 100644
index 0000000..1830f56
--- /dev/null
+++ b/lib/tests/backup_test.php
@@ -0,0 +1,184 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for backups.
+ *
+ * @package   core
+ * @category  phpunit
+ * @copyright 2012 Frédéric Massart <fred@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
+
+/**
+ * Unit tests for backup system
+ */
+class backup_testcase extends advanced_testcase {
+
+    public function test_next_automated_backup() {
+
+        $this->resetAfterTest();
+        $admin = get_admin();
+        $timezone = $admin->timezone;
+
+        // Notes
+        // - The next automated backup will never be on the same date than $now
+        // - backup_auto_weekdays starts on Sunday
+        // - Tests cannot be done in the past.
+
+        // Every Wed and Sat at 11pm.
+        set_config('backup_auto_active', '1', 'backup');
+        set_config('backup_auto_weekdays', '0010010', 'backup');
+        set_config('backup_auto_hour', '23', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+
+        $now = strtotime('next Monday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        // Every Sun and Sat at 12pm.
+        set_config('backup_auto_active', '1', 'backup');
+        set_config('backup_auto_weekdays', '1000001', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+
+        $now = strtotime('next Monday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        // Every Sun at 4am.
+        set_config('backup_auto_active', '1', 'backup');
+        set_config('backup_auto_weekdays', '1000000', 'backup');
+        set_config('backup_auto_hour', '4', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+
+        $now = strtotime('next Monday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        // Every day but Wed at 8:30pm.
+        set_config('backup_auto_active', '1', 'backup');
+        set_config('backup_auto_weekdays', '1110111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+
+        $now = strtotime('next Monday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Friday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
+
+    }
+}
-- 
1.7.9.5


From b20b1c32bf50ca58bccde841b093025337111a5b Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 2 Jul 2012 16:14:28 +0100
Subject: [PATCH 108/903] MDL-34145 postgres driver: fix get_tables perf on <=
 9.0

The query of the information_schema view seems to be painfully slow on
older versions of postgres (2000ms instead of 20ms). Therefore, it is
worth detecting that case, and using a more postgres specific feedback.
This is particularly important for 2.3+ unit tests.

Thanks to Petr Skoda for his help with this.
---
 lib/dml/pgsql_native_moodle_database.php |   21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/dml/pgsql_native_moodle_database.php b/lib/dml/pgsql_native_moodle_database.php
index c883aed..0c9b18e 100644
--- a/lib/dml/pgsql_native_moodle_database.php
+++ b/lib/dml/pgsql_native_moodle_database.php
@@ -292,12 +292,21 @@ class pgsql_native_moodle_database extends moodle_database {
         }
         $this->tables = array();
         $prefix = str_replace('_', '|_', $this->prefix);
-        // Get them from information_schema instead of catalog as far as
-        // we want to get only own session temp objects (catalog returns all)
-        $sql = "SELECT table_name
-                  FROM information_schema.tables
-                 WHERE table_name LIKE '$prefix%' ESCAPE '|'
-                   AND table_type IN ('BASE TABLE', 'LOCAL TEMPORARY')";
+        if ($this->is_min_version('9.1')) {
+            // Use ANSI standard information_schema in recent versions where it is fast enough.
+            $sql = "SELECT table_name
+                      FROM information_schema.tables
+                     WHERE table_name LIKE '$prefix%' ESCAPE '|'
+                       AND table_type IN ('BASE TABLE', 'LOCAL TEMPORARY')";
+        } else {
+            // information_schema is horribly slow in <= 9.0, so use pg internals.
+            // Note the pg_is_other_temp_schema. We only want temp objects from our own session.
+            $sql = "SELECT c.relname
+                      FROM pg_class c
+                     WHERE c.relname LIKE '$prefix%' ESCAPE '|'
+                       AND c.relkind = 'r'
+                       AND NOT pg_is_other_temp_schema(c.relnamespace)";
+        }
         $this->query_start($sql, null, SQL_QUERY_AUX);
         $result = pg_query($this->pgsql, $sql);
         $this->query_end($result);
-- 
1.7.9.5


From 8fb4b73f55a6bc4fdff143dbcdaaaae7af8da9dc Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 28 Jun 2012 09:32:13 +0800
Subject: [PATCH 109/903] MDL-29470 Backup: fixed unexpected next automated
 backup date

---
 backup/util/helper/backup_cron_helper.class.php |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 65e56ee..00db13d 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -281,23 +281,25 @@ abstract class backup_cron_automated_helper {
         $midnight = usergetmidnight($now, $timezone);
         $date = usergetdate($now, $timezone);
 
-        //Get number of days (from today) to execute backups
-        $automateddays = substr($config->backup_auto_weekdays,$date['wday']) . $config->backup_auto_weekdays;
-        $daysfromtoday = strpos($automateddays, "1");
+        // Get number of days (from today) to execute backups
+        $automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
+        $daysfromtoday = strpos($automateddays, "1", 1);
+
+        // If we can't find the next day, we set it to tomorrow
         if (empty($daysfromtoday)) {
             $daysfromtoday = 1;
         }
 
-        //If some day has been found
+        // If some day has been found
         if ($daysfromtoday !== false) {
-            //Calculate distance
-            $dist = ($daysfromtoday * 86400) +                //Days distance
-                    ($config->backup_auto_hour * 3600) +      //Hours distance
-                    ($config->backup_auto_minute * 60);       //Minutes distance
+            // Calculate distance
+            $dist = ($daysfromtoday * 86400) +                // Days distance
+                    ($config->backup_auto_hour * 3600) +      // Hours distance
+                    ($config->backup_auto_minute * 60);       // Minutes distance
             $result = $midnight + $dist;
         }
 
-        //If that time is past, call the function recursively to obtain the next valid day
+        // If that time is past, call the function recursively to obtain the next valid day
         if ($result > 0 && $result < time()) {
             $result = self::calculate_next_automated_backup($timezone, $result);
         }
-- 
1.7.9.5


From 34e0b4a71e7b27a3786d23248cb1a3010fc6aeed Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 26 Jun 2012 17:35:07 +0800
Subject: [PATCH 110/903] MDL-30816 choice module: fixed accessibility for
 responses table and make it easier for screenreader
 to read it

---
 mod/choice/lang/en/choice.php |    7 +-
 mod/choice/renderer.php       |  237 +++++++++++++++++++++++++++--------------
 mod/choice/styles.css         |    2 +
 3 files changed, 162 insertions(+), 84 deletions(-)

diff --git a/mod/choice/lang/en/choice.php b/mod/choice/lang/en/choice.php
index d1c89c7..42f4c1b 100644
--- a/mod/choice/lang/en/choice.php
+++ b/mod/choice/lang/en/choice.php
@@ -68,12 +68,15 @@ A choice activity may be used
 * To facilitate student decision-making, for example allowing students to vote on a direction for the course';
 $string['modulename_link'] = 'mod/choice/view';
 $string['modulenameplural'] = 'Choices';
+$string['moveselectedusersto'] = 'Move selected users to...';
 $string['mustchooseone'] = 'You must choose an answer before saving.  Nothing was saved.';
 $string['noguestchoose'] = 'Sorry, guests are not allowed to make choices.';
 $string['noresultsviewable'] = 'The results are not currently viewable.';
 $string['notanswered'] = 'Not answered yet';
 $string['notenrolledchoose'] = 'Sorry, only enrolled users are allowed to make choices.';
 $string['notopenyet'] = 'Sorry, this activity is not available until {$a}';
+$string['numberofuser'] = 'The number of user';
+$string['numberofuserinpercentage'] = 'The number of user in percentage';
 $string['option'] = 'Option';
 $string['page-mod-choice-x'] = 'Any choice module page';
 $string['pluginadministration'] = 'Choice administration';
@@ -89,6 +92,7 @@ $string['publishnot'] = 'Do not publish results to students';
 $string['removemychoice'] = 'Remove my choice';
 $string['removeresponses'] = 'Remove all responses';
 $string['responses'] = 'Responses';
+$string['responsesresultgraphheader'] = 'Graph display';
 $string['responsesto'] = 'Responses to {$a}';
 $string['savemychoice'] = 'Save my choice';
 $string['showunanswered'] = 'Show column for unanswered';
@@ -98,7 +102,6 @@ $string['taken'] = 'Taken';
 $string['timerestrict'] = 'Restrict answering to this time period';
 $string['viewallresponses'] = 'View {$a} responses';
 $string['withselected'] = 'With selected';
+$string['userchoosethisoption'] = 'User choose this option';
 $string['yourselection'] = 'Your selection';
 $string['skipresultgraph'] = 'Skip result graph';
-$string['moveselectedusersto'] = 'Move selected users to...';
-$string['numberofuser'] = 'The number of user';
diff --git a/mod/choice/renderer.php b/mod/choice/renderer.php
index 1c4da2b..08ddb02 100644
--- a/mod/choice/renderer.php
+++ b/mod/choice/renderer.php
@@ -141,34 +141,69 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results names ';
         $table->tablealign = 'center';
+        $table->summary = get_string('responsesto', 'choice', $choices->name);
         $table->data = array();
 
         $count = 0;
         ksort($choices->options);
 
         $columns = array();
+        $celldefault = new html_table_cell();
+        $celldefault->attributes['class'] = 'data';
+
+        // This extra cell is needed in order to support accessibility for screenreader. MDL-30816
+        $accessiblecell = new html_table_cell();
+        $accessiblecell->scope = 'row';
+        $accessiblecell->text = get_string('choiceoptions', 'choice');
+        $columns['options'][] = $accessiblecell;
+
+        $usernumberheader = clone($celldefault);
+        $usernumberheader->header = true;
+        $usernumberheader->attributes['class'] = 'header data';
+        $usernumberheader->text = get_string('numberofuser', 'choice');
+        $columns['usernumber'][] = $usernumberheader;
+
+
         foreach ($choices->options as $optionid => $options) {
-            $coldata = '';
+            $celloption = clone($celldefault);
+            $cellusernumber = clone($celldefault);
+            $cellusernumber->style = 'text-align: center;';
+
+            $celltext = '';
             if ($choices->showunanswered && $optionid == 0) {
-                $coldata .= html_writer::tag('div', format_string(get_string('notanswered', 'choice')), array('class'=>'option'));
+                $celltext = format_string(get_string('notanswered', 'choice'));
             } else if ($optionid > 0) {
-                $coldata .= html_writer::tag('div', format_string($choices->options[$optionid]->text), array('class'=>'option'));
+                $celltext = format_string($choices->options[$optionid]->text);
             }
             $numberofuser = 0;
             if (!empty($options->user) && count($options->user) > 0) {
                 $numberofuser = count($options->user);
             }
 
-            $coldata .= html_writer::tag('div', ' ('.$numberofuser. ')', array('class'=>'numberofuser', 'title' => get_string('numberofuser', 'choice')));
-            $columns[] = $coldata;
+            $celloption->text = $celltext;
+            $cellusernumber->text = $numberofuser;
+
+            $columns['options'][] = $celloption;
+            $columns['usernumber'][] = $cellusernumber;
         }
 
-        $table->head = $columns;
+        $table->head = $columns['options'];
+        $table->data[] = new html_table_row($columns['usernumber']);
 
-        $coldata = '';
         $columns = array();
+
+        // This extra cell is needed in order to support accessibility for screenreader. MDL-30816
+        $accessiblecell = new html_table_cell();
+        $accessiblecell->text = get_string('userchoosethisoption', 'choice');
+        $accessiblecell->header = true;
+        $accessiblecell->scope = 'row';
+        $accessiblecell->attributes['class'] = 'header data';
+        $columns[] = $accessiblecell;
+
         foreach ($choices->options as $optionid => $options) {
-            $coldata = '';
+            $cell = new html_table_cell();
+            $cell->attributes['class'] = 'data';
+
             if ($choices->showunanswered || $optionid > 0) {
                 if (!empty($options->user)) {
                     foreach ($options->user as $user) {
@@ -188,19 +223,16 @@ class mod_choice_renderer extends plugin_renderer_base {
                         $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
-                        $coldata .= html_writer::tag('div', $data, array('class'=>'user'));
+                        $cell->text = html_writer::tag('div', $data, array('class'=>'user'));
                     }
                 }
             }
-
-            $columns[] = $coldata;
+            $columns[] = $cell;
             $count++;
         }
+        $row = new html_table_row($columns);
+        $table->data[] = $row;
 
-        $table->data[] = $columns;
-        foreach ($columns as $d) {
-            $table->colclasses[] = 'data';
-        }
         $html .= html_writer::tag('div', html_writer::table($table), array('class'=>'response'));
 
         $actiondata = '';
@@ -245,71 +277,88 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellpadding = 5;
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results anonymous ';
+        $table->summary = get_string('responsesto', 'choice', $choices->name);
         $table->data = array();
+
         $count = 0;
         ksort($choices->options);
         $columns = array();
         $rows = array();
 
-        foreach ($choices->options as $optionid => $options) {
-            $numberofuser = 0;
-            if (!empty($options->user)) {
-               $numberofuser = count($options->user);
+        $headercelldefault = new html_table_cell();
+        $headercelldefault->scope = 'row';
+        $headercelldefault->header = true;
+        $headercelldefault->attributes = array('class'=>'header data');
+
+        // column header
+        $tableheader = clone($headercelldefault);
+        $tableheader->text = html_writer::tag('div', get_string('choiceoptions', 'choice'), array('class' => 'accesshide'));
+        $rows['header'][] = $tableheader;
+
+        // graph row header
+        $graphheader = clone($headercelldefault);
+        $graphheader->text = html_writer::tag('div', get_string('responsesresultgraphheader', 'choice'), array('class' => 'accesshide'));
+        $rows['graph'][] = $graphheader;
+
+        // user number row header
+        $usernumberheader = clone($headercelldefault);
+        $usernumberheader->text = get_string('numberofuser', 'choice');
+        $rows['usernumber'][] = $usernumberheader;
+
+        // user percentage row header
+        $userpercentageheader = clone($headercelldefault);
+        $userpercentageheader->text = get_string('numberofuserinpercentage', 'choice');
+        $rows['userpercentage'][] = $userpercentageheader;
+
+        $contentcelldefault = new html_table_cell();
+        $contentcelldefault->attributes = array('class'=>'data');
+
+        foreach ($choices->options as $optionid => $option) {
+            // calculate display length
+            $height = $percentageamount = $numberofuser = 0;
+            $usernumber = $userpercentage = '';
+
+            if (!empty($option->user)) {
+               $numberofuser = count($option->user);
             }
-            $height = 0;
-            $percentageamount = 0;
+
             if($choices->numberofuser > 0) {
                $height = ($CHOICE_COLUMN_HEIGHT * ((float)$numberofuser / (float)$choices->numberofuser));
                $percentageamount = ((float)$numberofuser/(float)$choices->numberofuser)*100.0;
             }
 
-            $displaydiagram = html_writer::tag('img','', array('style'=>'height:'.$height.'px;width:49px;', 'alt'=>'', 'src'=>$this->output->pix_url('column', 'choice')));
-
-            $cell = new html_table_cell();
-            $cell->text = $displaydiagram;
-            $cell->attributes = array('class'=>'graph vertical data');
-            $columns[] = $cell;
-        }
-        $rowgraph = new html_table_row();
-        $rowgraph->cells = $columns;
-        $rows[] = $rowgraph;
+            $displaygraph = html_writer::tag('img','', array('style'=>'height:'.$height.'px;width:49px;', 'alt'=>'', 'src'=>$this->output->pix_url('column', 'choice')));
 
-        $columns = array();
-        $printskiplink = true;
-        foreach ($choices->options as $optionid => $options) {
-            $columndata = '';
-            $numberofuser = 0;
-            if (!empty($options->user)) {
-               $numberofuser = count($options->user);
-            }
+            // header
+            $headercell = clone($contentcelldefault);
+            $headercell->text = $option->text;
+            $rows['header'][] = $headercell;
 
-            if ($printskiplink) {
-                $columndata .= html_writer::tag('div', '', array('class'=>'skip-block-to', 'id'=>'skipresultgraph'));
-                $printskiplink = false;
-            }
+            // Graph
+            $graphcell = clone($contentcelldefault);
+            $graphcell->attributes = array('class'=>'graph vertical data');
+            $graphcell->text = $displaygraph;
+            $rows['graph'][] = $graphcell;
 
-            if ($choices->showunanswered && $optionid == 0) {
-                $columndata .= html_writer::tag('div', format_string(get_string('notanswered', 'choice')), array('class'=>'option'));
-            } else if ($optionid > 0) {
-                $columndata .= html_writer::tag('div', format_string($choices->options[$optionid]->text), array('class'=>'option'));
-            }
-            $columndata .= html_writer::tag('div', ' ('.$numberofuser.')', array('class'=>'numberofuser', 'title'=> get_string('numberofuser', 'choice')));
+            $usernumber .= html_writer::tag('div', ' '.$numberofuser.'', array('class'=>'numberofuser', 'title'=> get_string('numberofuser', 'choice')));
+            $userpercentage .= html_writer::tag('div', format_float($percentageamount,1). '%', array('class'=>'percentage'));
 
-            if($choices->numberofuser > 0) {
-               $percentageamount = ((float)$numberofuser/(float)$choices->numberofuser)*100.0;
-            }
-            $columndata .= html_writer::tag('div', format_float($percentageamount,1). '%', array('class'=>'percentage'));
+            // number of user
+            $usernumbercell = clone($contentcelldefault);
+            $usernumbercell->text = $usernumber;
+            $rows['usernumber'][] = $usernumbercell;
 
-            $cell = new html_table_cell();
-            $cell->text = $columndata;
-            $cell->attributes = array('class'=>'data header');
-            $columns[] = $cell;
+            // percentage of user
+            $numbercell = clone($contentcelldefault);
+            $numbercell->text = $userpercentage;
+            $rows['userpercentage'][] = $numbercell;
         }
-        $rowdata = new html_table_row();
-        $rowdata->cells = $columns;
-        $rows[] = $rowdata;
 
-        $table->data = $rows;
+        $table->head = $rows['header'];
+        $trgraph = new html_table_row($rows['graph']);
+        $trusernumber = new html_table_row($rows['usernumber']);
+        $truserpercentage = new html_table_row($rows['userpercentage']);
+        $table->data = array($trgraph, $trusernumber, $truserpercentage);
 
         $header = html_writer::tag('h2',format_string(get_string("responses", "choice")));
         $html .= html_writer::tag('div', $header, array('class'=>'responseheader'));
@@ -331,52 +380,76 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellpadding = 5;
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results anonymous ';
+        $table->summary = get_string('responsesto', 'choice', $choices->name);
         $table->data = array();
 
+        $columnheaderdefault = new html_table_cell();
+        $columnheaderdefault->scope = 'col';
+
+        $tableheadertext = clone($columnheaderdefault);
+        $tableheadertext->text = get_string('choiceoptions', 'choice');
+
+        $tableheadernumber = clone($columnheaderdefault);
+        $tableheadernumber->text = get_string('numberofuser', 'choice');
+
+        $tableheaderpercentage = clone($columnheaderdefault);
+        $tableheaderpercentage->text = get_string('numberofuserinpercentage', 'choice');
+
+        $tableheadergraph = clone($columnheaderdefault);
+        $tableheadergraph->text = get_string('responsesresultgraphheader', 'choice');
+
+        $table->head = array($tableheadertext, $tableheadernumber, $tableheaderpercentage, $tableheadergraph);
+
         $count = 0;
         ksort($choices->options);
 
+        $columndefault = new html_table_cell();
+        $columndefault->attributes['class'] = 'data';
+
+        $colheaderdefault = new html_table_cell();
+        $colheaderdefault->scope = 'row';
+        $colheaderdefault->header = true;
+        $colheaderdefault->attributes['class'] = 'header data';
+
         $rows = array();
         foreach ($choices->options as $optionid => $options) {
-            $numberofuser = 0;
-            $graphcell = new html_table_cell();
+            $colheader = clone($colheaderdefault);
+            $colheader->text = $options->text;
+
+            $graphcell = clone($columndefault);
+            $datacellnumber = clone($columndefault);
+            $datacellpercentage = clone($columndefault);
+
+            $numberofuser = $width = $percentageamount = 0;
+
             if (!empty($options->user)) {
                $numberofuser = count($options->user);
             }
 
-            $width = 0;
-            $percentageamount = 0;
-            $columndata = '';
             if($choices->numberofuser > 0) {
                $width = ($CHOICE_COLUMN_WIDTH * ((float)$numberofuser / (float)$choices->numberofuser));
                $percentageamount = ((float)$numberofuser/(float)$choices->numberofuser)*100.0;
             }
-            $displaydiagram = html_writer::tag('img','', array('style'=>'height:50px; width:'.$width.'px', 'alt'=>'', 'src'=>$this->output->pix_url('row', 'choice')));
 
-            $skiplink = html_writer::tag('a', get_string('skipresultgraph', 'choice'), array('href'=>'#skipresultgraph'. $optionid, 'class'=>'skip-block'));
-            $skiphandler = html_writer::tag('span', '', array('class'=>'skip-block-to', 'id'=>'skipresultgraph'.$optionid));
+            $attributes = array();
+            $attributes['style'] = 'height:50px; width:'.$width.'px';
+            $attributes['alt'] = '';
+            $attributes['src'] = $this->output->pix_url('row', 'choice');
+            $displaydiagram = html_writer::tag('img','', $attributes);
 
-            $graphcell->text = $skiplink . $displaydiagram . $skiphandler;
+            $graphcell->text = $displaydiagram;
             $graphcell->attributes = array('class'=>'graph horizontal');
 
-            $datacell = new html_table_cell();
-            if ($choices->showunanswered && $optionid == 0) {
-                $columndata .= html_writer::tag('div', format_string(get_string('notanswered', 'choice')), array('class'=>'option'));
-            } else if ($optionid > 0) {
-                $columndata .= html_writer::tag('div', format_string($choices->options[$optionid]->text), array('class'=>'option'));
-            }
-            $columndata .= html_writer::tag('div', ' ('.$numberofuser.')', array('title'=> get_string('numberofuser', 'choice'), 'class'=>'numberofuser'));
-
             if($choices->numberofuser > 0) {
                $percentageamount = ((float)$numberofuser/(float)$choices->numberofuser)*100.0;
             }
-            $columndata .= html_writer::tag('div', format_float($percentageamount,1). '%', array('class'=>'percentage'));
 
-            $datacell->text = $columndata;
-            $datacell->attributes = array('class'=>'header');
+            $datacellnumber->text = $numberofuser;
+            $datacellpercentage->text = format_float($percentageamount,1). '%';
+
 
             $row = new html_table_row();
-            $row->cells = array($datacell, $graphcell);
+            $row->cells = array($colheader, $datacellnumber, $datacellpercentage, $graphcell);
             $rows[] = $row;
         }
 
diff --git a/mod/choice/styles.css b/mod/choice/styles.css
index ed2c5aa..bdca951 100644
--- a/mod/choice/styles.css
+++ b/mod/choice/styles.css
@@ -23,6 +23,8 @@
 
 .path-mod-choice .results.anonymous .graph.vertical,
 .path-mod-choice .cell {vertical-align: bottom; text-align: center; }
+.path-mod-choice .results.anonymous th.header {border: 1px solid inherit;}
+
 .path-mod-choice .results.names .header{width:10%; white-space: normal;}
 .path-mod-choice .results.names .cell{vertical-align: top; text-align: left;}
 .path-mod-choice .results.names .user,
-- 
1.7.9.5


From a2af7fd407b91b2c57607ff8ee4125f0e96d46a4 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 5 Jul 2012 12:20:20 +0800
Subject: [PATCH 111/903] MDL-30816 Choice module: add format_string() for
 choice name.

---
 mod/choice/renderer.php |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/mod/choice/renderer.php b/mod/choice/renderer.php
index 08ddb02..07bbd19 100644
--- a/mod/choice/renderer.php
+++ b/mod/choice/renderer.php
@@ -141,7 +141,7 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results names ';
         $table->tablealign = 'center';
-        $table->summary = get_string('responsesto', 'choice', $choices->name);
+        $table->summary = get_string('responsesto', 'choice', format_string($choices->name));
         $table->data = array();
 
         $count = 0;
@@ -206,6 +206,7 @@ class mod_choice_renderer extends plugin_renderer_base {
 
             if ($choices->showunanswered || $optionid > 0) {
                 if (!empty($options->user)) {
+                    $optionusers = '';
                     foreach ($options->user as $user) {
                         $data = '';
                         if (empty($user->imagealt)){
@@ -223,8 +224,9 @@ class mod_choice_renderer extends plugin_renderer_base {
                         $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
-                        $cell->text = html_writer::tag('div', $data, array('class'=>'user'));
+                        $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
                     }
+                    $cell->text = $optionusers;
                 }
             }
             $columns[] = $cell;
@@ -277,7 +279,7 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellpadding = 5;
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results anonymous ';
-        $table->summary = get_string('responsesto', 'choice', $choices->name);
+        $table->summary = get_string('responsesto', 'choice', format_string($choices->name));
         $table->data = array();
 
         $count = 0;
@@ -380,7 +382,7 @@ class mod_choice_renderer extends plugin_renderer_base {
         $table->cellpadding = 5;
         $table->cellspacing = 0;
         $table->attributes['class'] = 'results anonymous ';
-        $table->summary = get_string('responsesto', 'choice', $choices->name);
+        $table->summary = get_string('responsesto', 'choice', format_string($choices->name));
         $table->data = array();
 
         $columnheaderdefault = new html_table_cell();
-- 
1.7.9.5


From e819ff4263cd5cf8493ac12b642a66271f8e2eca Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 27 Jun 2012 15:27:50 +0100
Subject: [PATCH 112/903] MDL-34065 lib: improve two debugging messages.

If the string passed to get_string is empty, say that. Don't say that it
contains illegal characters.

When relying on the __call magic in plugin_renderer_base, when the
method cannot be found, include the right class name in the error
message.
---
 lib/moodlelib.php       |    2 +-
 lib/outputrenderers.php |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 2dd1f58..16db6c8 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -7179,7 +7179,7 @@ function get_string($identifier, $component = '', $a = NULL, $lazyload = false)
 
     $identifier = clean_param($identifier, PARAM_STRINGID);
     if (empty($identifier)) {
-        throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of the string identifier. Please fix your get_string() call and string definition');
+        throw new coding_exception('Invalid string identifier. The identifier cannot be empty. Please fix your get_string() call.');
     }
 
     // There is now a forth argument again, this time it is a boolean however so
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 1d16603..ea0f784 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -228,12 +228,12 @@ class plugin_renderer_base extends renderer_base {
      */
     public function __call($method, $arguments) {
         if (method_exists('renderer_base', $method)) {
-            throw new coding_exception('Protected method called against '.__CLASS__.' :: '.$method);
+            throw new coding_exception('Protected method called against '.get_class($this).' :: '.$method);
         }
         if (method_exists($this->output, $method)) {
             return call_user_func_array(array($this->output, $method), $arguments);
         } else {
-            throw new coding_exception('Unknown method called against '.__CLASS__.' :: '.$method);
+            throw new coding_exception('Unknown method called against '.get_class($this).' :: '.$method);
         }
     }
 }
-- 
1.7.9.5


From b9c20952a3507542e86bfc5627e99a4fa97061ad Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 27 Jun 2012 17:59:29 +0100
Subject: [PATCH 113/903] MDL-34065 questions: also fix two typos in comments.

Amended to change 2 accordin => according
---
 question/engine/states.php     |    2 +-
 question/type/rendererbase.php |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/question/engine/states.php b/question/engine/states.php
index e70d9bb..79c40b2 100644
--- a/question/engine/states.php
+++ b/question/engine/states.php
@@ -206,7 +206,7 @@ abstract class question_state {
      * Appropriate allowance is made for rounding float values.
      *
      * @param number $fraction the grade, on the fraction scale.
-     * @return int one of the state constants.
+     * @return question_state one of the state constants.
      */
     public static function graded_state_for_fraction($fraction) {
         if ($fraction < 0.000001) {
diff --git a/question/type/rendererbase.php b/question/type/rendererbase.php
index 25e470c..14fbdad 100644
--- a/question/type/rendererbase.php
+++ b/question/type/rendererbase.php
@@ -130,7 +130,7 @@ abstract class qtype_renderer extends plugin_renderer_base {
     }
 
     /**
-     * Gereate the specific feedback. This is feedback that varies accordin to
+     * Generate the specific feedback. This is feedback that varies according to
      * the reponse the student gave.
      * @param question_attempt $qa the question attempt to display.
      * @return string HTML fragment.
@@ -157,7 +157,7 @@ abstract class qtype_renderer extends plugin_renderer_base {
     }
 
     /**
-     * Gereate the specific feedback. This is feedback that varies accordin to
+     * Gereate the specific feedback. This is feedback that varies according to
      * the reponse the student gave.
      * @param question_attempt $qa the question attempt to display.
      * @return string HTML fragment.
-- 
1.7.9.5


From 9b47ec7bb3899a0fd1b4df5610e48a47b92c246e Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 5 Jul 2012 16:50:46 +0800
Subject: [PATCH 114/903] MDL-33746 make folder view look like filemanager
 tree view

---
 mod/folder/renderer.php |   25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/mod/folder/renderer.php b/mod/folder/renderer.php
index 276765f..539affe 100644
--- a/mod/folder/renderer.php
+++ b/mod/folder/renderer.php
@@ -41,8 +41,8 @@ class mod_folder_renderer extends plugin_renderer_base {
     public function render_folder_tree(folder_tree $tree) {
         global $PAGE;
 
-        echo '<div id="folder_tree">';
-        echo $this->htmllize_tree($tree, $tree->dir);
+        echo '<div id="folder_tree" class="filemanager">';
+        echo $this->htmllize_tree($tree, array('files' => array(), 'subdirs' => array($tree->dir)));
         echo '</div>';
         $this->page->requires->js_init_call('M.mod_folder.init_tree', array(true));
     }
@@ -56,14 +56,29 @@ class mod_folder_renderer extends plugin_renderer_base {
         if (empty($dir['subdirs']) and empty($dir['files'])) {
             return '';
         }
+        $browser = get_file_browser();
         $result = '<ul>';
         foreach ($dir['subdirs'] as $subdir) {
-            $result .= '<li>'.s($subdir['dirname']).' '.$this->htmllize_tree($tree, $subdir).'</li>';
+            $image = $this->output->pix_icon(file_folder_icon(24), $subdir['dirname'], 'moodle');
+            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', s($subdir['dirname']), array('class' => 'fp-filename'));
+            $filename = html_writer::tag('div', $filename, array('class' => 'fp-filename-icon'));
+            $result .= html_writer::tag('li', $filename. $this->htmllize_tree($tree, $subdir));
         }
         foreach ($dir['files'] as $file) {
-            $url = file_encode_url("$CFG->wwwroot/pluginfile.php", '/'.$tree->context->id.'/mod_folder/content/'.$tree->folder->revision.$file->get_filepath().$file->get_filename(), true);
+            $fileinfo = $browser->get_file_info($tree->context, $file->get_component(),
+                    $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
+            $url = $fileinfo->get_url(true);
             $filename = $file->get_filename();
-            $result .= '<li><span>'.html_writer::link($url, $filename).'</span></li>';
+            if ($imageinfo = $fileinfo->get_imageinfo()) {
+                $fileurl = new moodle_url($fileinfo->get_url());
+                $image = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
+                $image = html_writer::empty_tag('img', array('src' => $image));
+            } else {
+                $image = $this->output->pix_icon(file_file_icon($file, 24), $filename, 'moodle');
+            }
+            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', $filename, array('class' => 'fp-filename'));
+            $filename = html_writer::tag('span', html_writer::link($url, $filename), array('class' => 'fp-filename-icon'));
+            $result .= html_writer::tag('li', $filename);
         }
         $result .= '</ul>';
 
-- 
1.7.9.5


From 4539b33788d827e7392ed671dd989a98d71f1513 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 5 Jul 2012 16:10:37 +0200
Subject: [PATCH 115/903] Revert "MDL-30912 - lib - A tidy up of the submit
 url jump functions for greater ease with
 accessability."

This reverts commit a1a00aeee7c9291b51266d9bd3de89a7b89a636c.
---
 lib/javascript-static.js |   27 ++++++++++++---------------
 lib/outputrenderers.php  |    2 +-
 2 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index ed9aaba..6bf2e28 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -381,26 +381,26 @@ M.util.init_select_autosubmit = function(Y, formid, selectid, nothing) {
                     if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
                         //prevent event bubbling and detach handlers to prevent multiple submissions caused by double clicking
                         e.halt();
+                        paramobject.eventkeypress.detach();
+                        paramobject.eventblur.detach();
                         paramobject.eventchangeorblur.detach();
+
                         this.submit();
                     }
                 };
-
-                var changedown = function(e, paramobject) {
-                    if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
-                        if(e.keyCode == 13) {
-                            form.submit();
-                        }
-                    }
-                }
-
-                // Attach the change event to the keydown and click actions.
+                // Attach the change event to the keypress, blur, and click actions.
                 // We don't use the change event because IE fires it on every arrow up/down
                 // event.... usability
                 var paramobject = new Object();
                 paramobject.lastindex = select.get('selectedIndex');
-                paramobject.eventchangeorblur = select.on('click', processchange, form, paramobject);
-                paramobject.eventkeypress = Y.on('keydown', changedown, select, '', form, paramobject);
+                paramobject.eventkeypress = Y.on('key', processchange, select, 'press:13', form, paramobject);
+                paramobject.eventblur = select.on('blur', processchange, form, paramobject);
+                //little hack for chrome that need onChange event instead of onClick - see MDL-23224
+                if (Y.UA.webkit) {
+                    paramobject.eventchangeorblur = select.on('change', processchange, form, paramobject);
+                } else {
+                    paramobject.eventchangeorblur = select.on('click', processchange, form, paramobject);
+                }
             }
         }
     });
@@ -408,9 +408,6 @@ M.util.init_select_autosubmit = function(Y, formid, selectid, nothing) {
 
 /**
  * Attach handler to url_select
- * Deprecated from 2.3 onwards.
- * Please use @see init_select_autosubmit() for redirecting to a url (above).
- * This function has accessability issues and also does not use the formid passed through as a parameter.
  */
 M.util.init_url_select = function(Y, formid, selectid, nothing) {
     YUI(M.yui.loader).use('node', function(Y) {
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index ea0f784..9654364 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1472,7 +1472,7 @@ class core_renderer extends renderer_base {
             $go = html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('go')));
             $output .= html_writer::tag('noscript', html_writer::tag('div', $go), array('style'=>'inline'));
             $nothing = empty($select->nothing) ? false : key($select->nothing);
-            $output .= $this->page->requires->js_init_call('M.util.init_select_autosubmit', array($select->formid, $select->attributes['id'], $nothing));
+            $output .= $this->page->requires->js_init_call('M.util.init_url_select', array($select->formid, $select->attributes['id'], $nothing));
         } else {
             $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>$select->showbutton));
         }
-- 
1.7.9.5


From 2425229c886566f30e3af7bb7bcf843401e08229 Mon Sep 17 00:00:00 2001
From: David Balch <david.balch@conted.ox.ac.uk>
Date: Mon, 2 Jul 2012 14:25:56 +0800
Subject: [PATCH 116/903] MDL-34063 XHTML files should use the HTML icon, not
 the markup icon

---
 lib/filelib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index f1e44f3..fd6b23d 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -1418,7 +1418,7 @@ function &get_mimetypes_array() {
         'hqx'  => array ('type'=>'application/mac-binhex40', 'icon'=>'archive', 'groups'=>array('archive'), 'string'=>'archive'),
         'htc'  => array ('type'=>'text/x-component', 'icon'=>'markup'),
         'html' => array ('type'=>'text/html', 'icon'=>'html', 'groups'=>array('web_file')),
-        'xhtml'=> array ('type'=>'application/xhtml+xml', 'icon'=>'markup', 'groups'=>array('web_file')),
+        'xhtml'=> array ('type'=>'application/xhtml+xml', 'icon'=>'html', 'groups'=>array('web_file')),
         'htm'  => array ('type'=>'text/html', 'icon'=>'html', 'groups'=>array('web_file')),
         'ico'  => array ('type'=>'image/vnd.microsoft.icon', 'icon'=>'image', 'groups'=>array('image'), 'string'=>'image'),
         'ics'  => array ('type'=>'text/calendar', 'icon'=>'text'),
-- 
1.7.9.5


From b73a7519c4a39d13da220c131ae53f511dad2055 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 5 Jul 2012 23:22:05 +0200
Subject: [PATCH 117/903] Revert "MDL-33303 Filepicker: resized to match HTML
 editor and made resizable"

This reverts commit e5c2bbd0f7f013982ed1a38bd55dccf5b5388f20.
---
 files/renderer.php               |   17 +++----------
 lib/form/filemanager.js          |   51 ++------------------------------------
 theme/base/style/filemanager.css |    6 ++---
 3 files changed, 7 insertions(+), 67 deletions(-)

diff --git a/files/renderer.php b/files/renderer.php
index d869270..cfa14e0 100644
--- a/files/renderer.php
+++ b/files/renderer.php
@@ -107,7 +107,7 @@ class core_files_renderer extends plugin_renderer_base {
         $module = array(
             'name'=>'form_filemanager',
             'fullpath'=>'/lib/form/filemanager.js',
-            'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin', 'resize'),
+            'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
             'strings' => array(
                 array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
                 array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
@@ -123,7 +123,6 @@ class core_files_renderer extends plugin_renderer_base {
                     array($this->filemanager_js_templates()), true, $module);
         }
         $this->page->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
-        user_preference_allow_ajax_update('filemanagerresizedto', PARAM_SEQUENCE);
 
         // non javascript file manager
         $html .= '<noscript>';
@@ -193,17 +192,8 @@ class core_files_renderer extends plugin_renderer_base {
         $strdndenabledinbox = get_string('dndenabled_inbox', 'moodle');
         $loading = get_string('loading', 'repository');
 
-        $resizedto = get_user_preferences('filemanagerresizedto', null);
-        $filemanagerstyle = '';
-        $containerstyletag = '';
-        if (!is_null($resizedto) && preg_match('#^\d+,\d+$#', $resizedto)) {
-            list($width, $height) = explode(',', $resizedto, 2);
-            $filemanagerstyle = " style='width:{$width}px;'";
-            $containerstyletag = " style='height:{$height}px;'";
-        }
-
         $html = '
-<div id="filemanager-'.$client_id.'" class="filemanager fm-loading"'.$filemanagerstyle.'>
+<div id="filemanager-'.$client_id.'" class="filemanager fm-loading">
     <div class="fp-restrictions">
         '.$restrictions.'
         <span class="dndupload-message"> - '.$strdndenabled.' </span>
@@ -226,7 +216,7 @@ class core_files_renderer extends plugin_renderer_base {
         </div>
     </div>
     <div class="filemanager-loading mdl-align">'.$icon_progress.'</div>
-    <div class="filemanager-container"'.$containerstyletag.'>
+    <div class="filemanager-container" >
         <div class="fm-content-wrapper">
             <div class="fp-content"></div>
             <div class="fm-empty-container">
@@ -237,7 +227,6 @@ class core_files_renderer extends plugin_renderer_base {
         </div>
         <div class="filemanager-updating">'.$icon_progress.'</div>
     </div>
-    <div class="fp-statusbar"></div>
 </div>';
         return preg_replace('/\{\!\}/', '', $html);
     }
diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index ff0d0c2..d81d5d9 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -83,14 +83,6 @@ M.form_filemanager.init = function(Y, options) {
             } else {
                 this.filecount = 0;
             }
-
-            this.publish('filemanager:content-changed', {
-                context : this,
-                prefix : 'filemanager',
-                preventable : false,
-                type : 'content-changed'
-            });
-
             // prepare filemanager for drag-and-drop upload
             this.filemanager = Y.one('#filemanager-'+options.client_id);
             if (this.filemanager.hasClass('filemanager-container') || !this.filemanager.one('.filemanager-container')) {
@@ -130,44 +122,6 @@ M.form_filemanager.init = function(Y, options) {
             this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
             this.filemanager.all('.fp-vb-icons').addClass('checked')
             this.refresh(this.currentpath); // MDL-31113 get latest list from server
-
-            // Make sure that the filemanager is at least shown within the constraints of the page
-            if ((this.filemanager.get('offsetWidth') + this.filemanager.getX()) > this.filemanager.get('docWidth')) {
-                this.filemanager.setStyle('width', Math.round(this.filemanager.get('docWidth') - this.filemanager.getX()));
-            }
-
-            if (Y.Resize) {
-                // We only do this is the YUI resize component is loaded
-                var resize = new Y.Resize({
-                    node: this.dndcontainer,
-                    wrap : true,
-                    handles : ['br']
-                }).plug(Y.Plugin.ResizeConstrained, {
-                    minWidth : 410,
-                    maxWidth : this.dndcontainer.ancestor('.ffilemanager').get('offsetWidth') || 1600,
-                    minHeight : 160,
-                    maxHeight : 1024
-                });
-                // When it resizes we need to correct the width and height of other elements.
-                resize.on('resize:resize', function(e) {
-                    this.filemanager.setStyle('width', e.info.offsetWidth);
-                    var fmcw = this.filemanager.one('.fp-content');
-                    if (fmcw) {
-                        fmcw.setStyle('height', this.dndcontainer.get('offsetHeight'));
-                    }
-                }, this);
-                // After resizing we update the user preference so that we always show them the file manager at the same size.
-                resize.on('resize:end', function(e){
-                    M.util.set_user_preference('filemanagerresizedto', Math.round(e.info.offsetWidth).toString()+','+Math.round(e.info.offsetHeight).toString());
-                });
-                // When content gets updated by the filemanager we need to auto-update the height of the resizeable area to include it.
-                this.on('filemanager:content-changed', function(){
-                    var fmcw = this.filemanager.one('.fp-content');
-                    if (fmcw) {
-                        fmcw.setStyle('height', this.dndcontainer.get('offsetHeight'));
-                    }
-                }, this);
-            }
         },
 
         wait: function() {
@@ -557,7 +511,7 @@ M.form_filemanager.init = function(Y, options) {
                 filenode : element_template,
                 callbackcontext : this,
                 callback : function(e, node) {
-                    if (e.preventDefault) {e.preventDefault();}
+                    if (e.preventDefault) { e.preventDefault(); }
                     if (node.type == 'folder') {
                         this.refresh(node.filepath);
                     } else {
@@ -565,7 +519,7 @@ M.form_filemanager.init = function(Y, options) {
                     }
                 },
                 rightclickcallback : function(e, node) {
-                    if (e.preventDefault) {e.preventDefault();}
+                    if (e.preventDefault) { e.preventDefault(); }
                     this.select_file(node);
                 },
                 classnamecallback : function(node) {
@@ -652,7 +606,6 @@ M.form_filemanager.init = function(Y, options) {
                 node.appendChild(Y.Node.create('<option/>').
                     set('value', list[i]).setContent(list[i]))
             }
-            this.fire('filemanager:content-changed');
         },
         update_file: function(confirmed) {
             var selectnode = this.selectnode;
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 5c8c2e5..1a0e2ec 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -1,7 +1,7 @@
 /**
  * File Picker and File Manager
  */
-.filemanager {width: 680px; min-width: 410px;}
+
 .filemanager, .file-picker {font-size:11px;color: #555555;letter-spacing: .2px;}
 .filemanager a, .file-picker a {color:#555555;}
 .filemanager a:hover, .file-picker a:hover {color:#555555;text-decoration: none;}
@@ -290,10 +290,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
-.filemanager .fp-content{overflow: auto;}
+.filemanager .fp-content{overflow: auto;max-height: 472px;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
-.filemanager.fm-loaded .fp-statusbar {background: #F2F2F2;border: 1px solid #BBB;border-top:0;min-height:2em;margin-bottom:5px;padding-right:2em;}
-.filemanager .yui3-resize-handle-inner-br {bottom:-2em;}
 
 /*
  * Icon view (File Manager only)
-- 
1.7.9.5


From 2ddf3ffcd2e28b7b0359bc2e81bfc80aba1934b1 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 3 Jul 2012 00:31:27 +0000
Subject: [PATCH 118/903] Automatically generated installer lang files

---
 install/lang/zh_cn/langconfig.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/zh_cn/langconfig.php b/install/lang/zh_cn/langconfig.php
index 23878bb..0bc12e9 100644
--- a/install/lang/zh_cn/langconfig.php
+++ b/install/lang/zh_cn/langconfig.php
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = '简体中文';
-- 
1.7.9.5


From 50b1caaf868f00b24b0b88e85f30a065a3ac208f Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 4 Jul 2012 00:31:59 +0000
Subject: [PATCH 119/903] Automatically generated installer lang files

---
 install/lang/ru/install.php    |    2 +-
 install/lang/sr_cr/install.php |    2 +-
 install/lang/sr_lt/install.php |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/install/lang/ru/install.php b/install/lang/ru/install.php
index d675c4f..bc06968 100644
--- a/install/lang/ru/install.php
+++ b/install/lang/ru/install.php
@@ -34,7 +34,7 @@ $string['admindirname'] = 'Каталог администратора';
 $string['availablelangs'] = 'Доступные языковые пакеты';
 $string['chooselanguagehead'] = 'Выберите язык';
 $string['chooselanguagesub'] = 'Сейчас необходимо выбрать язык ТОЛЬКО для сообщений во время установки. Язык сайта и пользовательских интерфейсов можно будет указать далее в процессе установки.';
-$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если вы хотите обновить сайт, пожалуйста, используйте скрипт admin/cli/upgrade.php.';
+$string['clialreadyinstalled'] = 'Файл config.php уже существует. Если Вы хотите обновить сайт, то используйте скрипт admin/cli/upgrade.php.';
 $string['cliinstallheader'] = 'Программа установки Moodle {$a} в режиме командной строки';
 $string['databasehost'] = 'Сервер баз данных';
 $string['databasename'] = 'Название базы данных';
diff --git a/install/lang/sr_cr/install.php b/install/lang/sr_cr/install.php
index bd8a77d..1dc0ec5 100644
--- a/install/lang/sr_cr/install.php
+++ b/install/lang/sr_cr/install.php
@@ -37,7 +37,7 @@ $string['chooselanguagesub'] = 'Молимо изаберите језик ко
 $string['clialreadyconfigured'] = 'Датотека config.php већ постоји. Молимо, користите admin/cli/install_database.php ако желите да инсталирате овај сајт.';
 $string['clialreadyinstalled'] = 'Датотека config.php већ постоји. Употребите команду admin/cli/upgrade.php ако желите да надоградите свај сајт.';
 $string['cliinstallheader'] = 'Moodle {$a} програм за инсталацију из командне линије';
-$string['databasehost'] = 'Сервер базе података :';
+$string['databasehost'] = 'Сервер базе података';
 $string['databasename'] = 'Име базе података';
 $string['databasetypehead'] = 'Изаберите драјвер базе података';
 $string['dataroot'] = 'Директоријум података';
diff --git a/install/lang/sr_lt/install.php b/install/lang/sr_lt/install.php
index 8bf648d..817b854 100644
--- a/install/lang/sr_lt/install.php
+++ b/install/lang/sr_lt/install.php
@@ -37,7 +37,7 @@ $string['chooselanguagesub'] = 'Molimo izaberite jezik koji će se koristiti tok
 $string['clialreadyconfigured'] = 'Datoteka config.php već postoji. Molimo, koristite admin/cli/install_database.php ako želite da instalirate ovaj sajt.';
 $string['clialreadyinstalled'] = 'Datoteka config.php već postoji. Upotrebite komandu admin/cli/upgrade.php ako želite da nadogradite svaj sajt.';
 $string['cliinstallheader'] = 'Moodle {$a} program za instalaciju iz komandne linije';
-$string['databasehost'] = 'Server baze podataka :';
+$string['databasehost'] = 'Server baze podataka';
 $string['databasename'] = 'Ime baze podataka';
 $string['databasetypehead'] = 'Izaberite drajver baze podataka';
 $string['dataroot'] = 'Direktorijum podataka';
-- 
1.7.9.5


From b24e6ed930d8c603fa150b075f082aaac664b9be Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 5 Jul 2012 00:31:12 +0000
Subject: [PATCH 120/903] Automatically generated installer lang files

---
 install/lang/ca_valencia/error.php   |   34 +++++++++++++++++++++
 install/lang/ca_valencia/install.php |   55 ++++++++++++++++++++++++++++++++++
 install/lang/pt/install.php          |    2 +-
 3 files changed, 90 insertions(+), 1 deletion(-)
 create mode 100644 install/lang/ca_valencia/error.php
 create mode 100644 install/lang/ca_valencia/install.php

diff --git a/install/lang/ca_valencia/error.php b/install/lang/ca_valencia/error.php
new file mode 100644
index 0000000..9df0f04
--- /dev/null
+++ b/install/lang/ca_valencia/error.php
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['cannotsavemd5file'] = 'No s\'ha pogut alçar el fitxer md5';
+$string['cannotsavezipfile'] = 'No s\'ha pogut alçar el fitxer zip';
diff --git a/install/lang/ca_valencia/install.php b/install/lang/ca_valencia/install.php
new file mode 100644
index 0000000..d8be051
--- /dev/null
+++ b/install/lang/ca_valencia/install.php
@@ -0,0 +1,55 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no està instal·lat. La instal·lació prosseguirà en anglés.';
+$string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servidor actualment està definit en {$a}.</p>
+
+<p>Això pot causar que Moodle tinga problemes de memòria més avant, especialment si teniu molts mòduls habilitats i/o molts usuaris.</p>
+
+<p>És recomanable que configureu el PHP amb un límit superior, com ara 40 MB, sempre que siga possible. Hi ha diverses maneres de fer això:</p>
+<ol>
+<li>Si podeu, recompileu el PHP amb <i>--enable-memory-limit</i>. Això permetrà que Moodle definisca el límit de memòria per si mateix.</li>
+<li>Si teniu accés al fitxer php.ini, podeu canviar el paràmetre <b>memory_limit</b> a 40 MB. Si no hi teniu accés podeu demanar al vostre administrador que ho faça ell.</li>
+<li>En alguns servidors PHP podeu crear un fitxer .htaccess dins del directori de Moodle amb esta línia:
+<p><blockquote>php_value memory_limit 40M</blockquote></p>
+<p>Tanmateix, en alguns servidors això farà que no funcioni <b>cap</b> pàgina PHP (es visualitzaran errors) en el qual cas hauríeu de suprimir el fitxer .htaccess.</p></li>
+</ol>';
+$string['pathssubdataroot'] = 'Necessiteu un espai on Moodle puga alçar els fitxers penjats. Este directori hauria de tindre permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que siga accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
+$string['phpversionhelp'] = '<p>Moodle necessita la versió de PHP 4.1.0 o posterior.</p>
+<p>A hores d\'ara esteu utilitzant la versió {$a}.</p>
+<p>Vos caldrà actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.</p>';
+$string['welcomep20'] = 'Esteu veient esta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions!';
+$string['welcomep30'] = 'Esta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcioni <strong>Moodle</strong>:';
+$string['welcomep50'] = 'L\'ús de totes les aplicacions d\'este paquet és governat per les seues llicències respectives. El paquet <strong>{$a->installername}</strong> complet és
+<a href="http://www.opensource.org/docs/definition_plain.html">codi font obert</a> i es distribueix
+sota llicència <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
+$string['welcomep60'] = 'Les pàgines següents vos guiaran per una sèrie de passos fàcils de seguir per configurar <strong>Moodle</strong> en el vostre ordinador. Podeu acceptar els paràmetres per defecte o, opcionalment, modificar-los perquè s\'ajusten a les vostres necessitats.';
diff --git a/install/lang/pt/install.php b/install/lang/pt/install.php
index 0645b9e..4e35aff 100644
--- a/install/lang/pt/install.php
+++ b/install/lang/pt/install.php
@@ -35,7 +35,7 @@ $string['availablelangs'] = 'Lista de línguas disponíveis';
 $string['chooselanguagehead'] = 'Escolha uma língua';
 $string['chooselanguagesub'] = 'Escolha por favor a língua a usar na instalação. Esta língua será usada por omissão no site, mas pode ser alterada posteriormente.';
 $string['clialreadyconfigured'] = 'O ficheiro config.php já existe; por favor execute admin/cli/install_database.php se quiser instalar este sítio.';
-$string['clialreadyinstalled'] = 'O ficheiro config.php já existe. Por favor, use o script admin/cli/upgrade.php se quiser atualizar o seu site.';
+$string['clialreadyinstalled'] = 'O ficheiro config.php já existe. Por favor, use o script admin/cli/upgrade.php se quiser atualizar o seu sítio.';
 $string['cliinstallheader'] = 'Programa de instalação do Moodle {$a} por linha de comandos';
 $string['databasehost'] = 'Servidor da base de dados';
 $string['databasename'] = 'Nome da base de dados';
-- 
1.7.9.5


From 62e9e694b74e05a541324af233aba7a08fdb6bbb Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Fri, 6 Jul 2012 10:04:54 +1200
Subject: [PATCH 121/903] weekly release 2.3+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 69bc916..5a11acf 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062500.02;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062500.03;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3+ (Build: 20120701)';   // Human-friendly version name
+$release  = '2.3+ (Build: 20120706)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From f2867a86729cb50b2d95ac42a0464978cb2923f4 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Fri, 6 Jul 2012 11:27:47 +1200
Subject: [PATCH 122/903] Moodle 2.3.1 release

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 5a11acf..e220f57 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062500.03;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3+ (Build: 20120706)';   // Human-friendly version name
+$release  = '2.3.1 (Build: 20120706)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 2dd2bd7ead4d1cb47cd59b6ee3299df71146e3a4 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 2 Jul 2012 12:49:57 +0800
Subject: [PATCH 123/903] MDL-18301 Gradebook: Added feature for components to
 control grade visibility

---
 grade/edit/tree/item.php      |    1 +
 grade/edit/tree/item_form.php |   15 +++++++++++----
 lang/en/grades.php            |    1 +
 lib/grade/grade_item.php      |   12 ++++++++++++
 lib/moodlelib.php             |    2 ++
 mod/quiz/lib.php              |   19 ++++++++++---------
 6 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/grade/edit/tree/item.php b/grade/edit/tree/item.php
index 5b2a7c0..0e80c6b 100644
--- a/grade/edit/tree/item.php
+++ b/grade/edit/tree/item.php
@@ -97,6 +97,7 @@ if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->ag
 } else {
     $item->aggregationcoef = format_float($item->aggregationcoef, 4);
 }
+$item->cancontrolvisibility = $grade_item->can_control_visibility();
 
 $mform = new edit_item_form(null, array('current'=>$item, 'gpr'=>$gpr));
 
diff --git a/grade/edit/tree/item_form.php b/grade/edit/tree/item_form.php
index 6dd9683..862a6fd 100644
--- a/grade/edit/tree/item_form.php
+++ b/grade/edit/tree/item_form.php
@@ -143,11 +143,18 @@ class edit_item_form extends moodleform {
         }
 
         /// hiding
-        // advcheckbox is not compatible with disabledIf!
-        $mform->addElement('checkbox', 'hidden', get_string('hidden', 'grades'));
+        if ($item->cancontrolvisibility) {
+            // advcheckbox is not compatible with disabledIf!
+            $mform->addElement('checkbox', 'hidden', get_string('hidden', 'grades'));
+            $mform->addElement('date_time_selector', 'hiddenuntil', get_string('hiddenuntil', 'grades'), array('optional'=>true));
+            $mform->disabledIf('hidden', 'hiddenuntil[off]', 'notchecked');
+        } else {
+            $mform->addElement('static', 'hidden', get_string('hidden', 'grades'),
+                    get_string('componentcontrolsvisibility', 'grades'));
+            // Unset hidden to avoid data override.
+            unset($item->hidden);
+        }
         $mform->addHelpButton('hidden', 'hidden', 'grades');
-        $mform->addElement('date_time_selector', 'hiddenuntil', get_string('hiddenuntil', 'grades'), array('optional'=>true));
-        $mform->disabledIf('hidden', 'hiddenuntil[off]', 'notchecked');
 
         /// locking
         $mform->addElement('advcheckbox', 'locked', get_string('locked', 'grades'));
diff --git a/lang/en/grades.php b/lang/en/grades.php
index 5443b07..850e873 100644
--- a/lang/en/grades.php
+++ b/lang/en/grades.php
@@ -117,6 +117,7 @@ $string['categorytotalname'] = 'Category total name';
 $string['categorytotalfull'] = '{$a->category} total';
 $string['combo'] = 'Tabs and Dropdown menu';
 $string['compact'] = 'Compact';
+$string['componentcontrolsvisibility'] = 'Whether this grade item is hidden is controlled by the activity settings.';
 $string['contract'] = 'Contract category';
 $string['controls'] = 'Controls';
 $string['courseavg'] = 'Course average';
diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php
index 64913cb..8b1d312 100644
--- a/lib/grade/grade_item.php
+++ b/lib/grade/grade_item.php
@@ -2067,4 +2067,16 @@ class grade_item extends grade_object {
             return false;
         }
     }
+
+    /**
+     * Returns whether the grade item can control the visibility of the grades
+     *
+     * @return bool
+     */
+    public function can_control_visibility() {
+        if (get_plugin_directory($this->itemtype, $this->itemmodule)) {
+            return !plugin_supports($this->itemtype, $this->itemmodule, FEATURE_CONTROLS_GRADE_VISIBILITY, false);
+        }
+        return true;
+    }
 }
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 2dd1f58..92ca95e 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -385,6 +385,8 @@ define('FEATURE_GRADE_HAS_GRADE', 'grade_has_grade');
 define('FEATURE_GRADE_OUTCOMES', 'outcomes');
 /** True if module supports advanced grading methods */
 define('FEATURE_ADVANCED_GRADING', 'grade_advanced_grading');
+/** True if module controls the grade visibility over the gradebook */
+define('FEATURE_CONTROLS_GRADE_VISIBILITY', 'controlsgradevisbility');
 
 /** True if module has code to track whether somebody viewed it */
 define('FEATURE_COMPLETION_TRACKS_VIEWS', 'completion_tracks_views');
diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 97bd198..6e28cbf 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1550,15 +1550,16 @@ function quiz_attempt_summary_link_to_reports($quiz, $cm, $context, $returnzero
  */
 function quiz_supports($feature) {
     switch($feature) {
-        case FEATURE_GROUPS:                  return true;
-        case FEATURE_GROUPINGS:               return true;
-        case FEATURE_GROUPMEMBERSONLY:        return true;
-        case FEATURE_MOD_INTRO:               return true;
-        case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
-        case FEATURE_GRADE_HAS_GRADE:         return true;
-        case FEATURE_GRADE_OUTCOMES:          return false;
-        case FEATURE_BACKUP_MOODLE2:          return true;
-        case FEATURE_SHOW_DESCRIPTION:        return true;
+        case FEATURE_GROUPS:                    return true;
+        case FEATURE_GROUPINGS:                 return true;
+        case FEATURE_GROUPMEMBERSONLY:          return true;
+        case FEATURE_MOD_INTRO:                 return true;
+        case FEATURE_COMPLETION_TRACKS_VIEWS:   return true;
+        case FEATURE_GRADE_HAS_GRADE:           return true;
+        case FEATURE_GRADE_OUTCOMES:            return false;
+        case FEATURE_BACKUP_MOODLE2:            return true;
+        case FEATURE_SHOW_DESCRIPTION:          return true;
+        case FEATURE_CONTROLS_GRADE_VISIBILITY: return true;
 
         default: return null;
     }
-- 
1.7.9.5


From 0408a480108468a33aa775f9511496ed3b3709e5 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Fri, 6 Jul 2012 13:14:52 +0800
Subject: [PATCH 124/903] MDL-33885 Blog: Added maxlength rule to subject
 field

---
 blog/edit_form.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/blog/edit_form.php b/blog/edit_form.php
index 2eb767a..292d55c 100644
--- a/blog/edit_form.php
+++ b/blog/edit_form.php
@@ -38,11 +38,12 @@ class blog_edit_form extends moodleform {
 
         $mform->addElement('header', 'general', get_string('general', 'form'));
 
-        $mform->addElement('text', 'subject', get_string('entrytitle', 'blog'), 'size="60"');
+        $mform->addElement('text', 'subject', get_string('entrytitle', 'blog'), array('size' => 60, 'maxlength' => 128));
         $mform->addElement('editor', 'summary_editor', get_string('entrybody', 'blog'), null, $summaryoptions);
 
         $mform->setType('subject', PARAM_TEXT);
         $mform->addRule('subject', get_string('emptytitle', 'blog'), 'required', null, 'client');
+        $mform->addRule('subject', get_string('maximumchars', '', 128), 'maxlength', 128, 'client');
 
         $mform->setType('summary_editor', PARAM_RAW);
         $mform->addRule('summary_editor', get_string('emptybody', 'blog'), 'required', null, 'client');
-- 
1.7.9.5


From 79406900b5498c6059ad16fe278397ae88b0bcbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Thu, 5 Jul 2012 19:33:06 +0200
Subject: [PATCH 125/903] MDL-34175 automatically fix admin JS links

---
 lib/outputrequirementslib.php |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php
index a50fcd2..5329958 100644
--- a/lib/outputrequirementslib.php
+++ b/lib/outputrequirementslib.php
@@ -399,6 +399,12 @@ class page_requirements_manager {
         if ($url instanceof moodle_url) {
             return $url;
         } else if (strpos($url, '/') === 0) {
+            // Fix the admin links if needed.
+            if ($CFG->admin !== 'admin') {
+                if (strpos($url, "/admin/") === 0) {
+                    $url = preg_replace("|^/admin/|", "/$CFG->admin/", $url);
+                }
+            }
             if (debugging()) {
                 // check file existence only when in debug mode
                 if (!file_exists($CFG->dirroot . strtok($url, '?'))) {
-- 
1.7.9.5


From 93f3eb63d18f8f3584f4eff4a33e0bd37a98cb6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Thu, 5 Jul 2012 19:42:20 +0200
Subject: [PATCH 126/903] MDL-34175 a few more renamed admin fixes

---
 admin/settings/mnet.php                            |    2 +-
 admin/tool/assignmentupgrade/batchupgrade.php      |    6 +++---
 admin/tool/assignmentupgrade/index.php             |    2 +-
 admin/tool/assignmentupgrade/listnotupgraded.php   |    8 ++++----
 admin/tool/assignmentupgrade/upgradesingle.php     |    2 +-
 .../assignmentupgrade/upgradesingleconfirm.php     |    2 +-
 admin/tool/profiling/index.php                     |    2 +-
 lib/outputrenderers.php                            |    2 +-
 mod/lti/typessettings.php                          |    2 +-
 9 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/admin/settings/mnet.php b/admin/settings/mnet.php
index ed77e03..9bb5b15 100644
--- a/admin/settings/mnet.php
+++ b/admin/settings/mnet.php
@@ -29,7 +29,7 @@ if (isset($CFG->mnet_dispatcher_mode) and $CFG->mnet_dispatcher_mode !== 'off')
             new admin_externalpage(
                 'mnetpeer' . $host->id,
                 $host->name,
-                $CFG->wwwroot . '/admin/mnet/peers.php?step=update&hostid=' . $host->id,
+                $CFG->wwwroot . '/'.$CFG->admin.'/mnet/peers.php?step=update&hostid=' . $host->id,
                 'moodle/site:config'
             )
         );
diff --git a/admin/tool/assignmentupgrade/batchupgrade.php b/admin/tool/assignmentupgrade/batchupgrade.php
index 31bca24..a654f6e 100644
--- a/admin/tool/assignmentupgrade/batchupgrade.php
+++ b/admin/tool/assignmentupgrade/batchupgrade.php
@@ -26,9 +26,9 @@ define('NO_OUTPUT_BUFFERING', true);
 
 require_once(dirname(__FILE__) . '/../../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
 
 require_sesskey();
 
diff --git a/admin/tool/assignmentupgrade/index.php b/admin/tool/assignmentupgrade/index.php
index f4cd179..71ed56f 100644
--- a/admin/tool/assignmentupgrade/index.php
+++ b/admin/tool/assignmentupgrade/index.php
@@ -35,7 +35,7 @@
 
 require_once(dirname(__FILE__) . '/../../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/locallib.php');
 
 // admin_externalpage_setup calls require_login and checks moodle/site:config
 admin_externalpage_setup('assignmentupgrade');
diff --git a/admin/tool/assignmentupgrade/listnotupgraded.php b/admin/tool/assignmentupgrade/listnotupgraded.php
index b03883a..9d68c26 100644
--- a/admin/tool/assignmentupgrade/listnotupgraded.php
+++ b/admin/tool/assignmentupgrade/listnotupgraded.php
@@ -24,10 +24,10 @@
 
 require_once(dirname(__FILE__) . '/../../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/paginationform.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/paginationform.php');
 
 // admin_externalpage_setup calls require_login and checks moodle/site:config
 admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrade_url('listnotupgraded'));
diff --git a/admin/tool/assignmentupgrade/upgradesingle.php b/admin/tool/assignmentupgrade/upgradesingle.php
index 5125bbb..67f24b0 100644
--- a/admin/tool/assignmentupgrade/upgradesingle.php
+++ b/admin/tool/assignmentupgrade/upgradesingle.php
@@ -24,7 +24,7 @@
 
 require_once(dirname(__FILE__) . '/../../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/locallib.php');
 
 require_sesskey();
 
diff --git a/admin/tool/assignmentupgrade/upgradesingleconfirm.php b/admin/tool/assignmentupgrade/upgradesingleconfirm.php
index b7ec24c..143ebf1 100644
--- a/admin/tool/assignmentupgrade/upgradesingleconfirm.php
+++ b/admin/tool/assignmentupgrade/upgradesingleconfirm.php
@@ -24,7 +24,7 @@
 
 require_once(dirname(__FILE__) . '/../../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/'.$CFG->admin.'/tool/assignmentupgrade/locallib.php');
 
 require_sesskey();
 
diff --git a/admin/tool/profiling/index.php b/admin/tool/profiling/index.php
index 197a694..eebfcd8 100644
--- a/admin/tool/profiling/index.php
+++ b/admin/tool/profiling/index.php
@@ -142,7 +142,7 @@ if (isset($script)) {
 
     // The flexitable that will root listings
     $table = new xhprof_table_sql('profiling-list-table');
-    $baseurl = $CFG->wwwroot . '/admin/tool/profiling/index.php';
+    $baseurl = $CFG->wwwroot . '/'.$CFG->admin.'/tool/profiling/index.php';
 
     // Check if we are listing all or some URL ones
     $sqlconditions = '';
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 9654364..b2d0e49 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -468,7 +468,7 @@ class core_renderer extends renderer_base {
                 $link= '<a title="' . $title . '" href="' . $url . '">' . $txt . '</a>';
                 $output .= '<div class="profilingfooter">' . $link . '</div>';
             }
-            $output .= '<div class="purgecaches"><a href="'.$CFG->wwwroot.'/admin/purgecaches.php?confirm=1&amp;sesskey='.sesskey().'">'.get_string('purgecaches', 'admin').'</a></div>';
+            $output .= '<div class="purgecaches"><a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/purgecaches.php?confirm=1&amp;sesskey='.sesskey().'">'.get_string('purgecaches', 'admin').'</a></div>';
         }
         if (!empty($CFG->debugvalidators)) {
             // NOTE: this is not a nice hack, $PAGE->url is not always accurate and $FULLME neither, it is not a bug if it fails. --skodak
diff --git a/mod/lti/typessettings.php b/mod/lti/typessettings.php
index f88cb5e..037aa50 100644
--- a/mod/lti/typessettings.php
+++ b/mod/lti/typessettings.php
@@ -106,7 +106,7 @@ if ($data = $form->get_data()) {
 }
 
 $PAGE->set_title("$SITE->shortname: " . get_string('toolsetup', 'lti'));
-$PAGE->navbar->add(get_string('lti_administration', 'lti'), $CFG->wwwroot.'/admin/settings.php?section=modsettinglti');
+$PAGE->navbar->add(get_string('lti_administration', 'lti'), $CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=modsettinglti');
 
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('toolsetup', 'lti'));
-- 
1.7.9.5


From 6128bf9d2501eba33fcf769454e3566dbcac7809 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Tue, 3 Jul 2012 20:00:21 +0200
Subject: [PATCH 127/903] MDL-34159 improve where_clause_list performance

---
 lib/dml/moodle_database.php |   37 ++++++++++++++++-------------
 lib/dml/tests/dml_test.php  |   54 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php
index 48a992c..b44b740 100644
--- a/lib/dml/moodle_database.php
+++ b/lib/dml/moodle_database.php
@@ -574,21 +574,38 @@ abstract class moodle_database {
      * @return array An array containing sql 'where' part and 'params'
      */
     protected function where_clause_list($field, array $values) {
+        if (empty($values)) {
+            return array("1 = 2", array());
+        }
+
+        // Note: Do not use get_in_or_equal() because it can not deal with bools and nulls.
+
         $params = array();
-        $select = array();
+        $select = "";
         $values = (array)$values;
         foreach ($values as $value) {
             if (is_bool($value)) {
                 $value = (int)$value;
             }
             if (is_null($value)) {
-                $select[] = "$field IS NULL";
+                $select = "$field IS NULL";
             } else {
-                $select[] = "$field = ?";
                 $params[] = $value;
             }
         }
-        $select = implode(" OR ", $select);
+        if ($params) {
+            if ($select !== "") {
+                $select = "$select OR ";
+            }
+            $count = count($params);
+            if ($count == 1) {
+                $select = $select."$field = ?";
+            } else {
+                $qs = str_repeat(',?', $count);
+                $qs = ltrim($qs, ',');
+                $select = $select."$field IN ($qs)";
+            }
+        }
         return array($select, $params);
     }
 
@@ -1034,10 +1051,6 @@ abstract class moodle_database {
      */
     public function get_recordset_list($table, $field, array $values, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            $select = '1 = 2'; // Fake condition, won't return rows ever. MDL-17645
-            $params = array();
-        }
         return $this->get_recordset_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
     }
 
@@ -1132,10 +1145,6 @@ abstract class moodle_database {
      */
     public function get_records_list($table, $field, array $values, $sort='', $fields='*', $limitfrom=0, $limitnum=0) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            // nothing to return
-            return array();
-        }
         return $this->get_records_select($table, $select, $params, $sort, $fields, $limitfrom, $limitnum);
     }
 
@@ -1662,10 +1671,6 @@ abstract class moodle_database {
      */
     public function delete_records_list($table, $field, array $values) {
         list($select, $params) = $this->where_clause_list($field, $values);
-        if (empty($select)) {
-            // nothing to delete
-            return true;
-        }
         return $this->delete_records_select($table, $select, $params);
     }
 
diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index a5ad8c2..2bb7270 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -1137,7 +1137,7 @@ class dml_testcase extends database_driver_testcase {
         $tablename = $table->getName();
 
         $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
-        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0');
         $table->add_index('course', XMLDB_INDEX_NOTUNIQUE, array('course'));
         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
         $dbman->create_table($table);
@@ -1146,9 +1146,11 @@ class dml_testcase extends database_driver_testcase {
         $DB->insert_record($tablename, array('course' => 3));
         $DB->insert_record($tablename, array('course' => 5));
         $DB->insert_record($tablename, array('course' => 2));
+        $DB->insert_record($tablename, array('course' => null));
+        $DB->insert_record($tablename, array('course' => 1));
+        $DB->insert_record($tablename, array('course' => 0));
 
         $rs = $DB->get_recordset_list($tablename, 'course', array(3, 2));
-
         $counter = 0;
         foreach ($rs as $record) {
             $counter++;
@@ -1156,6 +1158,54 @@ class dml_testcase extends database_driver_testcase {
         $this->assertEquals(3, $counter);
         $rs->close();
 
+        $rs = $DB->get_recordset_list($tablename, 'course', array(3));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(2, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(null));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(6, null));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(null, 5, 5, 5));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(2, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(true));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
+        $rs = $DB->get_recordset_list($tablename, 'course', array(false));
+        $counter = 0;
+        foreach ($rs as $record) {
+            $counter++;
+        }
+        $this->assertEquals(1, $counter);
+        $rs->close();
+
         $rs = $DB->get_recordset_list($tablename, 'course',array()); // Must return 0 rows without conditions. MDL-17645
 
         $counter = 0;
-- 
1.7.9.5


From 880f8e7b84d495cc629474c3a67dba60bf96e409 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Tue, 3 Jul 2012 17:57:27 +0200
Subject: [PATCH 128/903] MDL-34147 use cygwin style paths in phpunit hints

---
 admin/tool/phpunit/cli/util.php            |    2 +-
 lib/phpunit/bootstraplib.php               |   17 ++++++++++++++++-
 lib/phpunit/classes/hint_resultprinter.php |    8 +++++++-
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/admin/tool/phpunit/cli/util.php b/admin/tool/phpunit/cli/util.php
index 1a8cea7..2986d64 100644
--- a/admin/tool/phpunit/cli/util.php
+++ b/admin/tool/phpunit/cli/util.php
@@ -123,7 +123,7 @@ Options:
 -h, --help     Print out this help
 
 Example:
-\$/usr/bin/php lib/phpunit/tool.php --install
+\$ php ".phpunit_bootstrap_cli_argument_path('/admin/tool/phpunit/cli/util.php')." --install
 ";
     echo $help;
     exit(0);
diff --git a/lib/phpunit/bootstraplib.php b/lib/phpunit/bootstraplib.php
index d28de8d..bc74dc9 100644
--- a/lib/phpunit/bootstraplib.php
+++ b/lib/phpunit/bootstraplib.php
@@ -101,7 +101,11 @@ function phpunit_bootstrap_cli_argument_path($moodlepath) {
     $path = realpath($CFG->dirroot.$moodlepath);
 
     if (strpos($path, $cwd) === 0) {
-        return substr($path, strlen($cwd));
+        $path = substr($path, strlen($cwd));
+    }
+
+    if (phpunit_bootstrap_is_cygwin()) {
+        $path = str_replace('\\', '/', $path);
     }
 
     return $path;
@@ -140,3 +144,14 @@ function phpunit_boostrap_fix_file_permissions($file) {
 
     return true;
 }
+
+/**
+ * Find out if running under Cygwin on Windows.
+ * @return bool
+ */
+function phpunit_bootstrap_is_cygwin() {
+    if (empty($_SERVER['SHELL']) or empty($_SERVER['OS'])) {
+        return false;
+    }
+    return ($_SERVER['OS'] === 'Windows_NT' and $_SERVER['SHELL'] === '/bin/bash');
+}
diff --git a/lib/phpunit/classes/hint_resultprinter.php b/lib/phpunit/classes/hint_resultprinter.php
index 638b4d0..9e46811 100644
--- a/lib/phpunit/classes/hint_resultprinter.php
+++ b/lib/phpunit/classes/hint_resultprinter.php
@@ -74,6 +74,12 @@ class Hint_ResultPrinter extends PHPUnit_TextUI_ResultPrinter {
             $file = substr($file, strlen($cwd)+1);
         }
 
-        $this->write("\nTo re-run:\n phpunit $testName $file\n");
+        $executable = 'phpunit';
+        if (phpunit_bootstrap_is_cygwin()) {
+            $file = str_replace('\\', '/', $file);
+            $executable = 'phpunit.bat';
+        }
+
+        $this->write("\nTo re-run:\n $executable $testName $file\n");
     }
 }
-- 
1.7.9.5


From fe6d428185e66746d6ebfa61728c6a64e946e8ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Thu, 5 Jul 2012 20:33:26 +0200
Subject: [PATCH 129/903] MDL-34046 improve mixed files upgrade error

Credit goes to Gordon Bateson.
---
 admin/renderer.php |    2 +-
 lang/en/admin.php  |   20 ++++++++++++++++++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/admin/renderer.php b/admin/renderer.php
index c064ca6..3a3c2bd 100644
--- a/admin/renderer.php
+++ b/admin/renderer.php
@@ -68,7 +68,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $output .= $this->header();
         $output .= $this->heading(get_string('upgradestalefiles', 'admin'));
         $output .= $this->box_start('generalbox', 'notice');
-        $output .= get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading'));
+        $output .= format_text(get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading')), FORMAT_MARKDOWN);
         $output .= html_writer::empty_tag('br');
         $output .= html_writer::tag('div', $this->single_button($this->page->url, get_string('reload'), 'get'), array('class' => 'buttons'));
         $output .= $this->box_end();
diff --git a/lang/en/admin.php b/lang/en/admin.php
index baf70f5..30253fd 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -1010,8 +1010,24 @@ $string['upgradelogs'] = 'For full functionality, your old logs need to be upgra
 $string['upgradelogsinfo'] = 'Some changes have recently been made in the way logs are stored.  To be able to view all of your old logs on a per-activity basis, your old logs need to be upgraded.  Depending on your site this can take a long time (eg several hours) and can be quite taxing on the database for large sites.  Once you start this process you should let it finish (by keeping the browser window open).  Don\'t worry - your site will work fine for other people while the logs are being upgraded.<br /><br />Do you want to upgrade your logs now?';
 $string['upgradesettings'] = 'New settings';
 $string['upgradesettingsintro'] = 'The settings shown below were added during your last Moodle upgrade. Make any changes necessary to the defaults and then click the &quot;Save changes&quot; button at the bottom of this page.';
-$string['upgradestalefiles'] = 'Invalid installation files detected, upgrade cannot continue';
-$string['upgradestalefilesinfo'] = 'Some old PHP scripts have been detected which may indicate that you installed this version over an older one. Please fix the installation directory by removing all old scripts (except config.php) before installing the new version and then try the upgrade again. You can find more information in upgrade documentation at <a href="{$a}">{$a}</a>';
+$string['upgradestalefiles'] = 'Mixed Moodle versions detected, upgrade cannot continue';
+$string['upgradestalefilesinfo'] = 'The Moodle update process has been paused because PHP scripts from at least two major versions of Moodle have been detected in the Moodle directory.
+
+This can cause significant problems later, so in order to continue you must ensure that the Moodle directory contains only files for a single version of Moodle.
+
+The recommended way to clean your Moodle directory is as follows:
+
+* rename the current Moodle directory to "moodle_old"
+* create a new Moodle directory containing only files from either a standard Moodle package download, or from the Moodle CVS or GIT repositories
+* move the original config.php file and any non-standard plugins from the "moodle_old" directory to the new Moodle directory
+
+When you have a clean Moodle directory, refresh this page to resume the Moodle update process.
+
+This warning is often caused by unzipping a standard Moodle package over a previous version of Moodle. While this is OK for minor upgrades, it is strongly discouraged for major Moodle upgrades.
+
+This warning can also be caused by an incomplete checkout or update operation from a CVS, SVN or GIT repository, in which case you may just have to wait for the operation complete, or perhaps run the appropriate clean up command and retry the operation.
+
+You can find more information in upgrade documentation at <a href="{$a}">{$a}</a>';
 $string['upgradesure'] = 'Your Moodle files have been changed, and you are about to automatically upgrade your server to this version: <br /><br />
 <strong>{$a}</strong> <br /><br />
 Once you do this you can not go back again. <br /><br />
-- 
1.7.9.5


From 25afd64b0f69b7d85ae94bb851c93a91e0134757 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Fri, 6 Jul 2012 15:59:57 +0800
Subject: [PATCH 130/903] MDL-26145 mod_chat Talk feature not working
 correctly

---
 mod/chat/gui_ajax/module.js |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/chat/gui_ajax/module.js b/mod/chat/gui_ajax/module.js
index 71c0241..fc48974 100644
--- a/mod/chat/gui_ajax/module.js
+++ b/mod/chat/gui_ajax/module.js
@@ -247,11 +247,11 @@ M.mod_chat_ajax.init = function(Y, cfg) {
                     li.all('td').item(1).append(Y.Node.create('<strong><a target="_blank" href="'+users[i].url+'">'+ users[i].name+'</a></strong>'));
                 } else {
                     li.all('td').item(1).append(Y.Node.create('<div><a target="_blank" href="'+users[i].url+'">'+users[i].name+'</a></div>'));
-                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>&nbsp;');
+                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>');
                     talk.on('click', this.talkto, this, users[i].name);
                     var beep = Y.Node.create('<a href="###">'+M.str.chat.beep+'</a>');
                     beep.on('click', this.send, this, users[i].id);
-                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append(beep));
+                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append('&nbsp;').append(beep));
                 }
                 list.append(li);
             }
-- 
1.7.9.5


From 69a600a067d52af195fb1045ed6c22262af88739 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 4 Jul 2012 10:55:52 +0100
Subject: [PATCH 131/903] MDL-34171 qformat_gift: Fix edge case with special
 character escaping.

We need to escape \ on export, because it is un-escaped on import.
---
 question/format/gift/format.php                |    4 +-
 question/format/gift/tests/giftformat_test.php |   69 ++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/question/format/gift/format.php b/question/format/gift/format.php
index 7aa95f2..06bcebc 100644
--- a/question/format/gift/format.php
+++ b/question/format/gift/format.php
@@ -553,8 +553,8 @@ class qformat_gift extends qformat_default {
     protected function repchar($text, $notused = 0) {
         // Escapes 'reserved' characters # = ~ {) :
         // Removes new lines
-        $reserved = array( '#', '=', '~', '{', '}', ':', "\n", "\r");
-        $escaped =  array('\#','\=','\~','\{','\}','\:', '\n', '' );
+        $reserved = array(  '\\',  '#', '=', '~', '{', '}', ':', "\n", "\r");
+        $escaped =  array('\\\\', '\#','\=','\~','\{','\}','\:', '\n', '' );
 
         $newtext = str_replace($reserved, $escaped, $text);
         return $newtext;
diff --git a/question/format/gift/tests/giftformat_test.php b/question/format/gift/tests/giftformat_test.php
index 73a8a6e..e06a123 100644
--- a/question/format/gift/tests/giftformat_test.php
+++ b/question/format/gift/tests/giftformat_test.php
@@ -885,4 +885,73 @@ FALSE#42 is the Ultimate Answer.#You gave the right answer.}";
 
         $this->assert_same_gift($expectedgift, $gift);
     }
+
+    public function test_export_backslash() {
+        // There was a bug (MDL-34171) where \\ was getting exported as \\, not
+        // \\\\, and on import, \\ in converted to \.
+        // We need \\\\ in the test code, because of PHPs string escaping rules.
+        $qdata = (object) array(
+            'id' => 666 ,
+            'name' => 'backslash',
+            'questiontext' => 'A \\ B \\\\ C',
+            'questiontextformat' => FORMAT_MOODLE,
+            'generalfeedback' => '',
+            'generalfeedbackformat' => FORMAT_MOODLE,
+            'defaultmark' => 1,
+            'penalty' => 0.3333333,
+            'length' => 1,
+            'qtype' => 'essay',
+            'options' => (object) array(
+                'responseformat' => 'editor',
+                'responsefieldlines' => 15,
+                'attachments' => 0,
+                'graderinfo' => '',
+                'graderinfoformat' => FORMAT_HTML,
+            ),
+        );
+
+        $exporter = new qformat_gift();
+        $gift = $exporter->writequestion($qdata);
+
+        $expectedgift = "// question: 666  name: backslash
+::backslash::A \\\\ B \\\\\\\\ C{}
+
+";
+
+        $this->assert_same_gift($expectedgift, $gift);
+    }
+
+    public function test_import_backslash() {
+        // There was a bug (MDL-34171) where \\ in the import was getting changed
+        // to \. This test checks for that.
+        // We need \\\\ in the test code, because of PHPs string escaping rules.
+        $gift = '
+// essay
+::double backslash:: A \\\\ B \\\\\\\\ C{}';
+        $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
+
+        $importer = new qformat_gift();
+        $q = $importer->readquestion($lines);
+
+        $expectedq = (object) array(
+            'name' => 'double backslash',
+            'questiontext' => 'A \\ B \\\\ C',
+            'questiontextformat' => FORMAT_MOODLE,
+            'generalfeedback' => '',
+            'generalfeedbackformat' => FORMAT_MOODLE,
+            'qtype' => 'essay',
+            'defaultmark' => 1,
+            'penalty' => 0.3333333,
+            'length' => 1,
+            'responseformat' => 'editor',
+            'responsefieldlines' => 15,
+            'attachments' => 0,
+            'graderinfo' => array(
+                'text' => '',
+                'format' => FORMAT_HTML,
+                'files' => array()),
+        );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
 }
-- 
1.7.9.5


From 6b4c491cb49c71f89cc3a14ef1f85cd09b432d21 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 6 Jun 2012 23:28:52 +0800
Subject: [PATCH 132/903] MDL-33514 - rss: only retrieve RSS feeds for valid
 users

---
 lib/rsslib.php |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/rsslib.php b/lib/rsslib.php
index 7c33d91..703cbcb 100644
--- a/lib/rsslib.php
+++ b/lib/rsslib.php
@@ -405,11 +405,12 @@ function rss_geterrorxmlfile($errortype = 'rsserror') {
  */
 function rss_get_userid_from_token($token) {
     global $DB;
-    $record = $DB->get_record('user_private_key', array('script'=>'rss','value' => $token), 'userid', IGNORE_MISSING);
-    if ($record) {
-        return $record->userid;
-    }
-    return null;
+
+    $sql = 'SELECT u.id FROM {user} u
+            JOIN {user_private_key} k ON u.id = k.userid
+            WHERE u.deleted = 0 AND u.confirmed = 1
+            AND k.value = ?';
+    return $DB->get_field_sql($sql, array($token), IGNORE_MISSING);
 }
 
 /**
-- 
1.7.9.5


From aacf3222dfedd55da6857e3328e83f96c536fabc Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 11 Jun 2012 10:26:29 +0800
Subject: [PATCH 133/903] MDL-33514 - rss: also exclude suspended users feeds

Thanks Petr!
---
 lib/rsslib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/rsslib.php b/lib/rsslib.php
index 703cbcb..dda8714 100644
--- a/lib/rsslib.php
+++ b/lib/rsslib.php
@@ -409,7 +409,7 @@ function rss_get_userid_from_token($token) {
     $sql = 'SELECT u.id FROM {user} u
             JOIN {user_private_key} k ON u.id = k.userid
             WHERE u.deleted = 0 AND u.confirmed = 1
-            AND k.value = ?';
+            AND u.suspended = 0 AND k.value = ?';
     return $DB->get_field_sql($sql, array($token), IGNORE_MISSING);
 }
 
-- 
1.7.9.5


From f19cd427091d57a03fe072bf8a1ccc27f01b4e61 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 9 Jul 2012 10:56:14 +1200
Subject: [PATCH 134/903] MDL-33575 choice module: add label to checkbox
 element when privacy of results is set to publish
 full results

---
 mod/choice/renderer.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/choice/renderer.php b/mod/choice/renderer.php
index 07bbd19..dc89877 100644
--- a/mod/choice/renderer.php
+++ b/mod/choice/renderer.php
@@ -214,7 +214,7 @@ class mod_choice_renderer extends plugin_renderer_base {
                         }
 
                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
-                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
+                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'', null, array('id' => 'attempt-user'.$user->id));
                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
                         }
                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
@@ -222,6 +222,7 @@ class mod_choice_renderer extends plugin_renderer_base {
 
                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
                         $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
+                        $name = html_writer::label($name, 'attempt-user'.$user->id);
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
                         $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
-- 
1.7.9.5


From d21224437513e83fba89d4e1e0723df08be3c014 Mon Sep 17 00:00:00 2001
From: Ruslan Kabalin <ruslan.kabalin@luns.net.uk>
Date: Fri, 22 Jun 2012 15:50:49 +0100
Subject: [PATCH 135/903] MDL-33890 Make course blocks less theme dependant

This fix checks that the empty block region is actaually the standard one, so
it can be hidden. The blocks move operating area is not resticted to page
content any more.
---
 lib/yui/blocks/blocks.js |   15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/lib/yui/blocks/blocks.js b/lib/yui/blocks/blocks.js
index 21cc5f1..cec719f 100644
--- a/lib/yui/blocks/blocks.js
+++ b/lib/yui/blocks/blocks.js
@@ -8,7 +8,6 @@ YUI.add('moodle-core-blocks', function(Y) {
         EDITINGMOVE : 'editing_move',
         HEADER : 'header',
         LIGHTBOX : 'lightbox',
-        PAGECONTENT : 'page-content',
         REGIONCONTENT : 'region-content',
         SKIPBLOCK : 'skip-block',
         SKIPBLOCKTO : 'skip-block-to'
@@ -28,7 +27,8 @@ YUI.add('moodle-core-blocks', function(Y) {
             this.parentnodeclass = CSS.REGIONCONTENT;
 
             // Initialise blocks dragging
-            var blockregionlist = Y.Node.all('#'+CSS.PAGECONTENT+' div.'+CSS.BLOCKREGION);
+            // Find all block regions on the page
+            var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
 
             if (blockregionlist.size() === 0) {
                 return false;
@@ -84,9 +84,6 @@ YUI.add('moodle-core-blocks', function(Y) {
                         }).plug(Y.Plugin.DDProxy, {
                             // Don't move the node at the end of the drag
                             moveOnEnd: false
-                        }).plug(Y.Plugin.DDConstrained, {
-                            // Keep it inside the .course-content
-                            constrain: '#'+CSS.PAGECONTENT
                         }).plug(Y.Plugin.DDWinScroll);
                     }
                 }, this);
@@ -139,6 +136,10 @@ YUI.add('moodle-core-blocks', function(Y) {
                 return false;
             }
 
+            // TODO: Hiding-displaying block region only works for base theme blocks
+            // (region-pre, region-post) at the moment. It should be improved
+            // to work with custom block regions as well.
+
             // TODO: Fix this for the case when user drag block towards empty section,
             // then the section appears, then user chnages his mind and moving back to
             // original section. The opposite section remains opened and empty.
@@ -151,9 +152,9 @@ YUI.add('moodle-core-blocks', function(Y) {
             }
 
             // Moving from empty region-content towards the opposite one,
-            // hide empty one
+            // hide empty one (only for region-pre, region-post areas at the moment).
             regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
-            if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0) {
+            if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
                 if (!documentbody.hasClass('side-'+regionname+'-only')) {
                     documentbody.addClass('side-'+regionname+'-only');
                 }
-- 
1.7.9.5


From 918f6d2c34cab4dd840fc4735a62d53d6800ee42 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Fri, 29 Jun 2012 14:50:40 +0800
Subject: [PATCH 136/903] MDL-27831 calendar: Removing reduntand control icons
 in delete.php

---
 calendar/delete.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/calendar/delete.php b/calendar/delete.php
index e79e945..9ca5374 100644
--- a/calendar/delete.php
+++ b/calendar/delete.php
@@ -124,7 +124,7 @@ echo $OUTPUT->box_end();
 $event->time = calendar_format_event_time($event, time(), null, false);
 $renderer = $PAGE->get_renderer('core_calendar');
 echo $renderer->start_layout();
-echo $renderer->event($event);
+echo $renderer->event($event, false);
 echo $renderer->complete_layout();
 
 echo $OUTPUT->box_end();
-- 
1.7.9.5


From 48bdd5217261e6bb3a8b4a4296bcd1da13250a3e Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Sat, 16 Jun 2012 22:47:48 +1200
Subject: [PATCH 137/903] MDL-33788 completion: SQL optimisation

---
 lib/completion/cron.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/completion/cron.php b/lib/completion/cron.php
index 3645c06..bf2a646 100644
--- a/lib/completion/cron.php
+++ b/lib/completion/cron.php
@@ -377,10 +377,11 @@ function completion_cron_completions() {
         SET
             reaggregate = 0
         WHERE
-            reaggregate < {$timestarted}
+            reaggregate < :timestarted
+        AND reaggregate > 0
     ";
 
-    $DB->execute($sql);
+    $DB->execute($sql, array('timestarted' => $timestarted));
 }
 
 /**
-- 
1.7.9.5


From d36249d6d69862a6219a1290a678a01039e9d50d Mon Sep 17 00:00:00 2001
From: David Balch <david.balch@conted.ox.ac.uk>
Date: Wed, 4 Jul 2012 09:24:23 +0800
Subject: [PATCH 138/903] MDL-34143 Add file type information for .mdb .accdb
 (MS Access databases)

---
 lib/filelib.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/filelib.php b/lib/filelib.php
index fd6b23d..3b2d453 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -1375,6 +1375,7 @@ function &get_mimetypes_array() {
         'xxx'  => array ('type'=>'document/unknown', 'icon'=>'unknown'),
         '3gp'  => array ('type'=>'video/quicktime', 'icon'=>'quicktime', 'groups'=>array('video'), 'string'=>'video'),
         'aac'  => array ('type'=>'audio/aac', 'icon'=>'audio', 'groups'=>array('audio'), 'string'=>'audio'),
+        'accdb'  => array ('type'=>'application/msaccess', 'icon'=>'base'),
         'ai'   => array ('type'=>'application/postscript', 'icon'=>'eps', 'groups'=>array('image'), 'string'=>'image'),
         'aif'  => array ('type'=>'audio/x-aiff', 'icon'=>'audio', 'groups'=>array('audio'), 'string'=>'audio'),
         'aiff' => array ('type'=>'audio/x-aiff', 'icon'=>'audio', 'groups'=>array('audio'), 'string'=>'audio'),
@@ -1438,6 +1439,7 @@ function &get_mimetypes_array() {
         'latex'=> array ('type'=>'application/x-latex', 'icon'=>'text'),
         'm'    => array ('type'=>'text/plain', 'icon'=>'sourcecode'),
         'mbz'  => array ('type'=>'application/vnd.moodle.backup', 'icon'=>'moodle'),
+        'mdb'  => array ('type'=>'application/x-msaccess', 'icon'=>'base'),
         'mov'  => array ('type'=>'video/quicktime', 'icon'=>'quicktime', 'groups'=>array('video','web_video'), 'string'=>'video'),
         'movie'=> array ('type'=>'video/x-sgi-movie', 'icon'=>'quicktime', 'groups'=>array('video'), 'string'=>'video'),
         'm3u'  => array ('type'=>'audio/x-mpegurl', 'icon'=>'mp3', 'groups'=>array('audio'), 'string'=>'audio'),
-- 
1.7.9.5


From b002b36ed30370f30f001221550a4e97ce3ec96e Mon Sep 17 00:00:00 2001
From: Barbara Ramiro <barbara@moodle.com>
Date: Wed, 20 Jun 2012 13:48:43 +0800
Subject: [PATCH 139/903] MDL-33795 Increased file picker width and height

---
 theme/base/style/filemanager.css |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 1a0e2ec..836233a 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -18,18 +18,18 @@
 .yui3-panel-focused {outline: none;}
 #filesskin .yui3-panel-content {padding-bottom: 20px;background: #F2F2F2;border-radius: 8px;border: 1px solid #FFFFFF;display: inline-block;-webkit-box-shadow: 5px 5px 20px 0px #666666;-moz-box-shadow: 5px 5px 20px 0px #666666;box-shadow: 5px 5px 20px 0px #666666;}
 #filesskin .yui3-widget-hd {border-radius: 10px 10px 0px 0px;border-bottom: 1px solid #BBBBBB;padding:5px 5px 5px 5px;text-align: center;font-size:12px;letter-spacing: 1px;color:#333333; text-shadow: 1px 1px 1px #FFFFFF;filter: dropshadow(color=#FFFFFF, offx=1, offy=1);
-background: #CCCCCC;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#CCCCCC');background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC);}
+background: #E2E2E2;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#CCCCCC');background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC);}
 .fp-panel-button {background: #FFFFFF;padding: 3px 20px 2px 20px; text-align: center;margin:10px; border-radius: 10px;display: inline-block;-webkit-box-shadow: 2px 2px 3px .1px #999999;-moz-box-shadow: 2px 2px 3px .1px #999999;box-shadow: 2px 2px 3px .1px #999999;}
 
 /*
  * File Picker layout
  */
-#filesskin .file-picker.fp-generallayout {width: 724px;background: #FFFFFF;border-radius:10px;border: 1px solid #CCCCCC;position: relative;}
+#filesskin .file-picker.fp-generallayout {width: 859px;background: #FFFFFF;border-radius:10px;border: 1px solid #CCCCCC;position: relative;}
 .file-picker .fp-repo-area {width:180px;overflow:auto;display:inline-block;border-right:1px solid #BBBBBB;position:absolute;top:26px;bottom:1px;}
 .dir-rtl .file-picker .fp-repo-area {border-left:1px solid #BBBBBB; border-right: none;}
 .file-picker .fp-repo-items {vertical-align:top;display: inline-block;margin-left: 181px;}
 .file-picker .fp-navbar {background: #F2F2F2;min-height:22px;border-bottom: 1px solid #BBBBBB;padding: 5px 8px;}
-.file-picker .fp-content {background: #FFFFFF;clear: both;overflow:auto;width: 543px;height: 349px;margin-bottom:-14px;}
+.file-picker .fp-content {background: #FFFFFF;clear: both;overflow:auto;width: 678px;height: 477px;margin-bottom:-14px;}
 
 .dir-rtl .file-picker .fp-repo-items {margin-right: 181px;}
 
-- 
1.7.9.5


From 9309b2dba8294462543d05f6102a6b346c6775e9 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 4 Jul 2012 15:02:07 +0800
Subject: [PATCH 140/903] MDL-17395 auth_email: clarify description

---
 auth/email/lang/en/auth_email.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/auth/email/lang/en/auth_email.php b/auth/email/lang/en/auth_email.php
index edd1a9e..e1dbb71 100644
--- a/auth/email/lang/en/auth_email.php
+++ b/auth/email/lang/en/auth_email.php
@@ -23,7 +23,7 @@
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-$string['auth_emaildescription'] = 'Email confirmation is the default authentication method.  When the user signs up, choosing their own new username and password, a confirmation email is sent to the user\'s email address.  This email contains a secure link to a page where the user can confirm their account. Future logins just check the username and password against the stored values in the Moodle database.';
+$string['auth_emaildescription'] = '<p>Email-based self-registration enables a user to create their own account via a \'Create new account\' button on the login page. The user then receives an email containing a secure link to a page where they can confirm their account. Future logins just check the username and password against the stored values in the Moodle database.</p><p>Note: In addition to enabling the plugin, email-based self-registration must also be selected from the self registration drop-down menu on the \'Manage authentication\' page.</p>';
 $string['auth_emailnoemail'] = 'Tried to send you an email but failed!';
 $string['auth_emailrecaptcha'] = 'Adds a visual/audio confirmation form element to the signup page for email self-registering users. This protects your site against spammers and contributes to a worthwhile cause. See http://www.google.com/recaptcha/learnmore for more details. <br /><em>PHP cURL extension is required.</em>';
 $string['auth_emailrecaptcha_key'] = 'Enable reCAPTCHA element';
-- 
1.7.9.5


From 65ab8112a3ca79d21aa0fbc945b4cb092060fa2e Mon Sep 17 00:00:00 2001
From: Gilles-Philippe Leblanc <gilles-philippe.leblanc@umontreal.ca>
Date: Fri, 6 Jul 2012 09:41:19 +1200
Subject: [PATCH 141/903] MDL-33822 SCORM Interactions report - fix formatting
 of empty cells.

---
 mod/scorm/report/interactions/report.php |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/mod/scorm/report/interactions/report.php b/mod/scorm/report/interactions/report.php
index 99204d1..d9152d1 100644
--- a/mod/scorm/report/interactions/report.php
+++ b/mod/scorm/report/interactions/report.php
@@ -185,6 +185,7 @@ class scorm_interactions_report extends scorm_default_report {
             $countsql .= $from.$where;
             $attempts = $DB->get_records_sql($select.$from.$where, $params);
             $questioncount = get_scorm_question_count($scorm->id);
+            $nbmaincolumns = count($columns);
             for($id = 0; $id < $questioncount; $id++) {
                 if ($displayoptions['qtext']) {
                     $columns[] = 'question' . $id;
@@ -476,9 +477,7 @@ class scorm_interactions_report extends scorm_default_report {
                                     $row[] = $score;
                                 }
                                 // interaction data
-                                $i=0;
-                                $element='cmi.interactions_'.$i.'.id';
-                                while(isset($trackdata->$element)) {
+                                for ($i=0; $i < $questioncount; $i++) {
                                     if ($displayoptions['qtext']) {
                                         $element='cmi.interactions_'.$i.'.id';
                                         if (isset($trackdata->$element)) {
@@ -513,8 +512,6 @@ class scorm_interactions_report extends scorm_default_report {
                                             $row[] = '&nbsp;';
                                         }
                                     }
-                                    $i++;
-                                    $element = 'cmi.interactions_'.$i.'.id';
                                 }
                             //---end of interaction data*/
                             } else {
@@ -525,6 +522,10 @@ class scorm_interactions_report extends scorm_default_report {
                                 } else {
                                     $row[] = $strstatus;
                                 }
+                                // complete the empty cells
+                                for ($i=0; $i < count($columns) - $nbmaincolumns; $i++) {
+                                    $row[] = '&nbsp;';
+                                }
                             }
                         }
                     }
-- 
1.7.9.5


From d563d4869475f7bc1e6ac840590f1983eb2a8c9e Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Fri, 29 Jun 2012 11:13:51 -0400
Subject: [PATCH 142/903] MDL-27800 admin: make front page restore link
 consistent

---
 admin/settings/frontpage.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/admin/settings/frontpage.php b/admin/settings/frontpage.php
index edd701d..c380e43 100644
--- a/admin/settings/frontpage.php
+++ b/admin/settings/frontpage.php
@@ -77,7 +77,7 @@ if (!during_initial_install()) { //do not use during installation
 
         $ADMIN->add('frontpage', new admin_externalpage('frontpagebackup', new lang_string('frontpagebackup', 'admin'), $CFG->wwwroot.'/backup/backup.php?id='.SITEID, 'moodle/backup:backupcourse', false, $frontpagecontext));
 
-        $ADMIN->add('frontpage', new admin_externalpage('frontpagerestore', new lang_string('frontpagerestore', 'admin'), $CFG->wwwroot.'/files/index.php?id='.SITEID.'&amp;wdir=/backupdata', 'moodle/restore:restorecourse', false, $frontpagecontext));
+        $ADMIN->add('frontpage', new admin_externalpage('frontpagerestore', new lang_string('frontpagerestore', 'admin'), $CFG->wwwroot.'/backup/restorefile.php?contextid='.$frontpagecontext->id, 'moodle/restore:restorecourse', false, $frontpagecontext));
 
         $questioncapabilities = array(
                 'moodle/question:add',
-- 
1.7.9.5


From 898010f1aa9853297fcb805bccf146d629040c47 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 4 Jul 2012 14:06:58 +0800
Subject: [PATCH 143/903] MDL-34061 mod_resource: filter settings weren't
 coming from defaults

---
 mod/resource/lib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/resource/lib.php b/mod/resource/lib.php
index 8243c5b..b500784 100644
--- a/mod/resource/lib.php
+++ b/mod/resource/lib.php
@@ -514,6 +514,7 @@ function resource_dndupload_handle($uploadinfo) {
     $data->printintro = $config->printintro;
     $data->showsize = $config->showsize;
     $data->showtype = $config->showtype;
+    $data->filterfiles = $config->filterfiles;
 
     return resource_add_instance($data, null);
 }
-- 
1.7.9.5


From b43bb8da947c6c6e09e9b8564076ce4caa5b6b4e Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Mon, 2 Jul 2012 08:10:24 +0100
Subject: [PATCH 144/903] MDL-34107 Upload repository - do not add a dot to
 files without an extension

---
 repository/upload/lib.php |   23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/repository/upload/lib.php b/repository/upload/lib.php
index 7420230..5b443a5 100644
--- a/repository/upload/lib.php
+++ b/repository/upload/lib.php
@@ -155,17 +155,22 @@ class repository_upload extends repository {
             $ext = '';
             $match = array();
             $filename = clean_param($_FILES[$elname]['name'], PARAM_FILE);
-            if (preg_match('/\.([a-z0-9]+)$/i', $filename, $match)) {
-                if (isset($match[1])) {
-                    $ext = $match[1];
-                }
-            }
-            $ext = !empty($ext) ? $ext : '';
-            if (preg_match('#\.(' . $ext . ')$#i', $saveas_filename)) {
-                // saveas filename contains file extension already
+            if (strpos($filename, '.') === false) {
+                // File has no extension at all - do not add a dot.
                 $record->filename = $saveas_filename;
             } else {
-                $record->filename = $saveas_filename . '.' . $ext;
+                if (preg_match('/\.([a-z0-9]+)$/i', $filename, $match)) {
+                    if (isset($match[1])) {
+                        $ext = $match[1];
+                    }
+                }
+                $ext = !empty($ext) ? $ext : '';
+                if (preg_match('#\.(' . $ext . ')$#i', $saveas_filename)) {
+                    // saveas filename contains file extension already
+                    $record->filename = $saveas_filename;
+                } else {
+                    $record->filename = $saveas_filename . '.' . $ext;
+                }
             }
         }
 
-- 
1.7.9.5


From 2eb66f3500bf55c31003c2fc9af137c9ab337407 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 2 Jul 2012 15:12:17 +0800
Subject: [PATCH 145/903] MDL-34139 filemanager select-file dialogue should
 update file on Enter

---
 lib/form/filemanager.js |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index d81d5d9..164c683 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -736,6 +736,12 @@ M.form_filemanager.init = function(Y, options) {
                 e.preventDefault();
                 this.update_file();
             }, this);
+            selectnode.all('form').on('keydown', function(e) {
+                if (e.keyCode == 13) {
+                    e.preventDefault();
+                    this.update_file();
+                }
+            }, this);
             selectnode.one('.fp-file-download').on('click', function(e) {
                 e.preventDefault();
                 if (this.selectui.fileinfo.type != 'folder') {
-- 
1.7.9.5


From 68ea10b079d9228c6269bd9b68c68af33e1dcd36 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 4 Jul 2012 10:06:02 +0800
Subject: [PATCH 146/903] MDL-33444 Upload repository can specify custom label
 for filepicker

---
 repository/filepicker.js |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/repository/filepicker.js b/repository/filepicker.js
index 93e4490..d23f361 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -1625,6 +1625,9 @@ M.core_filepicker.init = function(Y, options) {
             });
             content.one('form').set('id', id);
             content.one('.fp-file input').set('name', 'repo_upload_file');
+            if (data.upload.label && content.one('.fp-file label')) {
+                content.one('.fp-file label').setContent(data.upload.label);
+            }
             content.one('.fp-saveas input').set('name', 'title');
             content.one('.fp-setauthor input').setAttrs({name:'author', value:this.options.author});
             content.one('.fp-setlicense select').set('name', 'license');
-- 
1.7.9.5


From 6b8399df5e8a24b27bd805176972914c809f1e33 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Fri, 6 Jul 2012 09:53:59 +1200
Subject: [PATCH 147/903] MDL-34198 SCORM remove unecessary get_records call

---
 mod/scorm/report/interactions/report.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/mod/scorm/report/interactions/report.php b/mod/scorm/report/interactions/report.php
index d9152d1..b251127 100644
--- a/mod/scorm/report/interactions/report.php
+++ b/mod/scorm/report/interactions/report.php
@@ -183,7 +183,6 @@ class scorm_interactions_report extends scorm_default_report {
             $countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, ';
             $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
             $countsql .= $from.$where;
-            $attempts = $DB->get_records_sql($select.$from.$where, $params);
             $questioncount = get_scorm_question_count($scorm->id);
             $nbmaincolumns = count($columns);
             for($id = 0; $id < $questioncount; $id++) {
-- 
1.7.9.5


From eb88700a563604c8c15354e5a07df6f5af0abc31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Tue, 3 Jul 2012 13:29:01 +0200
Subject: [PATCH 148/903] MDL-34155 use course visibility default when creator
 does not have moodle/course:visibility

---
 course/edit_form.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/edit_form.php b/course/edit_form.php
index 19d1f98..dd3d4bd 100644
--- a/course/edit_form.php
+++ b/course/edit_form.php
@@ -229,7 +229,7 @@ class course_edit_form extends moodleform {
             if (!empty($course->id)) {
                 $mform->setConstant('visible', $course->visible);
             } else {
-                $mform->setConstant('visible', $category->visible);
+                $mform->setConstant('visible', $courseconfig->visible);
             }
         }
 
-- 
1.7.9.5


From c82d7fc832d9ef4b0f2a6b1bba77049414b9c358 Mon Sep 17 00:00:00 2001
From: Michael Aherne <michael.aherne@strath.ac.uk>
Date: Tue, 3 Jul 2012 12:05:05 +0100
Subject: [PATCH 149/903] MDL-34156 Remove subselect from slow query

---
 enrol/meta/locallib.php |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/enrol/meta/locallib.php b/enrol/meta/locallib.php
index 454c974..fa3125c 100644
--- a/enrol/meta/locallib.php
+++ b/enrol/meta/locallib.php
@@ -477,11 +477,10 @@ function enrol_meta_sync($courseid = NULL, $verbose = false) {
     $sql = "SELECT ue.*
               FROM {user_enrolments} ue
               JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
-         LEFT JOIN (SELECT xpue.userid, xpe.courseid
-                      FROM {user_enrolments} xpue
+         LEFT JOIN ({user_enrolments} xpue
                       JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
-                   ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
-             WHERE pue.userid IS NULL";
+                   ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid)
+             WHERE xpue.userid IS NULL";
     $rs = $DB->get_recordset_sql($sql, $params);
     foreach($rs as $ue) {
         if (!isset($instances[$ue->enrolid])) {
-- 
1.7.9.5


From c8b70884634499a0462f6edfd839bc3d605b4192 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Thu, 21 Jun 2012 09:58:45 +0200
Subject: [PATCH 150/903] MDL-33887 delay string fetching in
 PAGE->requires->string_for_js() till page footer

This should resolve problems with language switching such as when forcing course language.
---
 lib/outputrequirementslib.php            |   25 +++++++++++----
 lib/tests/outputrequirementslib_test.php |   49 ++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 6 deletions(-)
 create mode 100644 lib/tests/outputrequirementslib_test.php

diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php
index 5329958..e438abf 100644
--- a/lib/outputrequirementslib.php
+++ b/lib/outputrequirementslib.php
@@ -64,6 +64,11 @@ class page_requirements_manager {
     protected $stringsforjs = array();
 
     /**
+     * @var array List of get_string $a parameters - used for validation only.
+     */
+    protected $stringsforjs_as = array();
+
+    /**
      * @var array List of JS variables to be initialised
      */
     protected $jsinitvariables = array('head'=>array(), 'footer'=>array());
@@ -867,15 +872,17 @@ class page_requirements_manager {
      * @param mixed $a any extra data to add into the string (optional).
      */
     public function string_for_js($identifier, $component, $a = NULL) {
-        $string = get_string($identifier, $component, $a);
         if (!$component) {
-            throw new coding_exception('The $module parameter is required for page_requirements_manager::string_for_js.');
+            throw new coding_exception('The $component parameter is required for page_requirements_manager::string_for_js().');
         }
-        if (isset($this->stringsforjs[$component][$identifier]) && $this->stringsforjs[$component][$identifier] !== $string) {
+        if (isset($this->stringsforjs_as[$component][$identifier]) and $this->stringsforjs_as[$component][$identifier] !== $a) {
             throw new coding_exception("Attempt to re-define already required string '$identifier' " .
-                    "from lang file '$component'. Did you already ask for it with a different \$a? {$this->stringsforjs[$component][$identifier]} !== $string");
+                    "from lang file '$component' with different \$a parameter?");
+        }
+        if (!isset($this->stringsforjs[$component][$identifier])) {
+            $this->stringsforjs[$component][$identifier] = new lang_string($identifier, $component, $a);
+            $this->stringsforjs_as[$component][$identifier] = $a;
         }
-        $this->stringsforjs[$component][$identifier] = $string;
     }
 
     /**
@@ -1218,7 +1225,13 @@ class page_requirements_manager {
 
         // add all needed strings
         if (!empty($this->stringsforjs)) {
-            $output .= html_writer::script(js_writer::set_variable('M.str', $this->stringsforjs));
+            $strings = array();
+            foreach ($this->stringsforjs as $component=>$v) {
+                foreach($v as $indentifier => $langstring) {
+                    $strings[$component][$indentifier] = $langstring->out();
+                }
+            }
+            $output .= html_writer::script(js_writer::set_variable('M.str', $strings));
         }
 
         // add variables
diff --git a/lib/tests/outputrequirementslib_test.php b/lib/tests/outputrequirementslib_test.php
new file mode 100644
index 0000000..b5b1b20
--- /dev/null
+++ b/lib/tests/outputrequirementslib_test.php
@@ -0,0 +1,49 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for lib/outputrequirementslibphp.
+ *
+ * @package   core
+ * @category  phpunit
+ * @copyright 2012 Petr Škoda
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/outputrequirementslib.php');
+
+
+class outputrequirements_test extends advanced_testcase {
+    public function test_string_for_js() {
+        $this->resetAfterTest();
+
+        $page = new moodle_page();
+        $page->requires->string_for_js('course', 'moodle', 1);
+        $page->requires->string_for_js('course', 'moodle', 1);
+        try {
+            $page->requires->string_for_js('course', 'moodle', 2);
+            $this->fail('Exception expected when the same string with different $a requested');
+        } catch (Exception $e) {
+            $this->assertInstanceOf('coding_exception', $e);
+        }
+
+        // Note: we can not switch languages in phpunit yet,
+        //       it would be nice to test that the strings are actually fetched in the footer.
+    }
+}
-- 
1.7.9.5


From 95896749a52c6d082dd99b8dc7bb80e1c8f6178b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Mon, 25 Jun 2012 09:31:50 +0200
Subject: [PATCH 151/903] MDL-33617 add new index to improve perf of enrol
 related role_assignments

Conflicts:

	version.php
---
 lib/db/install.xml |    3 ++-
 lib/db/upgrade.php |   15 +++++++++++++++
 version.php        |    2 +-
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/lib/db/install.xml b/lib/db/install.xml
index 1d88b4d..22835b2 100644
--- a/lib/db/install.xml
+++ b/lib/db/install.xml
@@ -1130,7 +1130,8 @@
       <INDEXES>
         <INDEX NAME="sortorder" UNIQUE="false" FIELDS="sortorder" NEXT="rolecontext"/>
         <INDEX NAME="rolecontext" UNIQUE="false" FIELDS="roleid, contextid" COMMENT="Index on roleid and contextid" PREVIOUS="sortorder" NEXT="usercontextrole"/>
-        <INDEX NAME="usercontextrole" UNIQUE="false" FIELDS="userid, contextid, roleid" COMMENT="Index on userid, contextid and roleid" PREVIOUS="rolecontext"/>
+        <INDEX NAME="usercontextrole" UNIQUE="false" FIELDS="userid, contextid, roleid" COMMENT="Index on userid, contextid and roleid" PREVIOUS="rolecontext" NEXT="component-itemid-userid"/>
+        <INDEX NAME="component-itemid-userid" UNIQUE="false" FIELDS="component, itemid, userid" PREVIOUS="usercontextrole"/>
       </INDEXES>
     </TABLE>
     <TABLE NAME="role_capabilities" COMMENT="permission has to be signed, overriding a capability for a particular role in a particular context" PREVIOUS="role_assignments" NEXT="role_names">
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index f50ae6b..75e165f 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -899,6 +899,21 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062500.02);
     }
 
+    if ($oldversion < 2012062501.01) {
+
+        // Define index component-itemid-userid (not unique) to be added to role_assignments
+        $table = new xmldb_table('role_assignments');
+        $index = new xmldb_index('component-itemid-userid', XMLDB_INDEX_NOTUNIQUE, array('component', 'itemid', 'userid'));
+
+        // Conditionally launch add index component-itemid-userid
+        if (!$dbman->index_exists($table, $index)) {
+            $dbman->add_index($table, $index);
+        }
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012062501.01);
+    }
+
 
     return true;
 }
diff --git a/version.php b/version.php
index e220f57..7a77285 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From b2e5a60773421119a87ced76a7aae443ba238db2 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 10 Jul 2012 12:58:46 +0800
Subject: [PATCH 152/903] MDL-34159 - add comment lost from previous commit

---
 lib/dml/moodle_database.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php
index b44b740..9531782 100644
--- a/lib/dml/moodle_database.php
+++ b/lib/dml/moodle_database.php
@@ -575,7 +575,7 @@ abstract class moodle_database {
      */
     protected function where_clause_list($field, array $values) {
         if (empty($values)) {
-            return array("1 = 2", array());
+            return array("1 = 2", array()); // Fake condition, won't return rows ever. MDL-17645
         }
 
         // Note: Do not use get_in_or_equal() because it can not deal with bools and nulls.
-- 
1.7.9.5


From 7073fa4c4af8fdd5c68866f156a9f8c031f7f5a2 Mon Sep 17 00:00:00 2001
From: Sun Zhigang <sunner@gmail.com>
Date: Sat, 2 Jul 2011 18:41:26 +0800
Subject: [PATCH 153/903] MDL-28155 mod_assignment - Fix an ugly hack

Show download all link for any assignment types which implement
the download_submissions() method
---
 mod/assignment/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index 8f8dcf3..d7115e6 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1591,7 +1591,7 @@ class assignment_base {
                     }
                     $currentposition++;
                 }
-                if ($hassubmission && ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle')) { //TODO: this is an ugly hack, where is the plugin spirit? (skodak)
+                if ($hassubmission && method_exists('assignment_'.$this->assignment->assignmenttype, 'download_submissions')) {
                     echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link'));
                     echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment'));
                     echo html_writer::end_tag('div');
-- 
1.7.9.5


From db8152585056317d5ec42b3e21b838d89c1ef9ad Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 28 Jun 2012 11:50:17 +0800
Subject: [PATCH 154/903] MDL-33950 check if source file is accessible in
 repository_ajax.php

- repository::copy_to_area() does not check access any more, and repository_recent::copy_to_area() is unnecessary
- added repository::file_is_accessible() that checks access to the picked file (regardless of accessibility of the file it is referencing to)
---
 repository/lib.php             |   83 +++++++++++++++++++----------------
 repository/recent/lib.php      |   93 ++++++----------------------------------
 repository/repository_ajax.php |   11 ++++-
 3 files changed, 66 insertions(+), 121 deletions(-)

diff --git a/repository/lib.php b/repository/lib.php
index 6231209..0886ccb 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -651,45 +651,60 @@ abstract class repository {
      * @return stored_file|null
      */
     public static function get_moodle_file($source) {
-        $params = unserialize(base64_decode($source));
-        if (empty($params) || !is_array($params)) {
-            return null;
-        }
-        foreach (array('contextid', 'itemid', 'filename', 'filepath', 'component') as $key) {
-            if (!array_key_exists($key, $params)) {
-                return null;
+        $params = file_storage::unpack_reference($source, true);
+        $fs = get_file_storage();
+        return $fs->get_file($params['contextid'], $params['component'], $params['filearea'],
+                    $params['itemid'], $params['filepath'], $params['filename']);
+    }
+
+    /**
+     * Repository method to make sure that user can access particular file.
+     *
+     * This is checked when user tries to pick the file from repository to deal with
+     * potential parameter substitutions is request
+     *
+     * @param string $source
+     * @return bool whether the file is accessible by current user
+     */
+    public function file_is_accessible($source) {
+        if ($this->has_moodle_files()) {
+            try {
+                $params = file_storage::unpack_reference($source, true);
+            } catch (file_reference_exception $e) {
+                return false;
             }
+            $browser = get_file_browser();
+            $context = get_context_instance_by_id($params['contextid']);
+            $file_info = $browser->get_file_info($context, $params['component'], $params['filearea'],
+                    $params['itemid'], $params['filepath'], $params['filename']);
+            return !empty($file_info);
         }
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $component  = clean_param($params['component'], PARAM_COMPONENT);
-        $filearea   = clean_param($params['filearea'],  PARAM_AREA);
-        $itemid     = clean_param($params['itemid'],    PARAM_INT);
-        $filepath   = clean_param($params['filepath'],  PARAM_PATH);
-        $filename   = clean_param($params['filename'],  PARAM_FILE);
-        $fs = get_file_storage();
-        return $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename);
+        return true;
     }
 
     /**
-     * This function is used to copy a moodle file to draft area
+     * This function is used to copy a moodle file to draft area.
+     *
+     * It DOES NOT check if the user is allowed to access this file because the actual file
+     * can be located in the area where user does not have access to but there is an alias
+     * to this file in the area where user CAN access it.
+     * {@link file_is_accessible} should be called for alias location before calling this function.
      *
-     * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
+     * @param string $source The metainfo of file, it is base64 encoded php serialized data
      * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
      *      attributes of the new file
      * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
      *      the limit, the file_exception is thrown.
-     * @return array The information of file
+     * @return array The information about the created file
      */
-    public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
+    public function copy_to_area($source, $filerecord, $maxbytes = -1) {
         global $USER;
         $fs = get_file_storage();
-        $browser = get_file_browser();
 
         if ($this->has_moodle_files() == false) {
             throw new coding_exception('Only repository used to browse moodle files can use repository::copy_to_area()');
         }
 
-        $params = unserialize(base64_decode($encoded));
         $user_context = context_user::instance($USER->id);
 
         $filerecord = (array)$filerecord;
@@ -701,17 +716,9 @@ abstract class repository {
         $new_filepath = $filerecord['filepath'];
         $new_filename = $filerecord['filename'];
 
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'],    PARAM_INT);
-        $filename   = clean_param($params['filename'],  PARAM_FILE);
-        $filepath   = clean_param($params['filepath'],  PARAM_PATH);;
-        $filearea   = clean_param($params['filearea'],  PARAM_AREA);
-        $component  = clean_param($params['component'], PARAM_COMPONENT);
-
-        $context    = get_context_instance_by_id($contextid);
         // the file needs to copied to draft area
-        $file_info  = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
-        if ($maxbytes !== -1 && $file_info->get_filesize() > $maxbytes) {
+        $stored_file = self::get_moodle_file($source);
+        if ($maxbytes != -1 && $stored_file->get_filesize() > $maxbytes) {
             throw new file_exception('maxbytes');
         }
 
@@ -719,7 +726,7 @@ abstract class repository {
             // create new file
             $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
             $filerecord['filename'] = $unused_filename;
-            $file_info->copy_to_storage($filerecord);
+            $fs->create_file_from_storedfile($filerecord, $stored_file);
             $event = array();
             $event['event'] = 'fileexists';
             $event['newfile'] = new stdClass;
@@ -729,17 +736,17 @@ abstract class repository {
             $event['existingfile'] = new stdClass;
             $event['existingfile']->filepath = $new_filepath;
             $event['existingfile']->filename = $new_filename;
-            $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
+            $event['existingfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();
             return $event;
         } else {
-            $file_info->copy_to_storage($filerecord);
+            $fs->create_file_from_storedfile($filerecord, $stored_file);
             $info = array();
             $info['itemid'] = $draftitemid;
-            $info['file']  = $new_filename;
-            $info['title']  = $new_filename;
+            $info['file'] = $new_filename;
+            $info['title'] = $new_filename;
             $info['contextid'] = $user_context->id;
-            $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
-            $info['filesize'] = $file_info->get_filesize();
+            $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();
+            $info['filesize'] = $stored_file->get_filesize();
             return $info;
         }
     }
diff --git a/repository/recent/lib.php b/repository/recent/lib.php
index 2c1acf2..f1265c8 100644
--- a/repository/recent/lib.php
+++ b/repository/recent/lib.php
@@ -177,91 +177,22 @@ class repository_recent extends repository {
     public function supported_returntypes() {
         return FILE_INTERNAL;
     }
+
     /**
-     * This function overwrite the default implement to copying file using file_storage
+     * Repository method to make sure that user can access particular file.
+     *
+     * This is checked when user tries to pick the file from repository to deal with
+     * potential parameter substitutions is request
      *
-     * @param string $encoded The information of file, it is base64 encoded php serialized data
-     * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
-     *      attributes of the new file
-     * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
-     *      the limit, the file_exception is thrown.
-     * @return array The information of file
+     * @todo MDL-33805 remove this function when recent files are managed correctly
+     *
+     * @param string $source
+     * @return bool whether the file is accessible by current user
      */
-    public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
+    public function file_is_accessible($source) {
         global $USER;
-
-        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
-
-        $filerecord = (array)$filerecord;
-        // make sure the new file will be created in user draft area
-        $filerecord['component'] = 'user'; // make sure
-        $filerecord['filearea'] = 'draft'; // make sure
-        $filerecord['contextid'] = $user_context->id;
-        $filerecord['sortorder'] = 0;
-        $draftitemid = $filerecord['itemid'];
-        $new_filepath = $filerecord['filepath'];
-        $new_filename = $filerecord['filename'];
-
-        $fs = get_file_storage();
-
-        $params = unserialize(base64_decode($encoded));
-
-        $contextid  = clean_param($params['contextid'], PARAM_INT);
-        $fileitemid = clean_param($params['itemid'],    PARAM_INT);
-        $filename   = clean_param($params['filename'],  PARAM_FILE);
-        $filepath   = clean_param($params['filepath'],  PARAM_PATH);;
-        $filearea   = clean_param($params['filearea'],  PARAM_AREA);
-        $component  = clean_param($params['component'], PARAM_COMPONENT);
-
-        // XXX:
-        // When user try to pick a file from other filearea, normally file api will use file browse to
-        // operate the files with capability check, but in some areas, users don't have permission to
-        // browse the files (for example, forum_attachment area).
-        //
-        // To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
-        // capability check, we will use a better workaround to improve it.
-        // TODO MDL-33297 apply here
-        if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
-            // verify user id
-            if ($USER->id != $stored_file->get_userid()) {
-                throw new moodle_exception('errornotyourfile', 'repository');
-            }
-            if ($maxbytes !== -1 && $stored_file->get_filesize() > $maxbytes) {
-                throw new file_exception('maxbytes');
-            }
-
-            // test if file already exists
-            if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
-                // create new file
-                $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
-                $filerecord['filename'] = $unused_filename;
-                // create a tmp file
-                $fs->create_file_from_storedfile($filerecord, $stored_file);
-                $event = array();
-                $event['event'] = 'fileexists';
-                $event['newfile'] = new stdClass;
-                $event['newfile']->filepath = $new_filepath;
-                $event['newfile']->filename = $unused_filename;
-                $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out();
-                $event['existingfile'] = new stdClass;
-                $event['existingfile']->filepath = $new_filepath;
-                $event['existingfile']->filename = $new_filename;
-                $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
-                return $event;
-            } else {
-                $fs->create_file_from_storedfile($filerecord, $stored_file);
-                $info = array();
-                $info['title']  = $new_filename;
-                $info['file']  = $new_filename;
-                $info['itemid'] = $draftitemid;
-                $info['filesize']  = $stored_file->get_filesize();
-                $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
-                $info['contextid'] = $user_context->id;
-                return $info;
-            }
-        }
-        return false;
-
+        $file = self::get_moodle_file($source);
+        return (!empty($file) && $file->get_userid() == $USER->id);
     }
 
     /**
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index c9863c4..488ff2f 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -232,7 +232,14 @@ switch ($action) {
             $record->userid = $USER->id;
             $record->sortorder = 0;
 
+            // Check that user has permission to access this file
+            if (!$repo->file_is_accessible($source)) {
+                throw new file_exception('storedfilecannotread');
+            }
+
             // If file is already a reference, set $source = file source, $repo = file repository
+            // note that in this case user may not have permission to access the source file directly
+            // so no file_browser/file_info can be used below
             if ($repo->has_moodle_files()) {
                 $file = repository::get_moodle_file($source);
                 if ($file && $file->is_external_file()) {
@@ -298,13 +305,13 @@ switch ($action) {
             } else {
                 // Download file to moodle.
                 $downloadedfile = $repo->get_file($source, $saveas_filename);
-                if ($downloadedfile['path'] === false) {
+                if (empty($downloadedfile['path'])) {
                     $err->error = get_string('cannotdownload', 'repository');
                     die(json_encode($err));
                 }
 
                 // Check if exceed maxbytes.
-                if (($maxbytes!==-1) && (filesize($downloadedfile['path']) > $maxbytes)) {
+                if ($maxbytes != -1 && filesize($downloadedfile['path']) > $maxbytes) {
                     throw new file_exception('maxbytes');
                 }
 
-- 
1.7.9.5


From 95991122ab7c24ea6cf5db9f5b9f05f4c74255cd Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 28 Jun 2012 11:34:31 +0800
Subject: [PATCH 155/903] MDL-33473,MDL-33950,MDL-33837 Allow non-js
 filepicker to pick files from moodle repositories

- MDL-33473 actually make non-js filepicker to work with local repositories
- MDL-33950 validate that file is accessible
- MDL-33837 when picking a server file marked as main, do not make it main in current filearea
---
 repository/filepicker.php |   87 +++++++++++++++++++++++++++++----------------
 1 file changed, 56 insertions(+), 31 deletions(-)

diff --git a/repository/filepicker.php b/repository/filepicker.php
index 20b67ca..cfa2667 100644
--- a/repository/filepicker.php
+++ b/repository/filepicker.php
@@ -285,40 +285,65 @@ case 'sign':
     break;
 
 case 'download':
-    $thefile = $repo->get_file($fileurl, $filename);
-    $filesize = filesize($thefile['path']);
-    if (($maxbytes!=-1) && ($filesize>$maxbytes)) {
-        print_error('maxbytes');
+    // Check that user has permission to access this file
+    if (!$repo->file_is_accessible($fileurl)) {
+        print_error('storedfilecannotread');
     }
-    if (!empty($thefile)) {
-        $record = new stdClass();
-        $record->filepath = $savepath;
-        $record->filename = $filename;
-        $record->component = 'user';
-        $record->filearea = 'draft';
-        $record->itemid   = $itemid;
-        $record->license  = '';
-        $record->author   = '';
-
-        $now = time();
-        $record->timecreated  = $now;
-        $record->timemodified = $now;
-        $record->userid       = $USER->id;
-        $record->contextid = $user_context->id;
-
-        $sourcefield = $repo->get_file_source_info($thefile['url']);
-        $record->source = repository::build_source_field($sourcefield);
-        try {
-            $info = repository::move_to_filepool($thefile['path'], $record);
-            redirect($home_url, get_string('downloadsucc', 'repository'));
-        } catch (moodle_exception $e) {
-            // inject target URL
-            $e->link = $PAGE->url->out();
-            echo $OUTPUT->header(); // hack: we need the embedded header here, standard error printing would not use it
-            throw $e;
+
+    // If file is already a reference, set $fileurl = file source, $repo = file repository
+    // note that in this case user may not have permission to access the source file directly
+    // so no file_browser/file_info can be used below
+    if ($repo->has_moodle_files()) {
+        $file = repository::get_moodle_file($fileurl);
+        if ($file && $file->is_external_file()) {
+            $fileurl = $file->get_reference();
+            $repo_id = $file->get_repository_id();
+            $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
         }
+    }
+
+    $record = new stdClass();
+    $record->filepath = $savepath;
+    $record->filename = $filename;
+    $record->component = 'user';
+    $record->filearea = 'draft';
+    $record->itemid   = $itemid;
+    $record->license  = '';
+    $record->author   = '';
+
+    $now = time();
+    $record->timecreated  = $now;
+    $record->timemodified = $now;
+    $record->userid       = $USER->id;
+    $record->contextid = $user_context->id;
+    $record->sortorder = 0;
+
+    $sourcefield = $repo->get_file_source_info($fileurl);
+    $record->source = repository::build_source_field($sourcefield);
+
+    if ($repo->has_moodle_files()) {
+        $fileinfo = $repo->copy_to_area($fileurl, $record, $maxbytes);
+        redirect($home_url, get_string('downloadsucc', 'repository'));
     } else {
-        print_error('cannotdownload', 'repository');
+        $thefile = $repo->get_file($fileurl, $filename);
+        if (!empty($thefile['path'])) {
+            $filesize = filesize($thefile['path']);
+            if ($maxbytes != -1 && $filesize>$maxbytes) {
+                unlink($thefile['path']);
+                print_error('maxbytes');
+            }
+            try {
+                $info = repository::move_to_filepool($thefile['path'], $record);
+                redirect($home_url, get_string('downloadsucc', 'repository'));
+            } catch (moodle_exception $e) {
+                // inject target URL
+                $e->link = $PAGE->url->out();
+                echo $OUTPUT->header(); // hack: we need the embedded header here, standard error printing would not use it
+                throw $e;
+            }
+        } else {
+            print_error('cannotdownload', 'repository');
+        }
     }
 
     break;
-- 
1.7.9.5


From d6571ad763484ab9764275ad79d0f9362376a6cf Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 3 Jul 2012 11:52:25 +0800
Subject: [PATCH 156/903] MDL-33950 Correctly initialise repository and check
 access in js and non-js filepicker

---
 repository/filepicker.php      |   27 +++++++++++----------------
 repository/lib.php             |   28 +++++++++++++++++-----------
 repository/repository_ajax.php |   30 ++++++------------------------
 3 files changed, 34 insertions(+), 51 deletions(-)

diff --git a/repository/filepicker.php b/repository/filepicker.php
index cfa2667..73970d6 100644
--- a/repository/filepicker.php
+++ b/repository/filepicker.php
@@ -59,6 +59,7 @@ $search_text = optional_param('s', '',             PARAM_CLEANHTML);
 $maxfiles    = optional_param('maxfiles', -1,      PARAM_INT);    // maxfiles
 $maxbytes    = optional_param('maxbytes',  0,      PARAM_INT);    // maxbytes
 $subdirs     = optional_param('subdirs',  0,       PARAM_INT);    // maxbytes
+$accepted_types = optional_param_array('accepted_types', '*', PARAM_RAW);
 
 // the path to save files
 $savepath = optional_param('savepath', '/',    PARAM_PATH);
@@ -75,22 +76,16 @@ if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
 }
 $PAGE->set_course($course);
 
-// init repository plugin
-$sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instances} i '.
-       'WHERE i.id=? AND i.typeid=r.id';
-if ($repository = $DB->get_record_sql($sql, array($repo_id))) {
-    $type = $repository->type;
-    if (file_exists($CFG->dirroot.'/repository/'.$type.'/lib.php')) {
-        require_once($CFG->dirroot.'/repository/'.$type.'/lib.php');
-        $classname = 'repository_' . $type;
-        try {
-            $repo = new $classname($repo_id, $contextid, array('ajax'=>false, 'name'=>$repository->name, 'type'=>$type));
-        } catch (repository_exception $e){
-            print_error('pluginerror', 'repository');
-        }
-    } else {
-        print_error('invalidplugin', 'repository');
-    }
+if ($repo_id) {
+    // Get repository instance information
+    $repooptions = array(
+        'ajax' => false,
+        'mimetypes' => $accepted_types
+    );
+    $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
+
+    // Check permissions
+    $repo->check_capability();
 }
 
 $context = context::instance_by_id($contextid);
diff --git a/repository/lib.php b/repository/lib.php
index 0886ccb..c34dec7 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -521,9 +521,10 @@ abstract class repository {
      *
      * @param int $repositoryid repository ID
      * @param stdClass|int $context context instance or context ID
+     * @param array $options additional repository options
      * @return repository
      */
-    public static function get_repository_by_id($repositoryid, $context) {
+    public static function get_repository_by_id($repositoryid, $context, $options = array()) {
         global $CFG, $DB;
 
         $sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instances} i WHERE i.id=? AND i.typeid=r.id';
@@ -539,10 +540,15 @@ abstract class repository {
                 if (is_object($context)) {
                     $contextid = $context->id;
                 }
-                $repository = new $classname($repositoryid, $contextid, array('type'=>$type));
+                $options['type'] = $type;
+                $options['typeid'] = $record->typeid;
+                if (empty($options['name'])) {
+                    $options['name'] = $record->name;
+                }
+                $repository = new $classname($repositoryid, $contextid, $options);
                 return $repository;
             } else {
-                throw new moodle_exception('error');
+                throw new repository_exception('invalidplugin', 'repository');
             }
         }
     }
@@ -609,16 +615,16 @@ abstract class repository {
     }
 
     /**
-     * To check if the context id is valid
+     * Checks if user has a capability to view the current repository in current context
      *
-     * @static
-     * @param int $contextid
-     * @param stdClass $instance
      * @return bool
      */
-    public static function check_capability($contextid, $instance) {
-        $context = get_context_instance_by_id($contextid);
-        $capability = has_capability('repository/'.$instance->type.':view', $context);
+    public final function check_capability() {
+        $capability = false;
+        if (preg_match("/^repository_(.*)$/", get_class($this), $matches)) {
+            $type = $matches[1];
+            $capability = has_capability('repository/'.$type.':view', $this->context);
+        }
         if (!$capability) {
             throw new repository_exception('nopermissiontoaccess', 'repository');
         }
@@ -674,7 +680,7 @@ abstract class repository {
                 return false;
             }
             $browser = get_file_browser();
-            $context = get_context_instance_by_id($params['contextid']);
+            $context = context::instance_by_id($params['contextid']);
             $file_info = $browser->get_file_info($context, $params['component'], $params['filearea'],
                     $params['itemid'], $params['filepath'], $params['filename']);
             return !empty($file_info);
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index 488ff2f..2452158 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -70,17 +70,14 @@ if (!confirm_sesskey()) {
 }
 
 // Get repository instance information
-$sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instances} i WHERE i.id=? AND i.typeid=r.id';
-
-if (!$repository = $DB->get_record_sql($sql, array($repo_id))) {
-    $err->error = get_string('invalidrepositoryid', 'repository');
-    die(json_encode($err));
-} else {
-    $type = $repository->type;
-}
+$repooptions = array(
+    'ajax' => true,
+    'mimetypes' => $accepted_types
+);
+$repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
 
 // Check permissions
-repository::check_capability($contextid, $repository);
+$repo->check_capability();
 
 $moodle_maxbytes = get_user_max_upload_file_size($context);
 // to prevent maxbytes greater than moodle maxbytes setting
@@ -121,21 +118,6 @@ switch ($action) {
         break;
 }
 
-if (file_exists($CFG->dirroot.'/repository/'.$type.'/lib.php')) {
-    require_once($CFG->dirroot.'/repository/'.$type.'/lib.php');
-    $classname = 'repository_' . $type;
-    $repooptions = array(
-        'ajax' => true,
-        'name' => $repository->name,
-        'type' => $type,
-        'mimetypes' => $accepted_types
-    );
-    $repo = new $classname($repo_id, $contextid, $repooptions);
-} else {
-    $err->error = get_string('invalidplugin', 'repository', $type);
-    die(json_encode($err));
-}
-
 // These actions all occur on the currently active repository instance
 switch ($action) {
     case 'sign':
-- 
1.7.9.5


From 229aabf7c6b25ec4f63339a5bf0d0ae9549a0925 Mon Sep 17 00:00:00 2001
From: Petr Skoda <commits@skodak.org>
Date: Fri, 15 Jun 2012 10:37:12 +0200
Subject: [PATCH 157/903] MDL-33712 add support for unique moodle tags in
 tinymce

---
 lib/editor/tinymce/lib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/editor/tinymce/lib.php b/lib/editor/tinymce/lib.php
index 01537e9..10753a9 100644
--- a/lib/editor/tinymce/lib.php
+++ b/lib/editor/tinymce/lib.php
@@ -178,6 +178,9 @@ class tinymce_texteditor extends texteditor {
             $params['valid_elements'] = 'script[src|type],*[*]'; // for some reason the *[*] does not inlcude javascript src attribute MDL-25836
             $params['invalid_elements'] = '';
         }
+        // Add unique moodle elements - unfortunately we have to decide if these are SPANs or DIVs.
+        $params['extended_valid_elements'] = 'nolink,tex,algebra,lang[lang]';
+        $params['custom_elements'] = 'nolink,~tex,~algebra,lang';
 
         if (empty($options['legacy'])) {
             if (isset($options['maxfiles']) and $options['maxfiles'] != 0) {
-- 
1.7.9.5


From 89375aac4c2ef2126bc7f282c34f7e5bd0b04b4f Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 10 Jul 2012 20:33:18 +0200
Subject: [PATCH 158/903] Automatically generated installer lang files

---
 install/lang/ca/error.php      |    4 ++--
 install/lang/ca/install.php    |    2 ++
 install/lang/es_mx/moodle.php  |   36 ++++++++++++++++++++++++++++++++++
 install/lang/ga/langconfig.php |    2 +-
 install/lang/id/admin.php      |   42 ++++++++++++++++++++++++++++++++++++++++
 install/lang/id/moodle.php     |    1 +
 install/lang/ja/langconfig.php |    2 +-
 install/lang/sv_fi/moodle.php  |   34 ++++++++++++++++++++++++++++++++
 8 files changed, 119 insertions(+), 4 deletions(-)
 create mode 100644 install/lang/es_mx/moodle.php
 create mode 100644 install/lang/id/admin.php
 create mode 100644 install/lang/sv_fi/moodle.php

diff --git a/install/lang/ca/error.php b/install/lang/ca/error.php
index e8c7b55..e1de235 100644
--- a/install/lang/ca/error.php
+++ b/install/lang/ca/error.php
@@ -34,12 +34,12 @@ $string['cannotcreatelangdir'] = 'No s\'ha pogut crear el directori d\'idiomes.'
 $string['cannotcreatetempdir'] = 'No s\'ha pogut crear el directori temporal';
 $string['cannotdownloadcomponents'] = 'No s\'han pogut baixar components';
 $string['cannotdownloadzipfile'] = 'No s\'ha pogut baixar el fitxer zip';
-$string['cannotfindcomponent'] = 'No s\'ha pogut trobar un component';
+$string['cannotfindcomponent'] = 'No s\'ha pogut trobar el component';
 $string['cannotsavemd5file'] = 'No s\'ha pogut desar el fitxer md5';
 $string['cannotsavezipfile'] = 'No s\'ha pogut desar el fitxer zip';
 $string['cannotunzipfile'] = 'No s\'ha pogut descomprimir el fitxer';
 $string['componentisuptodate'] = 'El component està al dia';
-$string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer baixat.';
+$string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer baixat';
 $string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu-ho a provar';
 $string['missingrequiredfield'] = 'Falta algun camp necessari';
 $string['remotedownloaderror'] = 'No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres de servidor intermediari. Es recomana l\'extensió cURL.<br /><br />Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació "{$a->dest}" del vostre servidor i descomprimir-lo allí.';
diff --git a/install/lang/ca/install.php b/install/lang/ca/install.php
index 2b15652..be65a17 100644
--- a/install/lang/ca/install.php
+++ b/install/lang/ca/install.php
@@ -34,6 +34,8 @@ $string['admindirname'] = 'Directori d\'administració';
 $string['availablelangs'] = 'Llista d\'idiomes disponibles';
 $string['chooselanguagehead'] = 'Trieu un idioma';
 $string['chooselanguagesub'] = 'Trieu un idioma NOMÉS per a la instal·lació. En una pantalla posterior podreu triar idiomes per al lloc i per als usuaris.';
+$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir dmin/cli/install_database.php si voleu instal·lar aquest lloc web.';
+$string['clialreadyinstalled'] = 'El fitxer config.php ja existeix, feu servir admin/cli/upgrade.php si voleu actualitzar aquest lloc web.';
 $string['databasehost'] = 'Servidor de base de dades:';
 $string['databasename'] = 'Nom de la base de dades:';
 $string['dataroot'] = 'Directori de dades';
diff --git a/install/lang/es_mx/moodle.php b/install/lang/es_mx/moodle.php
new file mode 100644
index 0000000..2b6d46e
--- /dev/null
+++ b/install/lang/es_mx/moodle.php
@@ -0,0 +1,36 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Idioma';
+$string['next'] = 'Siguiente';
+$string['previous'] = 'Anterior';
+$string['reload'] = 'Recargar';
diff --git a/install/lang/ga/langconfig.php b/install/lang/ga/langconfig.php
index 9cea86c..cd9ab38 100644
--- a/install/lang/ga/langconfig.php
+++ b/install/lang/ga/langconfig.php
@@ -32,4 +32,4 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
-$string['thislanguage'] = 'Gaeilge';
+$string['thislanguage'] = 'Béarla';
diff --git a/install/lang/id/admin.php b/install/lang/id/admin.php
new file mode 100644
index 0000000..63281c9
--- /dev/null
+++ b/install/lang/id/admin.php
@@ -0,0 +1,42 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 'T';
+$string['cliansweryes'] = 'Y';
+$string['cliincorrectvalueerror'] = 'Error, nilai yang salah "{$a->value}" untuk opsi "{$a->option}"';
+$string['cliincorrectvalueretry'] = 'Nilai input salah, silahkan coba lagi';
+$string['clitypevalue'] = 'tipe nilai';
+$string['clitypevaluedefault'] = 'tipe nilai, tekan enter untuk menggunakan nilai default ({$a})';
+$string['cliunknowoption'] = 'Opsi tidak dikenali :
+ {$a}
+Silahkan gunakan opsi --help';
+$string['cliyesnoprompt'] = 'ketik y (Ya) atau t (Tidak)';
diff --git a/install/lang/id/moodle.php b/install/lang/id/moodle.php
index 81eb64b..e7db667 100644
--- a/install/lang/id/moodle.php
+++ b/install/lang/id/moodle.php
@@ -33,3 +33,4 @@ defined('MOODLE_INTERNAL') || die();
 $string['language'] = 'Bahasa';
 $string['next'] = 'Selanjutnya';
 $string['previous'] = 'Sebelumnya';
+$string['reload'] = 'Muat ulang';
diff --git a/install/lang/ja/langconfig.php b/install/lang/ja/langconfig.php
index a0245d5..eb70f69 100644
--- a/install/lang/ja/langconfig.php
+++ b/install/lang/ja/langconfig.php
@@ -30,6 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['parentlanguage'] = 'en';
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = '日本語';
diff --git a/install/lang/sv_fi/moodle.php b/install/lang/sv_fi/moodle.php
new file mode 100644
index 0000000..48a4a3a
--- /dev/null
+++ b/install/lang/sv_fi/moodle.php
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['previous'] = 'Föregående';
+$string['reload'] = 'Ladda om';
-- 
1.7.9.5


From df7799d989ed18be0ce98f90a788e2643069f81e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 11 Jul 2012 08:47:26 +0200
Subject: [PATCH 159/903] MDL-34175 one more hardcoded /admin/ in mnet

---
 admin/mnet/peers.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/admin/mnet/peers.php b/admin/mnet/peers.php
index 4d402ed..e7c1daf 100644
--- a/admin/mnet/peers.php
+++ b/admin/mnet/peers.php
@@ -30,7 +30,7 @@
 require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
 require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->dirroot.'/mnet/lib.php');
-require_once($CFG->dirroot.'/admin/mnet/peer_forms.php');
+require_once($CFG->dirroot.'/'.$CFG->admin.'/mnet/peer_forms.php');
 
 require_login();
 
-- 
1.7.9.5


From c465776d28c04b99374838c73a59ec099f0d26d7 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Wed, 11 Jul 2012 15:10:17 +0800
Subject: [PATCH 160/903] MDL-28155 mod_assignment Using the this object
 instead of a string

---
 mod/assignment/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index d7115e6..eea2714 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1591,7 +1591,7 @@ class assignment_base {
                     }
                     $currentposition++;
                 }
-                if ($hassubmission && method_exists('assignment_'.$this->assignment->assignmenttype, 'download_submissions')) {
+                if ($hassubmission && method_exists($this, 'download_submissions')) {
                     echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link'));
                     echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment'));
                     echo html_writer::end_tag('div');
-- 
1.7.9.5


From 294c22827292a4fac11f764eecfc86d84680c05c Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 12 Jul 2012 00:32:25 +0000
Subject: [PATCH 161/903] Automatically generated installer lang files

---
 install/lang/ca/install.php    |   27 +++++++++---
 install/lang/pt/admin.php      |   12 +++---
 install/lang/pt/error.php      |   26 ++++++------
 install/lang/pt/install.php    |   92 +++++++++++++++-------------------------
 install/lang/pt/langconfig.php |    1 +
 install/lang/pt/moodle.php     |    4 +-
 6 files changed, 77 insertions(+), 85 deletions(-)

diff --git a/install/lang/ca/install.php b/install/lang/ca/install.php
index be65a17..940d880 100644
--- a/install/lang/ca/install.php
+++ b/install/lang/ca/install.php
@@ -33,18 +33,23 @@ defined('MOODLE_INTERNAL') || die();
 $string['admindirname'] = 'Directori d\'administració';
 $string['availablelangs'] = 'Llista d\'idiomes disponibles';
 $string['chooselanguagehead'] = 'Trieu un idioma';
-$string['chooselanguagesub'] = 'Trieu un idioma NOMÉS per a la instal·lació. En una pantalla posterior podreu triar idiomes per al lloc i per als usuaris.';
+$string['chooselanguagesub'] = 'Trieu un idioma per a la instal·lació. S\'utilitzarà també com a idioma per defecte del lloc, tot i que després podeu canviar-lo.';
 $string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir dmin/cli/install_database.php si voleu instal·lar aquest lloc web.';
 $string['clialreadyinstalled'] = 'El fitxer config.php ja existeix, feu servir admin/cli/upgrade.php si voleu actualitzar aquest lloc web.';
+$string['cliinstallheader'] = 'Programa d\'instal·lació de línia d\'ordres de Moodle {$a}';
 $string['databasehost'] = 'Servidor de base de dades:';
 $string['databasename'] = 'Nom de la base de dades:';
+$string['databasetypehead'] = 'Trieu el controlador de la base de dades';
 $string['dataroot'] = 'Directori de dades';
+$string['datarootpermission'] = 'Permisos dels directoris de dades';
 $string['dbprefix'] = 'Prefix de taules';
 $string['dirroot'] = 'Directori de Moodle';
 $string['environmenthead'] = 'S\'està comprovant el vostre entorn';
-$string['errorsinenvironment'] = 'Hi ha errors en l\'entorn.';
+$string['environmentsub2'] = 'Cada versió de Moodle té uns requeriments mínims de versió de PHP i un nombre d\'extensions de PHP necessàries.
+Abans de cada instal·lació o actualització es realitza una comprovació exhaustiva de l\'entorn. Contacteu amb l\'administrador si no sabeu com instal·lar una nova versió de PHP o com habilitar les extensions.';
+$string['errorsinenvironment'] = 'La comprovació de l\'entorn ha fallat.';
 $string['installation'] = 'Instal·lació';
-$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no està instal·lat. La instal·lació prosseguirà en anglès.';
+$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no es pot baixar. La instal·lació prosseguirà en anglès.';
 $string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servidor actualment està definit en {$a}.</p>
 
 <p>Això pot causar que Moodle tingui problemes de memòria més endavant, especialment si teniu molts mòduls habilitats i/o molts usuaris.</p>
@@ -57,13 +62,23 @@ $string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servid
 <p><blockquote>php_value memory_limit 40M</blockquote></p>
 <p>Tanmateix, en alguns servidors això farà que no funcioni <b>cap</b> pàgina PHP (es visualitzaran errors) en el qual cas hauríeu de suprimir el fitxer .htaccess.</p></li>
 </ol>';
+$string['paths'] = 'Camins';
+$string['pathserrcreatedataroot'] = 'L\'instal·lador no pot crear el directori de dades ({$a->dataroot}).';
+$string['pathshead'] = 'Confirmeu els camins';
+$string['pathsrodataroot'] = 'No es pot escriure en el directori dataroot.';
+$string['pathsroparentdataroot'] = 'No es pot escriure en el directori pare ({$a->parent}). L\'instal·lador no pot crear el directori ({$a->dataroot}).';
+$string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen un URL especial /admin p. ex. per a accedir a un tauler de control o quelcom semblant. Malauradament això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple <em>moodleadmin</em>. Això modificarà els enllaços d\'administració de Moodle.';
 $string['pathssubdataroot'] = 'Necessiteu un espai on Moodle pugui desar els fitxers penjats. Aquest directori hauria de tenir permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que sigui accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
+$string['pathssubdirroot'] = 'Camí complet del directori d\'instal·lació de Moodle.';
+$string['pathsunsecuredataroot'] = 'La ubicació del dataroot no és segura.';
+$string['pathswrongadmindir'] = 'No existeix el directori d\'administració';
+$string['phpextension'] = 'Extensió PHP {$a}';
 $string['phpversion'] = 'Versió PHP';
-$string['phpversionhelp'] = '<p>Moodle necessita la versió de PHP 4.1.0 o posterior.</p>
+$string['phpversionhelp'] = '<p>Moodle necessita una versió de PHP 4.3.0 o 5.1.0 (les versions 5.0.x tenien uns quants problemes coneguts).</p>
 <p>A hores d\'ara esteu utilitzant la versió {$a}.</p>
-<p>Us caldrà actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.</p>';
+<p>Us cal actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.<br />(Si esteu utilitzant la versió 5.0.x, alternativament també podríeu tornar enrere a la 4.4.x)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
-$string['welcomep20'] = 'Esteu veient aquesta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions!';
+$string['welcomep20'] = 'Esteu veient aquesta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions.';
 $string['welcomep30'] = 'Aquesta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcioni <strong>Moodle</strong>:';
 $string['welcomep40'] = 'El paquet inclou també <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
 $string['welcomep50'] = 'L\'ús de totes les aplicacions d\'aquest paquet és governat per les seves llicències respectives. El paquet <strong>{$a->installername}</strong> complet és
diff --git a/install/lang/pt/admin.php b/install/lang/pt/admin.php
index cd1814f..09bd68f 100644
--- a/install/lang/pt/admin.php
+++ b/install/lang/pt/admin.php
@@ -32,13 +32,11 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 's';
-$string['cliincorrectvalueerror'] = 'Erro. Valor "{$a->value}" incorreto para "{$a->option}"';
+$string['cliincorrectvalueerror'] = 'Erro: o valor "{$a->value}" não é permitido para a opção "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Valor incorreto, por favor tente novamente';
 $string['clitypevalue'] = 'valor do tipo';
-$string['clitypevaluedefault'] = 'Escreva o valor. Ou Enter para usar o valor  por omissão ({$a}).';
-$string['cliunknowoption'] = 'Opções desconhecidas:
-{$a}
-Por favor use a opção --help';
+$string['clitypevaluedefault'] = 'valor do tipo, pressione a tecla Enter para usar o valor predefinido ({$a})';
+$string['cliunknowoption'] = 'Opções desconhecidas: {$a} Por favor use a opção --help';
 $string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
-$string['environmentrequireinstall'] = 'é necessário estar instalada/ativa';
-$string['environmentrequireversion'] = 'É requerida a versão {$a->needed} e está a correr a versão {$a->current}';
+$string['environmentrequireinstall'] = 'deve estar instalada e ativa';
+$string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
diff --git a/install/lang/pt/error.php b/install/lang/pt/error.php
index 1107cdc..05bdef95 100644
--- a/install/lang/pt/error.php
+++ b/install/lang/pt/error.php
@@ -30,19 +30,19 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['cannotcreatelangdir'] = 'Não é possível criar o diretório para pacotes linguísticos';
-$string['cannotcreatetempdir'] = 'Não é possível criar o diretório temporário';
-$string['cannotdownloadcomponents'] = 'Não é possível descarregar  componentes';
-$string['cannotdownloadzipfile'] = 'Não é possível descarregar o ficheiro ZIP';
-$string['cannotfindcomponent'] = 'O componente não foi encontrado';
-$string['cannotsavemd5file'] = 'Não é possível gravar ficheiro md5';
-$string['cannotsavezipfile'] = 'Não  é possível gravar ficheiro ZIP';
-$string['cannotunzipfile'] = 'Não é possível descompatar ficheiro ZIP';
-$string['componentisuptodate'] = 'O componente está atualizado';
-$string['downloadedfilecheckfailed'] = 'Falhou a verificação do ficheiro descarregado.';
+$string['cannotcreatelangdir'] = 'Não é possível criar a pasta de pacotes linguísticos';
+$string['cannotcreatetempdir'] = 'Não é possível criar a pasta de ficheiros temporários';
+$string['cannotdownloadcomponents'] = 'Não é possível descarregar os componentes.';
+$string['cannotdownloadzipfile'] = 'Não é possível descarregar o ficheiro ZIP.';
+$string['cannotfindcomponent'] = 'Não é possível encontrar o componente';
+$string['cannotsavemd5file'] = 'Não é possível gravar o ficheiro md5';
+$string['cannotsavezipfile'] = 'Não é possível gravar o ficheiro ZIP';
+$string['cannotunzipfile'] = 'Não é possível descompactar o ficheiro ZIP';
+$string['componentisuptodate'] = 'O componente está atualizado.';
+$string['downloadedfilecheckfailed'] = 'A verificação do ficheiro descarregado falhou.';
 $string['invalidmd5'] = 'md5 inválido';
-$string['missingrequiredfield'] = 'Falta algum campo necessário';
-$string['remotedownloaderror'] = 'Não foi possível descarregar algum componente para o seu servidor; verifique as definições do proxy; recomenda-se fortemente o uso da extensão cURL do PHP.<br /><br />Deverá descarregar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copiá-lo para "{$a->dest}" no seu servidor, e descomprimi-lo nesse local.';
+$string['missingrequiredfield'] = 'Um dos campos obrigatórios está em falta';
+$string['remotedownloaderror'] = 'O download do componente para o servidor falhou. Verifique as configurações do proxy. A instalação da extensão cURL do PHP é muito recomendada.<br /><br />Terá que descarregar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copiá-lo para a pasta "{$a->dest}" no seu servidor e descompactá-lo.';
 $string['wrongdestpath'] = 'Caminho de destino errado.';
-$string['wrongsourcebase'] = 'URL errado para a fonte.';
+$string['wrongsourcebase'] = 'Base do URL de origem errada';
 $string['wrongzipfilename'] = 'Nome de ficheiro ZIP errado.';
diff --git a/install/lang/pt/install.php b/install/lang/pt/install.php
index 4e35aff..c2d95ef 100644
--- a/install/lang/pt/install.php
+++ b/install/lang/pt/install.php
@@ -30,68 +30,46 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['admindirname'] = 'Diretório de administração';
-$string['availablelangs'] = 'Lista de línguas disponíveis';
-$string['chooselanguagehead'] = 'Escolha uma língua';
-$string['chooselanguagesub'] = 'Escolha por favor a língua a usar na instalação. Esta língua será usada por omissão no site, mas pode ser alterada posteriormente.';
-$string['clialreadyconfigured'] = 'O ficheiro config.php já existe; por favor execute admin/cli/install_database.php se quiser instalar este sítio.';
-$string['clialreadyinstalled'] = 'O ficheiro config.php já existe. Por favor, use o script admin/cli/upgrade.php se quiser atualizar o seu sítio.';
-$string['cliinstallheader'] = 'Programa de instalação do Moodle {$a} por linha de comandos';
+$string['admindirname'] = 'Pasta de administração';
+$string['availablelangs'] = 'Idiomas disponíveis';
+$string['chooselanguagehead'] = 'Selecione um idioma';
+$string['chooselanguagesub'] = 'Selecione o idioma a utilizar durante a instalação. Poderá depois selecionar um outro idioma para o site e para os utilizadores.';
+$string['clialreadyconfigured'] = 'O ficheiro config.php já existe, use admin/cli/install_database.php se desejar instalar este site.';
+$string['clialreadyinstalled'] = 'O ficheiro <b>config.php</b> já se encontra no servidor, o que indica que já existe uma instalação prévia do Moodle. Se pretender realizar uma atualização do Moodle existente, deve usar o <i>script</i> <b>admin/cli/upgrade.php</b>';
+$string['cliinstallheader'] = 'Programa para instalação do Moodle <b>{$a}</b> através da linha de comandos';
 $string['databasehost'] = 'Servidor da base de dados';
 $string['databasename'] = 'Nome da base de dados';
-$string['databasetypehead'] = 'Escolha driver da base de dados';
-$string['dataroot'] = 'Diretório de dados';
-$string['datarootpermission'] = 'Permissão dos diretórios de dados';
+$string['databasetypehead'] = 'Escolha o <i>driver</i> da base de dados';
+$string['dataroot'] = 'Pasta de dados';
+$string['datarootpermission'] = 'Permissões da diretoria de dados';
 $string['dbprefix'] = 'Prefixo das tabelas';
-$string['dirroot'] = 'Diretório do Moodle';
-$string['environmenthead'] = 'A verificar o seu ambiente ...';
-$string['environmentsub2'] = 'Cada versão do Moodle tem requisitos mínimos relativamente à versão do PHP e às extensões PHP obrigatórias. É feita uma análise total ao ambiente existente antes de cada instalação ou atualização. Por favor contate o seu administrador de sistemas se não souber como instalar uma nova versão do PHP ou ativar as suas extensões.';
-$string['errorsinenvironment'] = 'Erros no ambiente!';
+$string['dirroot'] = 'Pasta do Moodle';
+$string['environmenthead'] = 'A verificar sistema...';
+$string['environmentsub2'] = 'Cada nova versão do Moodle tem pré-requisitos mínimos relativamente à versão do PHP e extensões necessárias para o seu correto funcionamento. Estes pré-requisitos são verificados sempre que o Moodle é instalado ou atualizado. Contacte o administrador do servidor caso seja necessário atualizar a versão do PHP ou instalar novas extensões.';
+$string['errorsinenvironment'] = 'A verificação do sistema falhou!';
 $string['installation'] = 'Instalação';
-$string['langdownloaderror'] = 'Não foi possível descarregar a língua "{$a}". O processo de instalação continuará em Inglês.';
-$string['memorylimithelp'] = '<p>Atualmente o seu servidor impõe ao PHP um limite de memória de {$a}.</p>
-
-<p>Isso poderá causar mais tarde problemas, especialmente se tiver um grande número de módulos ativos e/ou um número elevado de utilizadores.</p>
-
-<p>Recomendamos que configure o PHP com um limite maior, por exemplo, 40M.
-Existem várias formas de fazer essa alteração:</p>
-<ol>
-<li>Recompilar o PHP com <i>--enable-memory-limit</i>.
-Isso permitirá que o próprio Moodle modifique o limite de memória.</li>
-<li>Se tiver acesso ao ficheiro php.ini, poderá modificar o valor de <b>memory_limit</b> para algo como 40M. Se não tiver acesso, poderá pedir ao adiminstrador do seu sistema que o faça.</li>
-<li>Em alguns servidores PHP poderá criar um ficheiro .htaccess no diretório do Moodle, com a linha:
-<p><blockquote>php_value memory_limit 40M</blockquote></p>
-<p>No entanto, em alguns servidores, isso faz com que nenhuma página PHP funcione (verá erros quando tentar ver as páginas) e terá que apagar o ficheiro .htaccess.</p></li>
-</ol>';
+$string['langdownloaderror'] = 'Não foi possível instalar o idioma <b>{$a}</b> por falha no download. O processo de instalação continuará em Inglês.';
+$string['memorylimithelp'] = '<p>O limite de memória para o PHP definido atualmente no servidor é <b>{$a}</b>.</p><p>Um número elevado de módulos em utilização ou de utilizadores registados pode fazer com que o Moodle apresente problemas de falta de memória.</p><p>É recomendado que o PHP seja configurado com um limite de memória de pelo menos 40MB. Esta configuração pode ser definida de diversas formas:</p><ol><li>Compilação do PHP com o parâmetro <b>--enable-memory-limit</b>. Esta definição permitirá ao próprio Moodle definir o valor a utilizar.</li><li>Alteração do parâmetro <b>memory_limit</b> no ficheiro de configuração do PHP para um valor igual ou superior a 40MB.</li><li>Criação de um ficheiro <b>.htaccess</b> na raiz da pasta do Moodle com a linha <b>php_value memory_limit 40M</b><p>ATENÇÃO: Em alguns servidores esta configuração impedirá o funcionamento de <b>todas</b> as páginas PHP. Nestes casos, não poderá ser utilizado o ficheiro <b>.htaccess</b>.</p></li></ol>';
 $string['paths'] = 'Caminhos';
-$string['pathserrcreatedataroot'] = 'O programa de instalação não conseguiu criar o diretório de dados ({$a->dataroot})';
+$string['pathserrcreatedataroot'] = 'O programa de instalação não conseguiu criar a pasta de dados <b>{$a->dataroot}</b>.';
 $string['pathshead'] = 'Confirmar caminhos';
-$string['pathsrodataroot'] = 'A diretoria dataroot não tem permissões de escrita.';
-$string['pathsroparentdataroot'] = 'O diretório pai ({$a->parent}) não tem permissões de escrita. O programa de instalação não conseguiu criar o diretório de dados ({$a->dataroot})';
-$string['pathssubadmindir'] = 'Alguns (poucos) alojamentos web usam /admin como um URL especial para permitir o acesso ao control panel ou a outras funcionalidades.
-Infelizmente esta designação entra em conflito com a localização que o Moodle atribui às páginas de administração.
-A solução passa por renomear o diretório admin da sua instalação do Moodle e colocando o nome escolhido aqui. Por exemplo:
-<em>moodleadmin</em>. Isto corrige os links de administração no Moodle.';
-$string['pathssubdataroot'] = 'É necessário um local onde o Moodle possa gravar os ficheiros submetidos. Este diretório tem que ter permissões de leitura e ESCRITA pelo servidor web (normalmente \'nobody\' ou \'apache\'), mas não pode estar acessível através da web. O programa de instalação tentará criar este diretório se ele ainda não existir.';
-$string['pathssubdirroot'] = 'Caminho completo para a diretoria de instalação do Moodle.';
-$string['pathssubwwwroot'] = 'Endereço web completo para acesso ao Moodle.
-Não é possível aceder ao Moodle usando vários endereços.
-Se o seu site tem vários endereços públicos é necessário definir redirecionamentos permanentes em todos eles exceto neste.
-Se o seu site pode ser acedido via intranet e Internet use este endereço público e configure o DNS para que a intranet permita a utilização deste endereço.
-Se o endereço não estiver correto mude o URL no seu browser para reiniciar a instalação com um valor diferente.';
-$string['pathsunsecuredataroot'] = 'O diretório dataroot não é seguro';
-$string['pathswrongadmindir'] = 'A diretoria admin não existe';
-$string['phpextension'] = 'Extensão PHP {$a}';
+$string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
+$string['pathsroparentdataroot'] = 'A pasta pai <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
+$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URL\'s especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso dos links para as funcionalidades de administração do Moodle.';
+$string['pathssubdataroot'] = 'É necessária uma pasta onde o Moodle possa gravar os ficheiros enviados para a plataforma. Esta pasta deve ter permissão de <b>leitura</b> e <b>escrita</b> pelo utilizador do web server (normalmente <b>nobody</b> ou <b>apache</b>). Por razões de segurança esta pasta não deve estar diretamente acessível através da Internet.';
+$string['pathssubdirroot'] = 'Caminho completo para a pasta de instalação do Moodle.';
+$string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redireccionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranets, então este endereço deve ser configurado no DNS de forma a que os utilizadores das Intranets possam usar este endereço público para aceder ao Moodle. Se o endereço não está correto, então altere o endereço indicado no browser para reiniciar a instalação com o URL correto.';
+$string['pathsunsecuredataroot'] = 'A localização da pasta de dados não é segura';
+$string['pathswrongadmindir'] = 'A pasta <b>admin</b> não existe';
+$string['phpextension'] = 'Extensão <b>{$a}</b> do PHP';
 $string['phpversion'] = 'Versão do PHP';
-$string['phpversionhelp'] = '<p>O Moodle precisa da versão 4.3.0 ou 5.1.0 do PHP (5.0.x produz vários problemas) ou superior.</p>
-<p>Atualmente está a utilizar a versão {$a}</p>
-<p>Deverá atualizar o PHP ou migrar para outro servidor com uma versão do PHP mais recente!</p>
-(No caso da versão 5.0.x, poderá regredir para uma versão 4.4.x)</p>';
+$string['phpversionhelp'] = '<p>A instalação do Moodle só é possível se o servidor tiver instalada a versão 4.3.0 ou 5.1.0 ( a versão 5.0.x apresenta vários problemas) ou superiores.</p><p>A versão atualmente instalada é  <b>{$a}</b></p><p>É necessário atualizar esta versão do PHP ou mudar para um novo servidor que possua as referidas versões!<br />(Se a versão instalada for a 5.0.x é possível regredir para a versão 4.4.x)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
-$string['welcomep20'] = 'Está a ver esta página porque o pacote <strong>{$a->packname} {$a->packversion}</strong> foi instalado e posto a funcionar com sucesso no seu computador. Parabens!';
-$string['welcomep30'] = 'Esta versão do <strong>{$a->installername}</strong> inclui aplicações para criar um ambiente onde o <strong>Moodle</strong> possa funcionar, nomeadamente:';
-$string['welcomep40'] = 'Este pacote também inclui <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
-$string['welcomep50'] = 'A utilização de todas as aplicações neste pacote está regida pelas respetivas licenças. O pacote <strong>{$a->installername}</strong> completo é <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> distribuido nos termos da licença <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
-$string['welcomep60'] = 'As páginas seguintes vão conduzí-lo por alguns passos simples de seguir para configurar o <strong>Moodle</strong> no seu computador. Poderá aceitar as definições selecionadas por omissão, ou, opcionalmente, usar outras definições mais apropriadas às suas necessidades.';
-$string['welcomep70'] = 'Clique no botão "Seguinte" em baixo, para continuar com a configuração do <strong>Moodle</strong>.';
-$string['wwwroot'] = 'Endereço Web';
+$string['welcomep20'] = 'A apresentação desta página confirma a correta instalação e ativação do pacote <strong>{$a->packname} {$a->packversion}</strong> no servidor.';
+$string['welcomep30'] = 'Esta versão do pacote <strong>{$a->installername}</strong> inclui as aplicações necessárias para o correto funcionamento do  <strong>Moodle</strong>, nomeadamente:';
+$string['welcomep40'] = 'Este pacote inclui <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
+$string['welcomep50'] = 'A utilização de todas as aplicações incluídas neste pacote é limitada pelas respetivas licenças. O pacote completo <strong>{$a->installername}</strong> é <ahref="http://www.opensource.org/docs/definition_plain.html">código aberto</a> e distribuído nos termos da licença <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
+$string['welcomep60'] = 'As páginas seguintes irão levá-lo através de alguns passos simples para
+     configurar e definir o <strong>Moodle</strong> no seu computador. Você pode aceitar as configurações predefinidas ou, opcionalmente, alterá-las para atender às suas próprias necessidades.';
+$string['welcomep70'] = 'Clique no botão "Seguinte" para continuar a configuração do <strong>Moodle</strong>.';
+$string['wwwroot'] = 'Endereço web';
diff --git a/install/lang/pt/langconfig.php b/install/lang/pt/langconfig.php
index 58ad62b..02f60f7 100644
--- a/install/lang/pt/langconfig.php
+++ b/install/lang/pt/langconfig.php
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Português - Portugal';
diff --git a/install/lang/pt/moodle.php b/install/lang/pt/moodle.php
index 9473ac8..1374074 100644
--- a/install/lang/pt/moodle.php
+++ b/install/lang/pt/moodle.php
@@ -30,7 +30,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['language'] = 'Língua';
-$string['next'] = 'Próximo';
+$string['language'] = 'Idioma';
+$string['next'] = 'Seguinte';
 $string['previous'] = 'Anterior';
 $string['reload'] = 'Recarregar';
-- 
1.7.9.5


From 074236eee7d95960b304104adbb4eee7d238ceac Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Tue, 24 Apr 2012 10:11:07 +1200
Subject: [PATCH 162/903] MDL-32582 - filter/multimedia: MP3 Flow Player
 doesn't work in Chrome if empty stylesheets are
 present

---
 lib/javascript-static.js |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 6bf2e28..5640b44 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1779,6 +1779,7 @@ M.util.load_flowplayer = function() {
                     // why??
                     continue;
                 }
+                if (!allrules) continue;
                 for(var i=0; i<allrules.length; i++) {
                     rule = '';
                     if (/^\.mp3flowplayer_.*Color$/.test(allrules[i].selectorText)) {
-- 
1.7.9.5


From 476f72e9bf231d507362ead6459d7b3c83d8af20 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 4 Jul 2012 13:18:37 +0800
Subject: [PATCH 163/903] MDL-34153 mod_forum: create RFC-2822 compliant
 message-ids

---
 mod/forum/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 812172a..4b7a8cc 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -383,7 +383,7 @@ WHERE
  * @return string A unique message-id
  */
 function forum_get_email_message_id($postid, $usertoid, $hostname) {
-    return '<'.hash('sha256',$postid.'to'.$usertoid.'@'.$hostname).'>';
+    return '<'.hash('sha256',$postid.'to'.$usertoid).'@'.$hostname.'>';
 }
 
 /**
-- 
1.7.9.5


From 9f7f501c0a400dccf8aa4c1228a0559e60f7a409 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 12 Jul 2012 18:21:00 +1200
Subject: [PATCH 164/903] Revert "MDL-33575 choice module: add label to
 checkbox element when privacy of results is set to
 publish full results"

This reverts commit f19cd427091d57a03fe072bf8a1ccc27f01b4e61.
---
 mod/choice/renderer.php |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mod/choice/renderer.php b/mod/choice/renderer.php
index dc89877..07bbd19 100644
--- a/mod/choice/renderer.php
+++ b/mod/choice/renderer.php
@@ -214,7 +214,7 @@ class mod_choice_renderer extends plugin_renderer_base {
                         }
 
                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
-                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'', null, array('id' => 'attempt-user'.$user->id));
+                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
                         }
                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
@@ -222,7 +222,6 @@ class mod_choice_renderer extends plugin_renderer_base {
 
                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
                         $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
-                        $name = html_writer::label($name, 'attempt-user'.$user->id);
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
                         $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
-- 
1.7.9.5


From 3b52187e251b910e14dc21d9a379d6c5cc63c290 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 12 Jul 2012 15:57:26 +0800
Subject: [PATCH 165/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 7a77285..246fae2 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.01;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.02;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1 (Build: 20120706)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120712)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 7ec63b27d005317d27a24e9ceac8ede520b7cd72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 11 Jul 2012 15:54:03 +0200
Subject: [PATCH 166/903] MDL-34271 cleanup mysql engine hack before adding
 similar collation hack

---
 lib/ddl/mysql_sql_generator.php           |   19 ++++++-----------
 lib/dml/mysqli_native_moodle_database.php |   32 ++++++++++++++++++-----------
 2 files changed, 26 insertions(+), 25 deletions(-)

diff --git a/lib/ddl/mysql_sql_generator.php b/lib/ddl/mysql_sql_generator.php
index 6ae310f..99d118d 100644
--- a/lib/ddl/mysql_sql_generator.php
+++ b/lib/ddl/mysql_sql_generator.php
@@ -117,23 +117,16 @@ class mysql_sql_generator extends sql_generator {
      * by any of its comments, indexes and sequence creation SQL statements.
      */
     public function getCreateTableSQL($xmldb_table) {
-        // first find out if want some special db engine
-        $engine = null;
-        if (method_exists($this->mdb, 'get_dbengine')) {
-            $engine = $this->mdb->get_dbengine();
-        }
-
+        // First find out if want some special db engine.
+        $engine = $this->mdb->get_dbengine();
         $sqlarr = parent::getCreateTableSQL($xmldb_table);
 
-        if (!$engine) {
-            // we rely on database defaults
-            return $sqlarr;
-        }
-
-        // let's inject the engine into SQL
+        // Let's inject the extra MySQL tweaks.
         foreach ($sqlarr as $i=>$sql) {
             if (strpos($sql, 'CREATE TABLE ') === 0) {
-                $sqlarr[$i] .= " ENGINE = $engine";
+                if ($engine) {
+                    $sqlarr[$i] .= " ENGINE = $engine";
+                }
             }
         }
 
diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php
index 93311bd..5134ac9 100644
--- a/lib/dml/mysqli_native_moodle_database.php
+++ b/lib/dml/mysqli_native_moodle_database.php
@@ -146,22 +146,28 @@ class mysqli_native_moodle_database extends moodle_database {
             return $this->dboptions['dbengine'];
         }
 
+        if ($this->external) {
+            return null;
+        }
+
         $engine = null;
 
-        if (!$this->external) {
-            // look for current engine of our config table (the first table that gets created),
-            // so that we create all tables with the same engine
-            $sql = "SELECT engine FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
-            $this->query_start($sql, NULL, SQL_QUERY_AUX);
-            $result = $this->mysqli->query($sql);
-            $this->query_end($result);
-            if ($rec = $result->fetch_assoc()) {
-                $engine = $rec['engine'];
-            }
-            $result->close();
+        // Look for current engine of our config table (the first table that gets created),
+        // so that we create all tables with the same engine.
+        $sql = "SELECT engine
+                  FROM INFORMATION_SCHEMA.TABLES
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $engine = $rec['engine'];
         }
+        $result->close();
 
         if ($engine) {
+            // Cache the result to improve performance.
+            $this->dboptions['dbengine'] = $engine;
             return $engine;
         }
 
@@ -175,7 +181,7 @@ class mysqli_native_moodle_database extends moodle_database {
         }
         $result->close();
 
-        if (!$this->external and $engine === 'MyISAM') {
+        if ($engine === 'MyISAM') {
             // we really do not want MyISAM for Moodle, InnoDB or XtraDB is a reasonable defaults if supported
             $sql = "SHOW STORAGE ENGINES";
             $this->query_start($sql, NULL, SQL_QUERY_AUX);
@@ -196,6 +202,8 @@ class mysqli_native_moodle_database extends moodle_database {
             }
         }
 
+        // Cache the result to improve performance.
+        $this->dboptions['dbengine'] = $engine;
         return $engine;
     }
 
-- 
1.7.9.5


From 41e8883ea8af217f43e29ddd28d57be3a41dc099 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 11 Jul 2012 16:39:20 +0200
Subject: [PATCH 167/903] MDL-34271 use the same collation when adding new
 tables or columns

---
 lib/ddl/mysql_sql_generator.php           |   42 +++++++++++++++-
 lib/dml/mysqli_native_moodle_database.php |   74 ++++++++++++++++++++++++++++-
 2 files changed, 113 insertions(+), 3 deletions(-)

diff --git a/lib/ddl/mysql_sql_generator.php b/lib/ddl/mysql_sql_generator.php
index 99d118d..abd5ddd 100644
--- a/lib/ddl/mysql_sql_generator.php
+++ b/lib/ddl/mysql_sql_generator.php
@@ -119,6 +119,9 @@ class mysql_sql_generator extends sql_generator {
     public function getCreateTableSQL($xmldb_table) {
         // First find out if want some special db engine.
         $engine = $this->mdb->get_dbengine();
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
+
         $sqlarr = parent::getCreateTableSQL($xmldb_table);
 
         // Let's inject the extra MySQL tweaks.
@@ -127,6 +130,12 @@ class mysql_sql_generator extends sql_generator {
                 if ($engine) {
                     $sqlarr[$i] .= " ENGINE = $engine";
                 }
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE = $collation";
+                }
             }
         }
 
@@ -141,9 +150,26 @@ class mysql_sql_generator extends sql_generator {
      * @return array of sql statements
      */
     public function getCreateTempTableSQL($xmldb_table) {
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
         $this->temptables->add_temptable($xmldb_table->getName());
-        $sqlarr = parent::getCreateTableSQL($xmldb_table); // we do not want the engine hack included in create table SQL
-        $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sqlarr);
+
+        $sqlarr = parent::getCreateTableSQL($xmldb_table);
+
+        // Let's inject the extra MySQL tweaks.
+        foreach ($sqlarr as $i=>$sql) {
+            if (strpos($sql, 'CREATE TABLE ') === 0) {
+                // We do not want the engine hack included in create table SQL.
+                $sqlarr[$i] = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sql);
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE $collation";
+                }
+            }
+        }
+
         return $sqlarr;
     }
 
@@ -224,9 +250,21 @@ class mysql_sql_generator extends sql_generator {
                     $xmldb_length='255';
                 }
                 $dbtype .= '(' . $xmldb_length . ')';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_TEXT:
                 $dbtype = 'LONGTEXT';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_BINARY:
                 $dbtype = 'LONGBLOB';
diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php
index 5134ac9..9294c07 100644
--- a/lib/dml/mysqli_native_moodle_database.php
+++ b/lib/dml/mysqli_native_moodle_database.php
@@ -82,7 +82,13 @@ class mysqli_native_moodle_database extends moodle_database {
             throw new dml_connection_exception($dberr);
         }
 
-        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci");
+        if (isset($dboptions['dbcollation']) and strpos($dboptions['dbcollation'], 'utf8_') === 0) {
+            $collation = $dboptions['dbcollation'];
+        } else {
+            $collation = 'utf8_unicode_ci';
+        }
+
+        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ".$collation);
 
         $conn->close();
 
@@ -208,6 +214,72 @@ class mysqli_native_moodle_database extends moodle_database {
     }
 
     /**
+     * Returns the current MySQL db collation.
+     *
+     * This is an ugly workaround for MySQL default collation problems.
+     *
+     * @return string or null MySQL collation name
+     */
+    public function get_dbcollation() {
+        if (isset($this->dboptions['dbcollation'])) {
+            return $this->dboptions['dbcollation'];
+        }
+        if ($this->external) {
+            return null;
+        }
+
+        $collation = null;
+
+        // Look for current collation of our config table (the first table that gets created),
+        // so that we create all tables with the same collation.
+        $sql = "SELECT collation_name
+                  FROM INFORMATION_SCHEMA.COLUMNS
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config' AND column_name = 'value'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $collation = $rec['collation_name'];
+        }
+        $result->close();
+
+        if (!$collation) {
+            // Get the default database collation, but only if using UTF-8.
+            $sql = "SELECT @@collation_database";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            if ($rec = $result->fetch_assoc()) {
+                if (strpos($rec['@@collation_database'], 'utf8_') === 0) {
+                    $collation = $rec['@@collation_database'];
+                }
+            }
+            $result->close();
+        }
+
+        if (!$collation) {
+            // We want only utf8 compatible collations.
+            $collation = null;
+            $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            while ($res = $result->fetch_assoc()) {
+                $collation = $res['Collation'];
+                if (strtoupper($res['Default']) === 'YES') {
+                    $collation = $res['Collation'];
+                    break;
+                }
+            }
+            $result->close();
+        }
+
+        // Cache the result to improve performance.
+        $this->dboptions['dbcollation'] = $collation;
+        return $collation;
+    }
+
+    /**
      * Returns localised database type name
      * Note: can be used before connect()
      * @return string
-- 
1.7.9.5


From 3eb9ebb3c893a625f89d112d1e8535a4b82fbd08 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Thu, 12 Jul 2012 14:38:05 +0200
Subject: [PATCH 168/903] MDL-34271 add new cli tool for mysql collation
 conversions

---
 admin/cli/mysql_collation.php |  211 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 211 insertions(+)
 create mode 100644 admin/cli/mysql_collation.php

diff --git a/admin/cli/mysql_collation.php b/admin/cli/mysql_collation.php
new file mode 100644
index 0000000..9938a3a
--- /dev/null
+++ b/admin/cli/mysql_collation.php
@@ -0,0 +1,211 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * MySQL collation conversion tool.
+ *
+ * @package    core
+ * @copyright  2012 Petr Skoda (http://skodak.org)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->libdir.'/clilib.php');      // cli only functions
+
+if ($DB->get_dbfamily() !== 'mysql') {
+    cli_error('This function is designed for MySQL databases only!');
+}
+
+// now get cli options
+list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'collation'=>false, 'available'=>false),
+    array('h'=>'help', 'l'=>'list', 'a'=>'available'));
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+$help =
+    "MySQL collation conversions script.
+
+It is strongly recommended to stop the web server before the conversion.
+This script may be executed before the main upgrade - 1.9.x data for example.
+
+Options:
+--collation=COLLATION Convert MySQL tables to different collation
+-l, --list            Show table and column information
+-a, --available       Show list of available collations
+-h, --help            Print out this help
+
+Example:
+\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
+";
+
+if (!empty($options['collation'])) {
+    $collations = mysql_get_collations();
+    $collation = clean_param($options['collation'], PARAM_ALPHANUMEXT);
+    $collation = strtolower($collation);
+    if (!isset($collations[$collation])) {
+        cli_error("Error: collation '$collation' is not available on this server!");
+    }
+
+    echo "Converting tables and columns to '$collation' for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $converted = 0;
+    $skipped   = 0;
+    $errors    = 0;
+    foreach ($rs as $table) {
+        echo str_pad($table->name, 40). " - ";
+
+        if ($table->collation === $collation) {
+            echo "NO CHANGE\n";
+            $skipped++;
+
+        } else {
+            $DB->change_database_structure("ALTER TABLE $table->name DEFAULT COLLATE = $collation");
+            echo "CONVERTED\n";
+            $converted++;
+        }
+
+        $sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
+        $rs2 = $DB->get_recordset_sql($sql);
+        foreach ($rs2 as $column) {
+            $column = (object)array_change_key_case((array)$column, CASE_LOWER);
+            echo '    '.str_pad($column->field, 36). " - ";
+            if ($column->collation === $collation) {
+                echo "NO CHANGE\n";
+                $skipped++;
+                continue;
+            }
+
+            if ($column->type === 'tinytext' or $column->type === 'mediumtext' or $column->type === 'text' or $column->type === 'longtext') {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+
+            } else if (strpos($column->type, 'varchar') === 0) {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+            } else {
+                echo "ERROR (unknown column type: $column->type)\n";
+                $error++;
+                continue;
+            }
+            echo "CONVERTED\n";
+            $converted++;
+        }
+        $rs2->close();
+    }
+    $rs->close();
+    echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
+    exit(0); // success
+
+} else if (!empty($options['list'])) {
+    echo "List of tables for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $counts = array();
+    foreach ($rs as $table) {
+        if (isset($counts[$table->collation])) {
+            $counts[$table->collation]++;
+        } else {
+            $counts[$table->collation] = 1;
+        }
+        echo str_pad($table->name, 40);
+        echo $table->collation.  "\n";
+        $collations = mysql_get_column_collations($table->name);
+        foreach ($collations as $columname=>$collation) {
+            if (isset($counts[$collation])) {
+                $counts[$collation]++;
+            } else {
+                $counts[$collation] = 1;
+            }
+            echo '    ';
+            echo str_pad($columname, 36);
+            echo $collation.  "\n";
+        }
+    }
+    $rs->close();
+
+    echo "\n";
+    echo "Table collations summary for $CFG->wwwroot:\n";
+    foreach ($counts as $collation => $count) {
+        echo "$collation: $count\n";
+    }
+    exit(0); // success
+
+} else if (!empty($options['available'])) {
+    echo "List of available MySQL collations for $CFG->wwwroot:\n";
+    $collations = mysql_get_collations();
+    foreach ($collations as $collation) {
+        echo " $collation\n";
+    }
+    die;
+
+} else {
+    echo $help;
+    die;
+}
+
+
+
+// ========== Some functions ==============
+
+function mysql_get_collations() {
+    global $DB;
+
+    $collations = array();
+    $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+    $rs = $DB->get_recordset_sql($sql);
+    foreach ($rs as $collation) {
+        $collations[$collation->collation] = $collation->collation;
+    }
+    $rs->close();
+
+    $collation = $DB->get_dbcollation();
+    if (isset($collations[$collation])) {
+        $collations[$collation] .= ' (default)';
+    }
+
+    return $collations;
+}
+
+function mysql_get_column_collations($tablename) {
+    global $DB;
+
+    $collations = array();
+    $sql = "SELECT column_name, collation_name
+              FROM INFORMATION_SCHEMA.COLUMNS
+             WHERE table_schema = DATABASE() AND table_name = ? AND collation_name IS NOT NULL";
+    $rs = $DB->get_recordset_sql($sql, array($tablename));
+    foreach($rs as $record) {
+        $collations[$record->column_name] = $record->collation_name;
+    }
+    $rs->close();
+    return $collations;
+}
-- 
1.7.9.5


From eab8660e8fc633a127098a280ce461704dc029ae Mon Sep 17 00:00:00 2001
From: Fred Woolard <woolardfa@appstate.edu>
Date: Fri, 6 Jul 2012 16:29:05 -0400
Subject: [PATCH 169/903] MDL-34211 Use the $table_name argument to check
 against $metatables key values

---
 lib/ddl/mysql_sql_generator.php |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/lib/ddl/mysql_sql_generator.php b/lib/ddl/mysql_sql_generator.php
index 6ae310f..83c3776 100644
--- a/lib/ddl/mysql_sql_generator.php
+++ b/lib/ddl/mysql_sql_generator.php
@@ -333,18 +333,14 @@ class mysql_sql_generator extends sql_generator {
      */
     public function isNameInUse($object_name, $type, $table_name) {
 
-        // Calculate the real table name
-        $xmldb_table = new xmldb_table($table_name);
-        $tname = $this->getTableName($xmldb_table);
-
         switch($type) {
             case 'ix':
             case 'uix':
                 // First of all, check table exists
                 $metatables = $this->mdb->get_tables();
-                if (isset($metatables[$tname])) {
+                if (isset($metatables[$table_name])) {
                     // Fetch all the indexes in the table
-                    if ($indexes = $this->mdb->get_indexes($tname)) {
+                    if ($indexes = $this->mdb->get_indexes($table_name)) {
                         // Look for existing index in array
                         if (isset($indexes[$object_name])) {
                             return true;
-- 
1.7.9.5


From fd626c410939618a1aa304cf880e9c94364c208e Mon Sep 17 00:00:00 2001
From: Fred Woolard <woolardfa@appstate.edu>
Date: Wed, 27 Jun 2012 18:46:14 -0400
Subject: [PATCH 170/903] MDL-34072: Adjust SQL for Oracle. Remove subquery
 alias altogether.

---
 course/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index 374b309..0376a3a 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -4033,7 +4033,7 @@ function average_number_of_participants() {
         WHERE ue.enrolid = e.id
             AND e.courseid <> :siteid
             AND c.id = e.courseid
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $enrolmenttotal = $DB->count_records_sql($sql, $params);
 
@@ -4066,7 +4066,7 @@ function average_number_of_courses_modules() {
         WHERE c.id = cm.course
             AND c.id <> :siteid
             AND cm.visible = 1
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $moduletotal = $DB->count_records_sql($sql, $params);
 
-- 
1.7.9.5


From a3db6afa39cd0620734490a731aa522ff885435f Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 13 Jul 2012 00:32:23 +0000
Subject: [PATCH 171/903] Automatically generated installer lang files

---
 install/lang/ca/install.php |    5 +++++
 install/lang/pt/admin.php   |    6 ++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/install/lang/ca/install.php b/install/lang/ca/install.php
index 940d880..fb62037 100644
--- a/install/lang/ca/install.php
+++ b/install/lang/ca/install.php
@@ -70,6 +70,11 @@ $string['pathsroparentdataroot'] = 'No es pot escriure en el directori pare ({$a
 $string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen un URL especial /admin p. ex. per a accedir a un tauler de control o quelcom semblant. Malauradament això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple <em>moodleadmin</em>. Això modificarà els enllaços d\'administració de Moodle.';
 $string['pathssubdataroot'] = 'Necessiteu un espai on Moodle pugui desar els fitxers penjats. Aquest directori hauria de tenir permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que sigui accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
 $string['pathssubdirroot'] = 'Camí complet del directori d\'instal·lació de Moodle.';
+$string['pathssubwwwroot'] = 'L\'adreça web completa on s\'accedirà a Moodle.
+No és possible accedir a Moodle en diferents adreces.
+Si el vostre lloc té múltiples adreces públiques haureu de configurar redireccions permanents per a totes excepte aquesta.
+Si el vostre lloc és accessible tant des d\'Internet com des d\'una intranet, utilitzeu aquí l\'adreça pública i configureu el DNS de manera que els usuaris de la intranet puguin utilitzar també l\'adreça pública.
+Si l\'adreça no és correcta, canvieu l\'URL en el vostre navegador per reiniciar la instal·lació amb un altre valor.';
 $string['pathsunsecuredataroot'] = 'La ubicació del dataroot no és segura.';
 $string['pathswrongadmindir'] = 'No existeix el directori d\'administració';
 $string['phpextension'] = 'Extensió PHP {$a}';
diff --git a/install/lang/pt/admin.php b/install/lang/pt/admin.php
index 09bd68f..beeead1 100644
--- a/install/lang/pt/admin.php
+++ b/install/lang/pt/admin.php
@@ -32,11 +32,13 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 's';
-$string['cliincorrectvalueerror'] = 'Erro: o valor "{$a->value}" não é permitido para a opção "{$a->option}"';
+$string['cliincorrectvalueerror'] = 'Erro. Valor "{$a->value}" incorreto para "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Valor incorreto, por favor tente novamente';
 $string['clitypevalue'] = 'valor do tipo';
 $string['clitypevaluedefault'] = 'valor do tipo, pressione a tecla Enter para usar o valor predefinido ({$a})';
-$string['cliunknowoption'] = 'Opções desconhecidas: {$a} Por favor use a opção --help';
+$string['cliunknowoption'] = 'Opções desconhecidas:
+{$a}
+Por favor use a opção --help';
 $string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
 $string['environmentrequireinstall'] = 'deve estar instalada e ativa';
 $string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
-- 
1.7.9.5


From 7397acb145f4865db5e8579d620ff7a72d55baa7 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 28 Jun 2012 16:27:04 +0800
Subject: [PATCH 172/903] MDL-31622 Forms: Date selector supports i18n

---
 .../dateselector/assets/skins/sam/dateselector.css |    1 +
 lib/form/yui/dateselector/dateselector.js          |   25 +++++++++++++++++++-
 lib/formslib.php                                   |   23 +++++++++++++++++-
 3 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/lib/form/yui/dateselector/assets/skins/sam/dateselector.css b/lib/form/yui/dateselector/assets/skins/sam/dateselector.css
index 01a37e7..d8abda4 100644
--- a/lib/form/yui/dateselector/assets/skins/sam/dateselector.css
+++ b/lib/form/yui/dateselector/assets/skins/sam/dateselector.css
@@ -1,3 +1,4 @@
 #dateselector-calendar-panel {background-color:#999;border-bottom:3px solid #999;border-right:3px solid #999;}
 #dateselector-calendar-content {border:1px solid #666;margin-top:-3px;margin-left:-3px;}
+#dateselector-calendar-content_t th.calweekdaycell {padding-left:3px; padding-right:3px;}
 body.ie #dateselector-calendar-panel.yui3-overlay-hidden table {display:none;}
\ No newline at end of file
diff --git a/lib/form/yui/dateselector/dateselector.js b/lib/form/yui/dateselector/dateselector.js
index d403547..1109b22 100644
--- a/lib/form/yui/dateselector/dateselector.js
+++ b/lib/form/yui/dateselector/dateselector.js
@@ -197,7 +197,30 @@ YUI.add('moodle-form-dateselector', function(Y) {
             this.calendar = new YAHOO.widget.Calendar(document.getElementById('dateselector-calendar-content'), {
                 iframe: false,
                 hide_blank_weeks: true,
-                start_weekday: config.firstdayofweek
+                start_weekday: config.firstdayofweek,
+                locale_weekdays: 'medium',
+                locale_months: 'long',
+                WEEKDAYS_MEDIUM: [
+                    config.sun,
+                    config.mon,
+                    config.tue,
+                    config.wed,
+                    config.thu,
+                    config.fri,
+                    config.sat ],
+                MONTHS_LONG: [
+                    config.january,
+                    config.february,
+                    config.march,
+                    config.april,
+                    config.may,
+                    config.june,
+                    config.july,
+                    config.august,
+                    config.september,
+                    config.october,
+                    config.november,
+                    config.december ],
             });
             this.calendar.changePageEvent.subscribe(function(){
                 this.fix_position();
diff --git a/lib/formslib.php b/lib/formslib.php
index 306c4e5..d02d332 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -79,7 +79,28 @@ function form_init_date_js() {
     if (!$done) {
         $module   = 'moodle-form-dateselector';
         $function = 'M.form.dateselector.init_date_selectors';
-        $config = array(array('firstdayofweek'=>get_string('firstdayofweek', 'langconfig')));
+        $config = array(array(
+            'firstdayofweek'    =>  get_string('firstdayofweek', 'langconfig'),
+            'mon'               => strftime('%a', 360000),      // 5th Jan 1970 at 12pm
+            'tue'               => strftime('%a', 446400),
+            'wed'               => strftime('%a', 532800),
+            'thu'               => strftime('%a', 619200),
+            'fri'               => strftime('%a', 705600),
+            'sat'               => strftime('%a', 792000),
+            'sun'               => strftime('%a', 878400),
+            'january'           => strftime('%B', 14400),       // 1st Jan 1970 at 12pm
+            'february'          => strftime('%B', 2692800),
+            'march'             => strftime('%B', 5112000),
+            'april'             => strftime('%B', 7790400),
+            'may'               => strftime('%B', 10382400),
+            'june'              => strftime('%B', 13060800),
+            'july'              => strftime('%B', 15652800),
+            'august'            => strftime('%B', 18331200),
+            'september'         => strftime('%B', 21009600),
+            'october'           => strftime('%B', 23601600),
+            'november'          => strftime('%B', 26280000),
+            'december'          => strftime('%B', 28872000)
+        ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
     }
-- 
1.7.9.5


From 881118184a3e58b28b6daccee8eda44988121a77 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 13 Jul 2012 10:08:10 +0800
Subject: [PATCH 173/903] MDL-34240 - google plugins: switch to
 PARAM_RAW_TRIMMED

This ensures the client credentials which are entered are trimmed
as users are finding problems with bad pastes.
---
 portfolio/googledocs/lib.php  |    2 ++
 portfolio/picasa/lib.php      |    2 ++
 repository/googledocs/lib.php |    2 ++
 repository/picasa/lib.php     |    2 ++
 4 files changed, 8 insertions(+)

diff --git a/portfolio/googledocs/lib.php b/portfolio/googledocs/lib.php
index 0405ba5..a7b87d0 100644
--- a/portfolio/googledocs/lib.php
+++ b/portfolio/googledocs/lib.php
@@ -108,7 +108,9 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
diff --git a/portfolio/picasa/lib.php b/portfolio/picasa/lib.php
index cbef42c..fff8760 100644
--- a/portfolio/picasa/lib.php
+++ b/portfolio/picasa/lib.php
@@ -108,7 +108,9 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_picasa', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
diff --git a/repository/googledocs/lib.php b/repository/googledocs/lib.php
index ee56c02..c3a00e1 100644
--- a/repository/googledocs/lib.php
+++ b/repository/googledocs/lib.php
@@ -119,7 +119,9 @@ class repository_googledocs extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
diff --git a/repository/picasa/lib.php b/repository/picasa/lib.php
index 7dbdf7b..10a78e7 100644
--- a/repository/picasa/lib.php
+++ b/repository/picasa/lib.php
@@ -121,7 +121,9 @@ class repository_picasa extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
-- 
1.7.9.5


From 7bef3664b8a435b36c27809a74ed2390be70961f Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 6 Jul 2012 12:20:01 +0100
Subject: [PATCH 174/903] MDL-23219 check permissions: show relevant
 role-assignments.

Adding this list of role assignments should make it much easier for
admins to work out why, when the permissions shown in the check
permisisons page are now what they expect.

I thought about making the links go more directly to, for example, the
assign roles pages for each context, but because of things like
enrolments in courses that is hard. It is only two clicks to go to the
context, then click the right link in the settings block there.

I also re-orderd some of the code in check.php to try to get all the DB
code before all the output code.
---
 admin/roles/check.php |   35 ++++++++++++++++++++++++++-----
 lang/en/role.php      |    2 ++
 lib/accesslib.php     |   56 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/admin/roles/check.php b/admin/roles/check.php
index 1f6f6ac..470159e 100644
--- a/admin/roles/check.php
+++ b/admin/roles/check.php
@@ -104,20 +104,45 @@ switch ($context->contextlevel) {
         break;
 }
 
+// Get the list of the reported-on user's role assignments - must be after
+// the page setup code above, or the language might be wrong.
+$reportuser = $userselector->get_selected_user();
+if (!is_null($reportuser)) {
+    $roleassignments = get_user_roles_with_special($context, $reportuser->id);
+    $rolenames = role_get_names($context);
+}
+
 echo $OUTPUT->header();
-// These are needed early because of tabs.php
-$assignableroles = get_assignable_roles($context, ROLENAME_BOTH);
-$overridableroles = get_overridable_roles($context, ROLENAME_BOTH);
 
 // Print heading.
 echo $OUTPUT->heading($title);
 
 // If a user has been chosen, show all the permissions for this user.
-$reportuser = $userselector->get_selected_user();
 if (!is_null($reportuser)) {
     echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
-    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
 
+    if (!empty($roleassignments)) {
+        echo $OUTPUT->heading(get_string('rolesforuser', 'role', fullname($reportuser)), 3);
+        echo html_writer::start_tag('ul');
+
+        $systemcontext = context_system::instance();
+        foreach ($roleassignments as $ra) {
+            $racontext = context::instance_by_id($ra->contextid);
+            $link = html_writer::link($racontext->get_url(), $racontext->get_context_name());
+
+            $rolename = $rolenames[$ra->roleid]->localname;
+            if (has_capability('moodle/role:manage', $systemcontext)) {
+                $rolename = html_writer::link(new moodle_url('/admin/roles/define.php',
+                        array('action' => 'view', 'roleid' => $ra->roleid)), $rolename);
+            }
+
+            echo html_writer::tag('li', get_string('roleincontext', 'role',
+                    array('role' => $rolename, 'context' => $link)));
+        }
+        echo html_writer::end_tag('ul');
+    }
+
+    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
     $table = new check_capability_table($context, $reportuser, $contextname);
     $table->display();
     echo $OUTPUT->box_end();
diff --git a/lang/en/role.php b/lang/en/role.php
index a8058ad..ffbdec3 100644
--- a/lang/en/role.php
+++ b/lang/en/role.php
@@ -301,6 +301,7 @@ $string['role:assign'] = 'Assign roles to users';
 $string['roleassignments'] = 'Role assignments';
 $string['roledefinitions'] = 'Role definitions';
 $string['rolefullname'] = 'Role name';
+$string['roleincontext'] = '{$a->role} in {$a->context}';
 $string['role:manage'] = 'Create and manage roles';
 $string['role:override'] = 'Override permissions for others';
 $string['role:review'] = 'Review permissions for others';
@@ -311,6 +312,7 @@ $string['roles_help'] = 'A role is a collection of permissions defined for the w
 $string['roles_link'] = 'roles';
 $string['role:safeoverride'] = 'Override safe permissions for others';
 $string['roleselect'] = 'Select role';
+$string['rolesforuser'] = 'Roles for user {$a}';
 $string['roleshortname'] = 'Short name';
 $string['role:switchroles'] = 'Switch to other roles';
 $string['roletoassign'] = 'Role to assign';
diff --git a/lib/accesslib.php b/lib/accesslib.php
index de180b4..b8aa9f9 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -3021,6 +3021,53 @@ function get_user_roles(context $context, $userid = 0, $checkparentcontexts = tr
 }
 
 /**
+ * Like get_user_roles, but adds in the authenticated user role, and the front
+ * page roles, if applicable.
+ *
+ * @param context $context the context.
+ * @param int $userid optional. Defaults to $USER->id
+ * @return array of objects with fields ->userid, ->contextid and ->roleid.
+ */
+function get_user_roles_with_special(context $context, $userid = 0) {
+    global $CFG, $USER;
+
+    if (empty($userid)) {
+        if (empty($USER->id)) {
+            return array();
+        }
+        $userid = $USER->id;
+    }
+
+    $ras = get_user_roles($context, $userid);
+
+    // Add front-page role if relevant.
+    $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : 0;
+    $isfrontpage = ($context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID) ||
+            is_inside_frontpage($context);
+    if ($defaultfrontpageroleid && $isfrontpage) {
+        $frontpagecontext = context_course::instance(SITEID);
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $frontpagecontext->id;
+        $ra->roleid = $defaultfrontpageroleid;
+        $ras[] = $ra;
+    }
+
+    // Add authenticated user role if relevant.
+    $defaultuserroleid      = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : 0;
+    if ($defaultuserroleid && !isguestuser($userid)) {
+        $systemcontext = context_system::instance();
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $systemcontext->id;
+        $ra->roleid = $defaultuserroleid;
+        $ras[] = $ra;
+    }
+
+    return $ras;
+}
+
+/**
  * Creates a record in the role_allow_override table
  *
  * @param int $sroleid source roleid
@@ -4137,6 +4184,15 @@ function role_get_name($role, context_course $coursecontext) {
 }
 
 /**
+ * Get all the localised role names for a context.
+ * @param context $context the context
+ * @param array of role objects with a ->localname field containing the context-specific role name.
+ */
+function role_get_names(context $context) {
+    return role_fix_names(get_all_roles(), $context);
+}
+
+/**
  * Prepare list of roles for display, apply aliases and format text
  *
  * @param array $roleoptions array roleid => rolename or roleid => roleobject
-- 
1.7.9.5


From e9879c02c68619fb5b4ea09a2d0e907566ddafc5 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 13 Jul 2012 18:02:20 +0100
Subject: [PATCH 175/903] MDL-34257 quiz 'secure' window: does not close
 automatically.

---
 mod/quiz/module.js    |    2 +-
 mod/quiz/renderer.php |    4 ++--
 mod/quiz/version.php  |    2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/mod/quiz/module.js b/mod/quiz/module.js
index c1bec7f..89fa16a 100644
--- a/mod/quiz/module.js
+++ b/mod/quiz/module.js
@@ -275,7 +275,7 @@ M.mod_quiz.secure_window = {
         }, '#secureclosebutton');
     },
 
-    close: function(url, delay) {
+    close: function(Y, url, delay) {
         setTimeout(function() {
             if (window.opener) {
                 window.opener.document.location.reload();
diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php
index 165ec10..391fc90 100644
--- a/mod/quiz/renderer.php
+++ b/mod/quiz/renderer.php
@@ -509,8 +509,8 @@ class mod_quiz_renderer extends plugin_renderer_base {
             $output .= html_writer::tag('p', get_string('pleaseclose', 'quiz'));
             $delay = 0;
         }
-        $this->page->requires->js_function_call('M.mod_quiz.secure_window.close',
-                array($url, $delay));
+        $this->page->requires->js_init_call('M.mod_quiz.secure_window.close',
+                array($url, $delay), false, quiz_get_js_module());
 
         $output .= $this->box_end();
         $output .= $this->footer();
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index aa9e48d..03f42f1 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX).
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX).
 $module->requires  = 2012061700;    // Requires this Moodle version.
 $module->component = 'mod_quiz';       // Full name of the plugin (used for diagnostics).
 $module->cron      = 60;
-- 
1.7.9.5


From 04de7affb6f43aaea6f14e1d25ed9872860bb430 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Sat, 14 Jul 2012 09:06:07 +0100
Subject: [PATCH 176/903] MDL-34164 quiz reports: only try to show graphs if
 GD is installed.

if (empty($CFG->gdversion)) { seems to be the common idiom for this.
I refactored the graph output into the renderer, to avoid having to
duplicate that test three times.
---
 mod/quiz/renderer.php                 |   18 ++++++++++++++++++
 mod/quiz/report/overview/report.php   |   21 ++++++++-------------
 mod/quiz/report/statistics/report.php |    9 ++++-----
 3 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php
index 165ec10..b7961aa 100644
--- a/mod/quiz/renderer.php
+++ b/mod/quiz/renderer.php
@@ -1149,6 +1149,24 @@ class mod_quiz_renderer extends plugin_renderer_base {
                 'id' => $cm->id, 'mode' => quiz_report_default_report($context)));
         return html_writer::link($url, $summary);
     }
+
+    /**
+     * Output a graph, or a message saying that GD is required.
+     * @param moodle_url $url the URL of the graph.
+     * @param string $title the title to display above the graph.
+     * @return string HTML fragment for the graph.
+     */
+    public function graph(moodle_url $url, $title) {
+        global $CFG;
+
+        if (empty($CFG->gdversion)) {
+            $graph = get_string('gdneed');
+        } else {
+            $graph = html_writer::empty_tag('img', array('src' => $url, 'alt' => $title));
+        }
+
+        return $this->heading($title) . html_writer::tag('div', $graph, array('class' => 'graph'));
+    }
 }
 
 class mod_quiz_links_to_other_attempts implements renderable {
diff --git a/mod/quiz/report/overview/report.php b/mod/quiz/report/overview/report.php
index ae2e1f6..27b4df5 100644
--- a/mod/quiz/report/overview/report.php
+++ b/mod/quiz/report/overview/report.php
@@ -40,7 +40,7 @@ require_once($CFG->dirroot . '/mod/quiz/report/overview/overview_table.php');
 class quiz_overview_report extends quiz_attempts_report {
 
     public function display($quiz, $cm, $course) {
-        global $CFG, $DB, $OUTPUT;
+        global $CFG, $DB, $OUTPUT, $PAGE;
 
         list($currentgroup, $students, $groupstudents, $allowed) =
                 $this->init('overview', 'quiz_overview_settings_form', $quiz, $cm, $course);
@@ -237,30 +237,25 @@ class quiz_overview_report extends quiz_attempts_report {
         }
 
         if (!$table->is_downloading() && $options->usercanseegrades) {
+            $output = $PAGE->get_renderer('mod_quiz');
             if ($currentgroup && $groupstudents) {
                 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
                 $params[] = $quiz->id;
                 if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?",
                         $params)) {
-                     $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                    $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                             array('id' => $quiz->id, 'groupid' => $currentgroup));
-                     $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
+                    $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
                             groups_get_group_name($currentgroup));
-                     echo $OUTPUT->heading($graphname);
-                     echo html_writer::tag('div', html_writer::empty_tag('img',
-                            array('src' => $imageurl, 'alt' => $graphname)),
-                            array('class' => 'graph'));
+                    echo $output->graph($imageurl, $graphname);
                 }
             }
 
             if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) {
-                 $graphname = get_string('overviewreportgraph', 'quiz_overview');
-                 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                         array('id' => $quiz->id));
-                 echo $OUTPUT->heading($graphname);
-                 echo html_writer::tag('div', html_writer::empty_tag('img',
-                        array('src' => $imageurl, 'alt' => $graphname)),
-                        array('class' => 'graph'));
+                $graphname = get_string('overviewreportgraph', 'quiz_overview');
+                echo $output->graph($imageurl, $graphname);
             }
         }
         return true;
diff --git a/mod/quiz/report/statistics/report.php b/mod/quiz/report/statistics/report.php
index 99cbd31..48c91ee 100644
--- a/mod/quiz/report/statistics/report.php
+++ b/mod/quiz/report/statistics/report.php
@@ -579,18 +579,17 @@ class quiz_statistics_report extends quiz_default_report {
      * @param int $quizstatsid the id of the statistics to show in the graph.
      */
     protected function output_statistics_graph($quizstatsid, $s) {
-        global $OUTPUT;
+        global $PAGE;
 
         if ($s == 0) {
             return;
         }
 
+        $output = $PAGE->get_renderer('mod_quiz');
         $imageurl = new moodle_url('/mod/quiz/report/statistics/statistics_graph.php',
                 array('id' => $quizstatsid));
-        $OUTPUT->heading(get_string('statisticsreportgraph', 'quiz_statistics'));
-        echo html_writer::tag('div', html_writer::empty_tag('img', array('src' => $imageurl,
-                'alt' => get_string('statisticsreportgraph', 'quiz_statistics'))),
-                array('class' => 'graph'));
+        $graphname = get_string('statisticsreportgraph', 'quiz_statistics');
+        echo $output->graph($imageurl, $graphname);
     }
 
     /**
-- 
1.7.9.5


From beae8b9888c630ed612ec03c90bb6ee33e2298ee Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sun, 15 Jul 2012 00:32:02 +0000
Subject: [PATCH 177/903] Automatically generated installer lang files

---
 install/lang/is/admin.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/is/admin.php b/install/lang/is/admin.php
index 1b5f34a..9bae23d 100644
--- a/install/lang/is/admin.php
+++ b/install/lang/is/admin.php
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 'j';
+$string['cliincorrectvalueerror'] = 'Villa, ótækt gildi "{$a->value}" fyrir "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Rangt gildi, vinsamlegast reyndu aftur';
 $string['clitypevalue'] = 'Sláðu inn gildi';
 $string['clitypevaluedefault'] = 'Sláðu inn gildi, sláðu á Enter hnappinn á lyklaborðinu til að nota sjálfgefið gildi ({$a})';
-- 
1.7.9.5


From e7bf0155f7ce189f65e668d487b56a2baa43bf40 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Wed, 11 Jul 2012 21:19:59 +0100
Subject: [PATCH 178/903] MDL-33874 Allow form fields to be ignored by the
 formchangechecker

---
 lib/yui/formchangechecker/formchangechecker.js |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/yui/formchangechecker/formchangechecker.js b/lib/yui/formchangechecker/formchangechecker.js
index dc819aa..a4fa15b 100644
--- a/lib/yui/formchangechecker/formchangechecker.js
+++ b/lib/yui/formchangechecker/formchangechecker.js
@@ -88,7 +88,11 @@ YUI.add('moodle-core-formchangechecker',
         /**
          * Set the form changed state to true
          */
-        M.core_formchangechecker.set_form_changed = function() {
+        M.core_formchangechecker.set_form_changed = function(e) {
+            if (e.target.hasClass('ignoredirty')) {
+                // Don't warn on elements with the ignoredirty class
+                return;
+            }
             M.core_formchangechecker.stateinformation.formchanged = 1;
 
             // Once the form has been marked as dirty, we no longer need to keep track of form elements
-- 
1.7.9.5


From bf79f77357f70cbe0356e08631744ec8764abfc0 Mon Sep 17 00:00:00 2001
From: Ashley Holman <ashley@netspot.com.au>
Date: Thu, 12 Jul 2012 23:18:51 +0930
Subject: [PATCH 179/903] MDL-34309: Fix broken postgres unix sockets in
 core_adodb_testcase::test_read_table

---
 enrol/database/tests/adodb_test.php |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/enrol/database/tests/adodb_test.php b/enrol/database/tests/adodb_test.php
index 2336d53..7f30c07 100644
--- a/enrol/database/tests/adodb_test.php
+++ b/enrol/database/tests/adodb_test.php
@@ -70,7 +70,11 @@ class core_adodb_testcase extends advanced_testcase {
                 set_config('dbsetupsql', 'SET NAMES \'UTF-8\'', 'enrol_database');
                 set_config('dbsybasequoting', '0', 'enrol_database');
                 if (!empty($CFG->dboptions['dbsocket']) and ($CFG->dbhost === 'localhost' or $CFG->dbhost === '127.0.0.1')) {
-                    set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    if (strpos($CFG->dboptions['dbsocket'], '/') !== false) {
+                      set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    } else {
+                      set_config('dbhost', '', 'enrol_database');
+                    }
                 }
                 break;
 
-- 
1.7.9.5


From b831bcc2be6ff875a68477af0d7f91dadfa0c7b0 Mon Sep 17 00:00:00 2001
From: Barbara Ramiro <barbara@moodle.com>
Date: Thu, 12 Jul 2012 20:00:23 +0800
Subject: [PATCH 180/903] MDL-33841 Min-height set to remove unnecessary
 scrollbar on tree and list view

---
 theme/base/style/filemanager.css |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 836233a..5fbacc3 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -290,7 +290,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
-.filemanager .fp-content{overflow: auto;max-height: 472px;}
+.filemanager .fp-content{overflow: auto;max-height: 472px;min-height: 157px;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
 
 /*
-- 
1.7.9.5


From 4b791f1d17f9943c0bcacf41c3927d9de0e22c79 Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Mon, 2 Jul 2012 13:04:39 -0700
Subject: [PATCH 181/903] MDL-27563 shibboleth: set context on login page

---
 auth/shibboleth/login.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/auth/shibboleth/login.php b/auth/shibboleth/login.php
index ee3372f..6f984c5 100644
--- a/auth/shibboleth/login.php
+++ b/auth/shibboleth/login.php
@@ -63,6 +63,7 @@ $PAGE->https_required();
     $loginsite = get_string("loginsite");
 
     $PAGE->set_url('/auth/shibboleth/login.php');
+    $PAGE->set_context(context_system::instance());
     $PAGE->navbar->add($loginsite);
     $PAGE->set_title("$site->fullname: $loginsite");
     $PAGE->set_heading($site->fullname);
-- 
1.7.9.5


From 66681a5192e88693418a9917b719df28733f6560 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Wed, 11 Jul 2012 08:31:56 +0800
Subject: [PATCH 182/903] MDL-34258: Plagiarism API now returns strings so
 mod_assign needs these updates

---
 mod/assign/locallib.php |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 2fef79b..85ff77e 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -1744,7 +1744,7 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            plagiarism_update_status($this->get_course(), $this->get_course_module());
+            $o .= plagiarism_update_status($this->get_course(), $this->get_course_module());
         }
 
         $actionformtext = $this->output->render($gradingactions);
@@ -1808,11 +1808,8 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            ob_start();
 
-            plagiarism_print_disclosure($this->get_course_module()->id);
-            $o = ob_get_contents();
-            ob_end_clean();
+            $o .= plagiarism_print_disclosure($this->get_course_module()->id);
         }
 
         return $o;
-- 
1.7.9.5


From f8e493faff5f694d665afbf9e4ec2a496df42f01 Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Sat, 7 Jul 2012 18:56:42 +0100
Subject: [PATCH 183/903] MDL-34214 Course dndupload - removed unneeded
 classes from preview element

---
 course/dndupload.js         |    2 +-
 theme/base/style/course.css |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/dndupload.js b/course/dndupload.js
index 4651120..7bfef1d 100644
--- a/course/dndupload.js
+++ b/course/dndupload.js
@@ -514,7 +514,7 @@ M.course_dndupload = {
             namespan: document.createElement('span')
         };
 
-        preview.li.className = 'dndupload-preview activity resource modtype_resource dndupload-hidden';
+        preview.li.className = 'dndupload-preview dndupload-hidden';
 
         preview.div.className = 'mod-indent';
         preview.li.appendChild(preview.div);
diff --git a/theme/base/style/course.css b/theme/base/style/course.css
index 09dc4b2..d073270 100644
--- a/theme/base/style/course.css
+++ b/theme/base/style/course.css
@@ -167,7 +167,7 @@ input.titleeditor {
 
 /* Course drag and drop upload styles */
 #dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;z-index: 0;}
-.dndupload-preview {color:#909090;border:1px dashed #909090;}
+.dndupload-preview {color:#909090;border:1px dashed #909090;list-style:none;}
 .dndupload-progress-outer {width:70px;border:1px solid black;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
 .dndupload-progress-inner {width:0%;height:100%;background-color:green;display:inline-block;margin:0;padding:0;float:left;}
 .dndupload-hidden {display:none;}
-- 
1.7.9.5


From 28fc596d03c07eeaf8e5cd4d9fe7702b477f5437 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 16 Jul 2012 09:45:11 +0800
Subject: [PATCH 184/903] MDL-33624 lang - remove incosistent use of
 placeholder

---
 blog/index.php            |    2 +-
 course/delete.php         |    4 ++--
 course/externallib.php    |    2 +-
 enrol/authorize/index.php |    2 +-
 lang/en/error.php         |    2 +-
 mod/data/export.php       |    2 +-
 notes/externallib.php     |    2 +-
 7 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/blog/index.php b/blog/index.php
index 77476a9..c008427 100644
--- a/blog/index.php
+++ b/blog/index.php
@@ -143,7 +143,7 @@ if (!empty($groupid)) {
     }
 
     if (!$course = $DB->get_record('course', array('id'=>$group->courseid))) {
-        print_error(get_string('invalidcourseid', 'blog'));
+        print_error('invalidcourseid');
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
diff --git a/course/delete.php b/course/delete.php
index ba9c3be..ebe6b78 100644
--- a/course/delete.php
+++ b/course/delete.php
@@ -18,11 +18,11 @@
     $strcategories = get_string("categories");
 
     if (! $course = $DB->get_record("course", array("id"=>$id))) {
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
     if ($site->id == $course->id) {
         // can not delete frontpage!
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
diff --git a/course/externallib.php b/course/externallib.php
index 41c5ab4..bf43d2b 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -722,7 +722,7 @@ class core_course_external extends external_api {
         // Context validation.
 
         if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
-            throw new moodle_exception('invalidcourseid', 'error', '', $params['courseid']);
+            throw new moodle_exception('invalidcourseid', 'error');
         }
 
         // Category where duplicated course is going to be created.
diff --git a/enrol/authorize/index.php b/enrol/authorize/index.php
index 5bdee18..7b93b04 100644
--- a/enrol/authorize/index.php
+++ b/enrol/authorize/index.php
@@ -53,7 +53,7 @@
 
 /// Get course
     if (!($course = $DB->get_record('course', array('id'=>$courseid)))) {
-        print_error('invalidcourseid', '', '', $courseid);
+        print_error('invalidcourseid');
     }
 
 /// Only SITE users can access to this page
diff --git a/lang/en/error.php b/lang/en/error.php
index b40859b..7ad032c 100644
--- a/lang/en/error.php
+++ b/lang/en/error.php
@@ -280,7 +280,7 @@ $string['invalidcomponent'] = 'Invalid component name';
 $string['invalidconfirmdata'] = 'Invalid confirmation data';
 $string['invalidcontext'] = 'Invalid context';
 $string['invalidcourse'] = 'Invalid course';
-$string['invalidcourseid'] = 'You are trying to use an invalid course ID: ({$a})';
+$string['invalidcourseid'] = 'You are trying to use an invalid course ID';
 $string['invalidcourselevel'] = 'Incorrect context level';
 $string['invalidcoursemodule'] = 'Invalid course module ID';
 $string['invalidcoursenameshort'] = 'Invalid short course name';
diff --git a/mod/data/export.php b/mod/data/export.php
index 3040ef6..40fc894 100644
--- a/mod/data/export.php
+++ b/mod/data/export.php
@@ -41,7 +41,7 @@ if (! $cm = get_coursemodule_from_instance('data', $data->id, $data->course)) {
 }
 
 if(! $course = $DB->get_record('course', array('id'=>$cm->course))) {
-    print_error('invalidcourseid', '', '', $cm->course);
+    print_error('invalidcourseid');
 }
 
 // fill in missing properties needed for updating of instance
diff --git a/notes/externallib.php b/notes/externallib.php
index fc31e9b..f671042 100644
--- a/notes/externallib.php
+++ b/notes/externallib.php
@@ -110,7 +110,7 @@ class core_notes_external extends external_api {
             //check the course exists
             if (empty($courses[$note['courseid']])) {
                 $success = false;
-                $errormessage = get_string('invalidcourseid', 'notes', $note['courseid']);
+                $errormessage = get_string('invalidcourseid', 'error');
             } else {
                 // Ensure the current user is allowed to run this function
                 $context = get_context_instance(CONTEXT_COURSE, $note['courseid']);
-- 
1.7.9.5


From ae8e49e8de59d9bf8234a9aa144dc6b2ea666054 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 9 Jul 2012 10:16:21 +0800
Subject: [PATCH 185/903] MDL-34213 fixed mistype causing wrong link in some
 browsers

---
 repository/filepicker.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/repository/filepicker.js b/repository/filepicker.js
index d23f361..7c4e1f4 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -1737,7 +1737,7 @@ M.core_filepicker.init = function(Y, options) {
                 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
                 setStyle('display', 'none');
             toolbar.append(helplnk);
-            toolbar.one('.fp-tb-manage').one('a,button').
+            toolbar.one('.fp-tb-help').one('a,button').
                 on('click', function(e) {
                     e.preventDefault();
                     helplnk.simulate('click')
-- 
1.7.9.5


From 021bea1240041925193f35cada26ee7ab07e2fc1 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 16 Jul 2012 14:10:27 +0800
Subject: [PATCH 186/903] MDL-30798 Blog: link param for entries about this
 course link is fixed

---
 blocks/blog_recent/block_blog_recent.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/blocks/blog_recent/block_blog_recent.php b/blocks/blog_recent/block_blog_recent.php
index b3d564f..fe6c970 100644
--- a/blocks/blog_recent/block_blog_recent.php
+++ b/blocks/blog_recent/block_blog_recent.php
@@ -86,17 +86,20 @@ class block_blog_recent extends block_base {
 
         $context = $this->page->context;
 
+        $url = new moodle_url('/blog/index.php');
         $filter = array();
         if ($context->contextlevel == CONTEXT_MODULE) {
             $filter['module'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('modulename', $this->page->cm->modname);
             $strview = get_string('viewallmodentries', 'blog', $a);
+            $url->param('modid', $context->instanceid);
         } else if ($context->contextlevel == CONTEXT_COURSE) {
             $filter['course'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('course');
             $strview = get_string('viewblogentries', 'blog', $a);
+            $url->param('courseid', $context->instanceid);
         } else {
             $strview = get_string('viewsiteentries', 'blog');
         }
@@ -104,7 +107,6 @@ class block_blog_recent extends block_base {
 
         $bloglisting = new blog_listing($filter);
         $entries = $bloglisting->get_entries(0, $this->config->numberofrecentblogentries, 4);
-        $url = new moodle_url('/blog/index.php', $filter);
 
         if (!empty($entries)) {
             $entrieslist = array();
-- 
1.7.9.5


From 5f3d7b1949af3cf29669b8c77229077c262a9228 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Thu, 21 Jun 2012 11:03:30 +0800
Subject: [PATCH 187/903] MDL-26587 Question : fixed restoring shortanswer
 where answers are missing due to data error in mbz
 file.

---
 .../restore_qtype_shortanswer_plugin.class.php     |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php b/question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
index 5dd1e86..9f1b67b 100644
--- a/question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
+++ b/question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
@@ -68,8 +68,8 @@ class restore_qtype_shortanswer_plugin extends restore_qtype_plugin {
         $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
 
         // If the question has been created by restore, we need to create its
-        // question_shortanswer too
-        if ($questioncreated) {
+        // question_shortanswer too, if they are defined (the gui should ensure this).
+        if ($questioncreated && !empty($data->answers)) {
             // Adjust some columns
             $data->question = $newquestionid;
             // Map sequence of question_answer ids
-- 
1.7.9.5


From e52f82253e31ebe18569941587c3d7b68c95183f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Monlla=C3=B3?= <david.monllao@gmail.com>
Date: Thu, 22 Dec 2011 16:34:32 +0100
Subject: [PATCH 188/903] MDL-30876 filter_mediaplugin Wrapping the style
 sheets access with try & catch

Conflicts:

	lib/javascript-static.js
---
 lib/javascript-static.js |   26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 5640b44..66af621 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1771,15 +1771,27 @@ M.util.load_flowplayer = function() {
 
             var rule;
             for (var j=0; j < document.styleSheets.length; j++) {
-                if (typeof (document.styleSheets[j].rules) != 'undefined') {
-                    var allrules = document.styleSheets[j].rules;
-                } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
-                    var allrules = document.styleSheets[j].cssRules;
-                } else {
-                    // why??
+
+                // To avoid javascript security violation accessing cross domain stylesheets
+                var allrules = false;
+                try {
+                    if (typeof (document.styleSheets[j].rules) != 'undefined') {
+                        allrules = document.styleSheets[j].rules;
+                    } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
+                        allrules = document.styleSheets[j].cssRules;
+                    } else {
+                        // why??
+                        continue;
+                    }
+                } catch (e) {
                     continue;
                 }
-                if (!allrules) continue;
+
+                // On cross domain style sheets Chrome V8 allows access to rules but returns null
+                if (!allrules) {
+                    continue;
+                }
+
                 for(var i=0; i<allrules.length; i++) {
                     rule = '';
                     if (/^\.mp3flowplayer_.*Color$/.test(allrules[i].selectorText)) {
-- 
1.7.9.5


From b27d56ea6f069a253a76483748502e4e8b192476 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 17 Jul 2012 00:31:47 +0000
Subject: [PATCH 189/903] Automatically generated installer lang files

---
 install/lang/is/langconfig.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/is/langconfig.php b/install/lang/is/langconfig.php
index 4de4bef..bcf067a 100644
--- a/install/lang/is/langconfig.php
+++ b/install/lang/is/langconfig.php
@@ -31,4 +31,4 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['thisdirection'] = 'ltr';
-$string['thislanguage'] = '&Iacute;slenska';
+$string['thislanguage'] = 'Íslenska';
-- 
1.7.9.5


From b6e65b5312f4ae0d2d8f2daa9a6e92ffcf76611c Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 13 Jul 2012 11:40:06 +0800
Subject: [PATCH 190/903] MDL-33575 choice module: add label to checkbox
 element when privacy of results is set to publish
 full results

---
 mod/choice/renderer.php |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/mod/choice/renderer.php b/mod/choice/renderer.php
index 07bbd19..ccbb949 100644
--- a/mod/choice/renderer.php
+++ b/mod/choice/renderer.php
@@ -213,15 +213,17 @@ class mod_choice_renderer extends plugin_renderer_base {
                             $user->imagealt = '';
                         }
 
+                        $userfullname = fullname($user, $choices->fullnamecapability);
                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
-                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
+                            $attemptaction = html_writer::label($userfullname, 'attempt-user'.$user->id, false, array('class' => 'accesshide'));
+                            $attemptaction .= html_writer::checkbox('attemptid[]', $user->id,'', null, array('id' => 'attempt-user'.$user->id));
                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
                         }
                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
                         $data .= html_writer::tag('div', $userimage, array('class'=>'image'));
 
                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
-                        $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
+                        $name = html_writer::tag('a', $userfullname, array('href'=>$userlink, 'class'=>'username'));
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
                         $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
-- 
1.7.9.5


From 574cc949cd84e6f00dc2ecb4daa2e889b8465f17 Mon Sep 17 00:00:00 2001
From: Juan Leyva <juanleyvadelgado@gmail.com>
Date: Wed, 4 Jul 2012 10:34:24 +0200
Subject: [PATCH 191/903] MDL-34083 Deleted user_files from backup options

---
 course/externallib.php |    2 --
 1 file changed, 2 deletions(-)

diff --git a/course/externallib.php b/course/externallib.php
index bf43d2b..fe23d9d 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -674,7 +674,6 @@ class core_course_external extends external_api {
                                             "filters" (int) Include course filters  (default to 1 that is equal to yes),
                                             "users" (int) Include users (default to 0 that is equal to no),
                                             "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
-                                            "user_files" (int) Include user files  (default to 0 that is equal to no),
                                             "comments" (int) Include user comments  (default to 0 that is equal to no),
                                             "completion_information" (int) Include user course completion information  (default to 0 that is equal to no),
                                             "logs" (int) Include course logs  (default to 0 that is equal to no),
@@ -739,7 +738,6 @@ class core_course_external extends external_api {
             'filters' => 1,
             'users' => 0,
             'role_assignments' => 0,
-            'user_files' => 0,
             'comments' => 0,
             'completion_information' => 0,
             'logs' => 0,
-- 
1.7.9.5


From 3240c7100eb81d401e6c3f904a7b2f5acfd9ea32 Mon Sep 17 00:00:00 2001
From: Juan Leyva <juanleyvadelgado@gmail.com>
Date: Fri, 13 Jul 2012 11:31:44 +0300
Subject: [PATCH 192/903] MDL-34083 Fixing the param type also after deleting
 the invalid option

---
 course/externallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/externallib.php b/course/externallib.php
index fe23d9d..b18c0a4 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -668,7 +668,7 @@ class core_course_external extends external_api {
                 'options' => new external_multiple_structure(
                     new external_single_structure(
                         array(
-                                'name' => new external_value(PARAM_ALPHA, 'The backup option name:
+                                'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
                                             "activities" (int) Include course activites (default to 1 that is equal to yes),
                                             "blocks" (int) Include course blocks (default to 1 that is equal to yes),
                                             "filters" (int) Include course filters  (default to 1 that is equal to yes),
-- 
1.7.9.5


From 23371805ea877ee564329b9aae4bd279b0b993b7 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 17 Jul 2012 16:42:22 +0800
Subject: [PATCH 193/903] MDL-33560 Enrol: Enrol password can be unmasked

---
 enrol/self/locallib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/enrol/self/locallib.php b/enrol/self/locallib.php
index 86adfbf..a189e7d 100644
--- a/enrol/self/locallib.php
+++ b/enrol/self/locallib.php
@@ -67,7 +67,7 @@ class enrol_self_enrol_form extends moodleform {
         if ($instance->password) {
             //change the id of self enrolment key input as there can be multiple self enrolment methods
             $mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_self'),
-                    array('id' => $instance->id."_enrolpassword"));
+                    array('id' => 'enrolpassword_'.$instance->id));
         } else {
             $mform->addElement('static', 'nokey', '', get_string('nopassword', 'enrol_self'));
         }
@@ -127,4 +127,4 @@ class enrol_self_enrol_form extends moodleform {
 
         return $errors;
     }
-}
\ No newline at end of file
+}
-- 
1.7.9.5


From 371d354ab3eb85c7315c4982a800a6b217cd905e Mon Sep 17 00:00:00 2001
From: Nathan Mares <nathan@catalyst-au.net>
Date: Tue, 17 Jul 2012 19:11:57 +1000
Subject: [PATCH 194/903] MDL-34368: Fix broken query in so tokens are
 correctly checked against the linked service

---
 webservice/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/webservice/lib.php b/webservice/lib.php
index 4fac2e9..afba3a4 100644
--- a/webservice/lib.php
+++ b/webservice/lib.php
@@ -1110,7 +1110,7 @@ abstract class webservice_zend_server extends webservice_server {
                   FROM {external_services} s
                   JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1)
                   JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)
-                 WHERE s.enabled = 1 AND su.validuntil IS NULL OR su.validuntil < :now $wscond2";
+                 WHERE s.enabled = 1 AND (su.validuntil IS NULL OR su.validuntil < :now) $wscond2";
 
         $params = array_merge($params, array('userid'=>$USER->id, 'now'=>time()));
 
-- 
1.7.9.5


From 35cf43cb421821f9ff7ca98a073e5c19ace36ddd Mon Sep 17 00:00:00 2001
From: Jean-Philippe Gaudreau <jp.gaudreau@umontreal.ca>
Date: Tue, 17 Jul 2012 09:03:17 -0400
Subject: [PATCH 195/903] MDL-31516 Fixing grade_edit_tree::format_number

---
 grade/edit/tree/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index 5a268b4..eee8664 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -389,7 +389,7 @@ class grade_edit_tree {
     //Grader report has its own decimal place settings so they are handled elsewhere
     static function format_number($number) {
         $formatted = rtrim(format_float($number, 4),'0');
-        if (substr($formatted, -1)=='.') { //if last char is the decimal point
+        if (substr($formatted, -1)==get_string('decsep', 'langconfig')) { //if last char is the decimal point
             $formatted .= '0';
         }
         return $formatted;
-- 
1.7.9.5


From 483d768bc0a0bbc357c302389d4e5bad0eaabf20 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 19 Jun 2012 15:43:14 +0800
Subject: [PATCH 196/903] MDL-33767 Course: The actions on default section
 redirect to the correct section

---
 course/editsection.php     |   10 +++-------
 course/format/renderer.php |   22 +++++++++-------------
 course/lib.php             |   28 +++++++++-------------------
 3 files changed, 21 insertions(+), 39 deletions(-)

diff --git a/course/editsection.php b/course/editsection.php
index ecd905b..e4d6bea 100644
--- a/course/editsection.php
+++ b/course/editsection.php
@@ -33,9 +33,9 @@ require_once($CFG->libdir . '/conditionlib.php');
 require_once('editsection_form.php');
 
 $id = required_param('id',PARAM_INT);    // Week/topic ID
-$sectionreturn = optional_param('sectionreturn', 0, PARAM_BOOL);
+$sectionreturn = optional_param('sr', 0, PARAM_INT);
 
-$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sectionreturn'=> $sectionreturn));
+$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sr'=> $sectionreturn));
 
 $section = $DB->get_record('course_sections', array('id' => $id), '*', MUST_EXIST);
 $course = $DB->get_record('course', array('id' => $section->course), '*', MUST_EXIST);
@@ -60,11 +60,7 @@ $mform = new editsection_form($PAGE->url, array('course' => $course, 'editoropti
         'cs' => $section, 'showavailability' => $section->showavailability));
 $mform->set_data($section); // set current value
 
-if ($sectionreturn) {
-    $returnurl = course_get_url($course, $section->section);
-} else {
-    $returnurl = course_get_url($course);
-}
+$returnurl = course_get_url($course, $sectionreturn);
 
 /// If data submitted, then process and store.
 if ($mform->is_cancelled()){
diff --git a/course/format/renderer.php b/course/format/renderer.php
index b7c0e21..1fec7b2 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -122,9 +122,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param stdClass $section The course_section entry from DB
      * @param stdClass $course The course entry from DB
      * @param bool $onsectionpage true if being printed on a single-section page
+     * @param int $sectionreturn The section to return to after an action
      * @return string HTML to output.
      */
-    protected function section_header($section, $course, $onsectionpage) {
+    protected function section_header($section, $course, $onsectionpage, $sectionreturn=0) {
         global $PAGE;
 
         $o = '';
@@ -159,12 +160,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         $context = context_course::instance($course->id);
         if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
-            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id));
-
-            if ($onsectionpage) {
-                $url->param('sectionreturn', 1);
-            }
-
+            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
             $o.= html_writer::link($url,
                 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'), 'class' => 'iconsmall edit')),
                 array('title' => get_string('editsummary')));
@@ -560,10 +556,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
             echo $this->start_section_list();
-            echo $this->section_header($thissection, $course, true);
-            print_section($course, $thissection, $mods, $modnamesused, true);
+            echo $this->section_header($thissection, $course, true, $displaysection);
+            print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, $displaysection);
             if ($PAGE->user_is_editing()) {
-                print_section_add_menus($course, 0, $modnames, false, false, true);
+                print_section_add_menus($course, 0, $modnames, false, false, $displaysection);
             }
             echo $this->section_footer();
             echo $this->end_section_list();
@@ -592,14 +588,14 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         // The requested section page.
         $thissection = $sections[$displaysection];
-        echo $this->section_header($thissection, $course, true);
+        echo $this->section_header($thissection, $course, true, $displaysection);
         // Show completion help icon.
         $completioninfo = new completion_info($course);
         echo $completioninfo->display_help_icon();
 
-        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, true);
+        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, $displaysection);
         if ($PAGE->user_is_editing()) {
-            print_section_add_menus($course, $displaysection, $modnames, false, false, true);
+            print_section_add_menus($course, $displaysection, $modnames, false, false, $displaysection);
         }
         echo $this->section_footer();
         echo $this->end_section_list();
diff --git a/course/lib.php b/course/lib.php
index 0376a3a..3a2e3ad 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1376,8 +1376,9 @@ function get_print_section_cm_text(cm_info $cm, $course) {
 
 /**
  * Prints a section full of activity modules
+ * @param int $sectionreturn The section to return to
  */
-function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn = false) {
+function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=0) {
     global $CFG, $USER, $DB, $PAGE, $OUTPUT;
 
     static $initialised;
@@ -1637,12 +1638,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     $mod->groupmode = false;
                 }
                 echo '&nbsp;&nbsp;';
-
-                if ($sectionreturn) {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
-                } else {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, 0);
-                }
+                echo make_editing_buttons($mod, $absolute, true, $mod->indent, $sectionreturn);
                 echo $mod->get_after_edit_icons();
             }
 
@@ -1761,8 +1757,9 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
 
 /**
  * Prints the menus to add activities and resources.
+ * @param int $sectionreturn The section to link back to
  */
-function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn = false) {
+function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=0) {
     global $CFG, $OUTPUT;
 
     // check to see if user can add menus
@@ -1778,14 +1775,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
     $activities = array();
 
     // We need to add the section section to the link for each module
-    $sectionlink = '&section=' . $section;
-
-    // We need to add the section to return to
-    if ($sectionreturn) {
-        $sectionreturnlink = '&sr=' . $section;
-    } else {
-        $sectionreturnlink = '&sr=0';
-    }
+    $sectionlink = '&section=' . $section . '&sr=' . $sectionreturn;
 
     foreach ($modules as $module) {
         if (isset($module->types)) {
@@ -1793,7 +1783,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
             // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
             $subtypes = array();
             foreach ($module->types as $subtype) {
-                $subtypes[$subtype->link . $sectionlink . $sectionreturnlink] = $subtype->title;
+                $subtypes[$subtype->link . $sectionlink] = $subtype->title;
             }
 
             // Sort module subtypes into the list
@@ -1815,11 +1805,11 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
         } else {
             // This module has no subtypes
             if ($module->archetype == MOD_ARCHETYPE_RESOURCE) {
-                $resources[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $resources[$module->link . $sectionlink] = $module->title;
             } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) {
                 // System modules cannot be added by user, do not add to dropdown
             } else {
-                $activities[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $activities[$module->link . $sectionlink] = $module->title;
             }
         }
     }
-- 
1.7.9.5


From a64fbc87b6808d8a31a20c240415e89eccea25f7 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Fri, 29 Jun 2012 13:43:02 +0800
Subject: [PATCH 197/903] MDL-33767 Course: General section displays its title
 when required

---
 course/format/renderer.php |   10 ++++++++--
 course/lib.php             |   16 ++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index 1fec7b2..1309025 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -151,7 +151,13 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
         $o.= html_writer::start_tag('div', array('class' => 'content'));
 
-        if (!$onsectionpage) {
+        // When not on a section page, we display the section titles except the general section if null
+        $hasnamenotsecpg = (!$onsectionpage && ($section->section != 0 || !is_null($section->name)));
+
+        // When on a section page, we only display the general section title, if title is not the default one
+        $hasnamesecpg = ($onsectionpage && ($section->section == 0 && !is_null($section->name)));
+
+        if ($hasnamenotsecpg || $hasnamesecpg) {
             $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname');
         }
 
@@ -642,7 +648,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         unset($sections[0]);
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
-            echo $this->section_header($thissection, $course, true);
+            echo $this->section_header($thissection, $course, false);
             print_section($course, $thissection, $mods, $modnamesused, true);
             if ($PAGE->user_is_editing()) {
                 print_section_add_menus($course, 0, $modnames);
diff --git a/course/lib.php b/course/lib.php
index 3a2e3ad..63df417 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1376,7 +1376,16 @@ function get_print_section_cm_text(cm_info $cm, $course) {
 
 /**
  * Prints a section full of activity modules
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $mods The modules in the section
+ * @param array $modnamesused An array containing the list of modules and their names
+ * @param bool $absolute All links are absolute
+ * @param string $width Width of the container
+ * @param bool $hidecompletion Hide completion status
  * @param int $sectionreturn The section to return to
+ * @return void
  */
 function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=0) {
     global $CFG, $USER, $DB, $PAGE, $OUTPUT;
@@ -1757,7 +1766,14 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
 
 /**
  * Prints the menus to add activities and resources.
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $modnames An array containing the list of modules and their names
+ * @param bool $vertical Vertical orientation
+ * @param bool $return Return the menus or send them to output
  * @param int $sectionreturn The section to link back to
+ * @return void|string depending on $return
  */
 function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=0) {
     global $CFG, $OUTPUT;
-- 
1.7.9.5


From 8a172fa7cfb5b0eecc1fecca02d2a6a0142d18f5 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Mon, 16 Jul 2012 08:08:03 +0100
Subject: [PATCH 198/903] MDL-33874 Don't warn about focussed form fields with
 the ignoredirty class

---
 lib/yui/formchangechecker/formchangechecker.js |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/yui/formchangechecker/formchangechecker.js b/lib/yui/formchangechecker/formchangechecker.js
index a4fa15b..5c46983 100644
--- a/lib/yui/formchangechecker/formchangechecker.js
+++ b/lib/yui/formchangechecker/formchangechecker.js
@@ -43,6 +43,10 @@ YUI.add('moodle-core-formchangechecker',
                  * get_form_dirty_state function later.
                  */
                 store_initial_value : function(e) {
+                    if (e.target.hasClass('ignoredirty')) {
+                        // Don't warn on elements with the ignoredirty class
+                        return;
+                    }
                     if (M.core_formchangechecker.get_form_dirty_state()) {
                         // Clear the store_initial_value listeners as the form is already dirty so
                         // we no longer need to call this function
-- 
1.7.9.5


From 00cfd8bc947d4f799e04b2f706fdd3604b55b8f6 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 13:21:16 +0800
Subject: [PATCH 199/903] MDL-34217: Swap short and long text for setting in
 assignment module

---
 mod/assign/settings.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/assign/settings.php b/mod/assign/settings.php
index 187bc9a..95e2cfb 100644
--- a/mod/assign/settings.php
+++ b/mod/assign/settings.php
@@ -50,8 +50,8 @@ if ($ADMIN->fulltree) {
 
     // The default here is feedback_comments (if it exists)
     $settings->add(new admin_setting_configselect('assign/feedback_plugin_for_gradebook',
-                   new lang_string('feedbackpluginforgradebook', 'mod_assign'),
-                   new lang_string('feedbackplugin', 'mod_assign'), 'assignfeedback_comments', $menu));
+                   new lang_string('feedbackplugin', 'mod_assign'),
+                   new lang_string('feedbackpluginforgradebook', 'mod_assign'), 'assignfeedback_comments', $menu));
     $settings->add(new admin_setting_configcheckbox('assign/showrecentsubmissions',
                    new lang_string('showrecentsubmissions', 'assign'),
                    new lang_string('configshowrecentsubmissions', 'assign'), 0));
-- 
1.7.9.5


From 617c624732c142e1f7879a22db942a23c3fb0579 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 12:01:38 +0800
Subject: [PATCH 200/903] MDL-32948: Improved help for "Require students click
 submit button" setting

Describes the effect of changing this setting after students have submitted.
---
 mod/assign/lang/en/assign.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index 251cff5..47b6d89 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -206,7 +206,7 @@ $string['sendsubmissionreceipts_help'] = 'This switch will enable submission rec
 $string['settings'] = 'Assignment settings';
 $string['showrecentsubmissions'] = 'Show recent submissions';
 $string['submissiondrafts'] = 'Require students click submit button';
-$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system.';
+$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system. If this setting is changed from "No" to "Yes" after students have already submitted those submissions will be regarded as final.';
 $string['submissionnotready'] = 'This assignment is not ready to submit:';
 $string['submissionplugins'] = 'Submission plugins';
 $string['submissionreceipts'] = 'Send submission receipts';
-- 
1.7.9.5


From cfe170e4303f860eace6d8697469f2181f9b5def Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Thu, 5 Jul 2012 11:52:30 +0800
Subject: [PATCH 201/903] MDL-13629 grade: added some unit tests to clarify
 the handling of droplow and improved
 apply_limit_rules()

---
 lib/grade/grade_category.php            |   60 +++++++++++++++++++++++-----
 lib/grade/tests/grade_category_test.php |   66 +++++++++++++++++++++++++++++--
 2 files changed, 114 insertions(+), 12 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index ca67450..95b99f8 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -878,22 +878,64 @@ class grade_category extends grade_object {
             asort($grade_values, SORT_NUMERIC);
             $dropped = 0;
 
-            foreach ($grade_values as $itemid=>$value) {
+            // If we have fewer grade items available to drop than $this->droplow, use this flag to escape the loop
+            // May occur because of "extra credit" or if droplow is higher than the number of grade items
+            $droppedsomething = true;
 
-                if ($dropped < $this->droplow) {
+            while ($dropped < $this->droplow && $droppedsomething) {
+                $droppedsomething = false;
 
-                    if ($extraused and $items[$itemid]->aggregationcoef > 0) {
-                        // no drop low for extra credits
+                $grade_keys = array_keys($grade_values);
+                if (count($grade_keys) === 0) {
+                    //We've dropped all grade items
+                    break;
+                }
 
-                    } else {
-                        unset($grade_values[$itemid]);
-                        $dropped++;
+                $originalindex = $founditemid = $foundmax = null;
+
+                // Find the first remaining grade item that is available to be dropped
+                foreach ($grade_keys as $gradekeyindex=>$gradekey) {
+                    if (!$extraused || $items[$gradekey]->aggregationcoef <= 0) {
+                        // Found a non-extra credit grade item that is eligible to be dropped
+                        $originalindex = $gradekeyindex;
+                        $founditemid = $grade_keys[$originalindex];
+                        $foundmax = $items[$founditemid]->grademax;
+                        break;
                     }
+                }
 
-                } else {
-                    // we have dropped enough
+                if (empty($founditemid)) {
+                    // No grade items available to drop
                     break;
                 }
+
+                $i = 1;
+                while ($originalindex+$i < count($grade_keys)) {
+                    $possibleitemid = $grade_keys[$originalindex+$i];
+                    if ($grade_values[$founditemid] != $grade_values[$possibleitemid]) {
+                        // The next grade item has a different grade. Stop looking.
+                        break;
+                    }
+
+                    if ($extraused && $items[$possibleitemid]->aggregationcoef > 0) {
+                        // Don't drop extra credit grade items. Continue the search.
+                        continue;
+                    }
+
+                    if ($foundmax < $items[$possibleitemid]->grademax) {
+                        // Found a grade item with the same grade and a higher grademax
+                        $foundmax = $items[$possibleitemid]->grademax;
+                        $founditemid = $possibleitemid;
+                        // Continue searching to see if there is an even higher grademax...
+                    }
+
+                    $i++;
+                }
+
+                // Now drop whatever grade item we have found
+                unset($grade_values[$founditemid]);
+                $dropped++;
+                $droppedsomething = true;
             }
 
         } else if (!empty($this->keephigh)) {
diff --git a/lib/grade/tests/grade_category_test.php b/lib/grade/tests/grade_category_test.php
index 102ef86..727e698 100644
--- a/lib/grade/tests/grade_category_test.php
+++ b/lib/grade/tests/grade_category_test.php
@@ -406,6 +406,7 @@ class grade_category_testcase extends grade_base_testcase {
         $items[$this->grade_items[2]->id] = new grade_item($this->grade_items[2], false);
         $items[$this->grade_items[4]->id] = new grade_item($this->grade_items[4], false);
 
+        // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades
         $category = new grade_category();
         $category->droplow = 2;
         $grades = array($this->grade_items[0]->id=>5.374,
@@ -417,6 +418,7 @@ class grade_category_testcase extends grade_base_testcase {
         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
         $this->assertEquals($grades[$this->grade_items[4]->id], 7.3754);
 
+        // Test aggregating only the highest 1 out of 4 grades
         $category = new grade_category();
         $category->keephigh = 1;
         $category->droplow = 0;
@@ -429,25 +431,28 @@ class grade_category_testcase extends grade_base_testcase {
         $grade = reset($grades);
         $this->assertEquals(9.4743, $grade);
 
+        // Test excluding the lowest 2 out of 4 grades from aggregation with no 0 grades
+        // An extra credit grade item should be kept even if droplow means it would otherwise be excluded
         $category = new grade_category();
         $category->droplow     = 2;
         $category->aggregation = GRADE_AGGREGATE_SUM;
-        $items[$this->grade_items[2]->id]->aggregationcoef = 1;
+        $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit"
         $grades = array($this->grade_items[0]->id=>5.374,
                         $this->grade_items[1]->id=>9.4743,
                         $this->grade_items[2]->id=>2.5474,
                         $this->grade_items[4]->id=>7.3754);
-
         $category->apply_limit_rules($grades, $items);
         $this->assertEquals(count($grades), 2);
         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
         $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
 
+        // Test only aggregating the highest 1 out of 4 grades
+        // An extra credit grade item is retained in addition to the highest grade
         $category = new grade_category();
         $category->keephigh = 1;
         $category->droplow = 0;
         $category->aggregation = GRADE_AGGREGATE_SUM;
-        $items[$this->grade_items[2]->id]->aggregationcoef = 1;
+        $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit"
         $grades = array($this->grade_items[0]->id=>5.374,
                         $this->grade_items[1]->id=>9.4743,
                         $this->grade_items[2]->id=>2.5474,
@@ -456,6 +461,61 @@ class grade_category_testcase extends grade_base_testcase {
         $this->assertEquals(count($grades), 2);
         $this->assertEquals($grades[$this->grade_items[1]->id], 9.4743);
         $this->assertEquals($grades[$this->grade_items[2]->id], 2.5474);
+
+
+        // Test excluding the lowest 1 out of 4 grades from aggregation with two 0 grades
+        $items[$this->grade_items[2]->id]->aggregationcoef = 0; // Undo marking grade item 2 as "extra credit"
+        $category = new grade_category();
+        $category->droplow     = 1;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>5, // 5 out of 100
+                        $this->grade_items[2]->id=>2, // 0 out of 6
+                        $this->grade_items[4]->id=>0); // 0 out of 100
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 3);
+        $this->assertEquals($grades[$this->grade_items[1]->id], 5);
+        $this->assertEquals($grades[$this->grade_items[2]->id], 2);
+        $this->assertEquals($grades[$this->grade_items[4]->id], 0);
+
+        // Test excluding the lowest 2 out of 4 grades from aggregation with three 0 grades
+        $category = new grade_category();
+        $category->droplow     = 2;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>5, // 5 out of 100
+                        $this->grade_items[2]->id=>0, // 0 out of 6
+                        $this->grade_items[4]->id=>0); // 0 out of 100. Should be excluded from aggregation.
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 2);
+        $this->assertEquals($grades[$this->grade_items[1]->id], 5);
+        $this->assertEquals($grades[$this->grade_items[2]->id], 0);
+
+        // Test excluding the lowest 5 out of 4 grades from aggregation
+        // Just to check we handle this sensibly
+        $category = new grade_category();
+        $category->droplow     = 5;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>5, // 5 out of 100
+                        $this->grade_items[2]->id=>6, // 6 out of 6
+                        $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation.
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 0);
+
+        // Test excluding the lowest 4 out of 4 grades from aggregation with one marked as extra credit
+        $category = new grade_category();
+        $category->droplow     = 4;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $items[$this->grade_items[2]->id]->aggregationcoef = 1; // Mark grade item 2 as "extra credit"
+        $grades = array($this->grade_items[0]->id=>0, // 0 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>5, // 5 out of 100. Should be excluded from aggregation.
+                        $this->grade_items[2]->id=>6, // 6 out of 6. Extra credit. Should be retained.
+                        $this->grade_items[4]->id=>1);// 1 out of 100. Should be excluded from aggregation.
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 1);
+        $this->assertEquals($grades[$this->grade_items[2]->id], 6);
+
     }
 
     /**
-- 
1.7.9.5


From dec465b3e9e2c930143b050dba5b1b0fa5832ba6 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 17 Jul 2012 10:15:14 +0800
Subject: [PATCH 202/903] MDL-32665 mod_chat: disabled popup notifications in
 the chat windows

---
 mod/chat/gui_ajax/index.php  |    1 +
 mod/chat/gui_basic/index.php |    1 +
 2 files changed, 2 insertions(+)

diff --git a/mod/chat/gui_ajax/index.php b/mod/chat/gui_ajax/index.php
index 6955693..db7f340 100644
--- a/mod/chat/gui_ajax/index.php
+++ b/mod/chat/gui_ajax/index.php
@@ -11,6 +11,7 @@ if ($groupid !== 0) {
     $url->param('groupid', $groupid);
 }
 $PAGE->set_url($url);
+$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window
 
 $chat = $DB->get_record('chat', array('id'=>$id), '*', MUST_EXIST);
 $course = $DB->get_record('course', array('id'=>$chat->course), '*', MUST_EXIST);
diff --git a/mod/chat/gui_basic/index.php b/mod/chat/gui_basic/index.php
index 82e02cb..aa79bd5 100644
--- a/mod/chat/gui_basic/index.php
+++ b/mod/chat/gui_basic/index.php
@@ -44,6 +44,7 @@ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
 require_login($course, false, $cm);
 require_capability('mod/chat:chat', $context);
 $PAGE->set_pagelayout('base');
+$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window
 
 /// Check to see if groups are being used here
  if ($groupmode = groups_get_activity_groupmode($cm)) {   // Groups are being used
-- 
1.7.9.5


From fece4fd6482afb6499481200f884ca74f319820f Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 18 Jul 2012 10:32:46 +1200
Subject: [PATCH 203/903] MDL-34374 SCORM prevent skipview being set to always
 when used inside a SCORM course format.

---
 mod/scorm/locallib.php |   10 +++++++---
 mod/scorm/mod_form.php |    9 ++++++++-
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php
index c48c467..6021912 100644
--- a/mod/scorm/locallib.php
+++ b/mod/scorm/locallib.php
@@ -22,6 +22,10 @@ define('SCORM_UPDATE_NEVER', '0');
 define('SCORM_UPDATE_EVERYDAY', '2');
 define('SCORM_UPDATE_EVERYTIME', '3');
 
+define('SCORM_SKIPVIEW_NEVER', '0');
+define('SCORM_SKIPVIEW_FIRST', '1');
+define('SCORM_SKIPVIEW_ALWAYS', '2');
+
 define('SCO_ALL', 0);
 define('SCO_DATA', 1);
 define('SCO_ONLY', 2);
@@ -109,9 +113,9 @@ function scorm_get_what_grade_array() {
  * @return array an array of skip view options
  */
 function scorm_get_skip_view_array() {
-    return array(0 => get_string('never'),
-                 1 => get_string('firstaccess', 'scorm'),
-                 2 => get_string('always'));
+    return array(SCORM_SKIPVIEW_NEVER => get_string('never'),
+                 SCORM_SKIPVIEW_FIRST => get_string('firstaccess', 'scorm'),
+                 SCORM_SKIPVIEW_ALWAYS => get_string('always'));
 }
 
 /**
diff --git a/mod/scorm/mod_form.php b/mod/scorm/mod_form.php
index d558c6b..4b0837c 100644
--- a/mod/scorm/mod_form.php
+++ b/mod/scorm/mod_form.php
@@ -124,7 +124,14 @@ class mod_scorm_mod_form extends moodleform_mod {
         $mform->setAdvanced('winoptgrp', $cfg_scorm->winoptgrp_adv);
 
         // Skip view page
-        $mform->addElement('select', 'skipview', get_string('skipview', 'scorm'), scorm_get_skip_view_array());
+        $skipviewoptions = scorm_get_skip_view_array();
+        if ($COURSE->format == 'scorm') { // Remove option that would cause a constant redirect.
+            unset($skipviewoptions[SCORM_SKIPVIEW_ALWAYS]);
+            if ($cfg_scorm->skipview == SCORM_SKIPVIEW_ALWAYS) {
+                $cfg_scorm->skipview = SCORM_SKIPVIEW_FIRST;
+            }
+        }
+        $mform->addElement('select', 'skipview', get_string('skipview', 'scorm'), $skipviewoptions);
         $mform->addHelpButton('skipview', 'skipview', 'scorm');
         $mform->setDefault('skipview', $cfg_scorm->skipview);
         $mform->setAdvanced('skipview', $cfg_scorm->skipview_adv);
-- 
1.7.9.5


From 9592f5dea8f46233ab8eae05766e29f390d2bc89 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 19 Jul 2012 13:45:56 +0800
Subject: [PATCH 204/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 246fae2..1e9ff4b 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.02;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.03;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120712)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120719)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From e2bf940699cab3690332537a13bd37228c6ab35d Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 16 Jul 2012 14:54:06 +0800
Subject: [PATCH 205/903] MDL-29563 course Hide duplication button in
 activities without backup2 support - Credit to Mark
 Nielsen

---
 course/lib.php          |    4 ++--
 course/modduplicate.php |   18 ++++++++++++++----
 lang/en/moodle.php      |    1 +
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index 63df417..36ef842 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -3292,8 +3292,8 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         );
     }
 
-    // Duplicate (require both target import caps to be able to duplicate, see modduplicate.php)
-    if (has_all_capabilities($dupecaps, $coursecontext)) {
+    // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php)
+    if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) {
         $actions[] = new action_link(
             new moodle_url($baseurl, array('duplicate' => $mod->id)),
             new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall')),
diff --git a/course/modduplicate.php b/course/modduplicate.php
index e08ea35..b4d593b 100644
--- a/course/modduplicate.php
+++ b/course/modduplicate.php
@@ -56,6 +56,20 @@ $PAGE->set_pagelayout('incourse');
 
 $output = $PAGE->get_renderer('core', 'backup');
 
+$a          = new stdClass();
+$a->modtype = get_string('modulename', $cm->modname);
+$a->modname = format_string($cm->name);
+
+if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
+    echo $output->header();
+    echo $output->notification(get_string('duplicatenosupport', 'core', $a));
+    echo $output->continue_button(
+        new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id))
+    );
+    echo $output->footer();
+    die;
+}
+
 // backup the activity
 
 $bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
@@ -118,10 +132,6 @@ if (empty($CFG->keeptempdirectoriesonbackup)) {
     fulldelete($backupbasepath);
 }
 
-$a          = new stdClass();
-$a->modtype = get_string('modulename', $cm->modname);
-$a->modname = format_string($cm->name);
-
 echo $output->header();
 
 if ($newcmid) {
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index af23c90..1aae903 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -487,6 +487,7 @@ $string['duplicate'] = 'Duplicate';
 $string['duplicateconfirm'] = 'Are you sure you want to duplicate {$a->modtype} \'{$a->modname}\' ?';
 $string['duplicatecontcourse'] = 'Return to the course';
 $string['duplicatecontedit'] = 'Edit the new copy';
+$string['duplicatenosupport'] = '\'{$a->modname}\' activity could not be duplicated because the {$a->modtype} module does not support backup and restore.';
 $string['duplicatesuccess'] = '{$a->modtype} \'{$a->modname}\' has been duplicated successfully';
 $string['duplicatinga'] = 'Duplicating: {$a}';
 $string['edhelpaspellpath'] = 'To use spell-checking within the editor, you MUST have <strong>aspell 0.50</strong> or later installed on your server, and you must specify the correct path to access the aspell binary.  On Unix/Linux systems, this path is usually <strong>/usr/bin/aspell</strong>, but it might be something else.';
-- 
1.7.9.5


From da2104aa0e06fe07eb7374eecf5f00835bedac7e Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Tue, 17 Jul 2012 14:11:55 +0800
Subject: [PATCH 206/903] MDL-29563 course Throwing an exception instead of a
 message

---
 course/modduplicate.php |    9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/course/modduplicate.php b/course/modduplicate.php
index b4d593b..30c9aaf 100644
--- a/course/modduplicate.php
+++ b/course/modduplicate.php
@@ -61,13 +61,8 @@ $a->modtype = get_string('modulename', $cm->modname);
 $a->modname = format_string($cm->name);
 
 if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
-    echo $output->header();
-    echo $output->notification(get_string('duplicatenosupport', 'core', $a));
-    echo $output->continue_button(
-        new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id))
-    );
-    echo $output->footer();
-    die;
+    $url = new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id));
+    print_error('duplicatenosupport', 'core', $url, $a);
 }
 
 // backup the activity
-- 
1.7.9.5


From 001ff67298b6b8e7b76c4d7081c35d9df38f3cd8 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Mon, 16 Jul 2012 14:01:33 +1200
Subject: [PATCH 207/903] MDL-34233 SCORM backup - change to using
 set_source_sql to preserve order of records in
 backup.

---
 mod/scorm/backup/moodle2/backup_scorm_stepslib.php |   79 ++++++++++++++++----
 1 file changed, 63 insertions(+), 16 deletions(-)

diff --git a/mod/scorm/backup/moodle2/backup_scorm_stepslib.php b/mod/scorm/backup/moodle2/backup_scorm_stepslib.php
index 27862e4..5a1bf0b 100644
--- a/mod/scorm/backup/moodle2/backup_scorm_stepslib.php
+++ b/mod/scorm/backup/moodle2/backup_scorm_stepslib.php
@@ -127,25 +127,72 @@ class backup_scorm_activity_structure_step extends backup_activity_structure_ste
         // Define sources
         $scorm->set_source_table('scorm', array('id' => backup::VAR_ACTIVITYID));
 
-        $sco->set_source_table('scorm_scoes', array('scorm' => backup::VAR_PARENTID));
-
-        $scodata->set_source_table('scorm_scoes_data', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrulecond->set_source_table('scorm_seq_ruleconds', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrulecondsdata->set_source_table('scorm_seq_rulecond', array('ruleconditionsid' => backup::VAR_PARENTID));
-
-        $seqrolluprule->set_source_table('scorm_seq_rolluprule', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrolluprulecond->set_source_table('scorm_seq_rolluprulecond', array('rollupruleid' => backup::VAR_PARENTID));
-
-        $seqobjective->set_source_table('scorm_seq_objective', array('scoid' => backup::VAR_PARENTID));
-
-        $seqmapinfo->set_source_table('scorm_seq_mapinfo', array('objectiveid' => backup::VAR_PARENTID));
+        // Use set_source_sql for other calls as set_source_table returns records in reverse order
+        // and order is important for several SCORM fields - esp scorm_scoes.
+        $sco->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes}
+                WHERE scorm = :scorm
+                ORDER BY id',
+            array('scorm' => backup::VAR_PARENTID));
+
+        $scodata->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes_data}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrulecond->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_ruleconds}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrulecondsdata->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rulecond}
+                WHERE ruleconditionsid = :ruleconditionsid
+                ORDER BY id',
+            array('ruleconditionsid' => backup::VAR_PARENTID));
+
+        $seqrolluprule->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rolluprule}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrolluprulecond->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rolluprulecond}
+                WHERE rollupruleid = :rollupruleid
+                ORDER BY id',
+            array('rollupruleid' => backup::VAR_PARENTID));
+
+        $seqobjective->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_objective}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqmapinfo->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_mapinfo}
+                WHERE objectiveid = :objectiveid
+                ORDER BY id',
+            array('objectiveid' => backup::VAR_PARENTID));
 
         // All the rest of elements only happen if we are including user info
         if ($userinfo) {
-            $scotrack->set_source_table('scorm_scoes_track', array('scoid' => backup::VAR_PARENTID));
+            $scotrack->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes_track}
+                WHERE scoid = :scoid
+                ORDER BY id',
+                array('scoid' => backup::VAR_PARENTID));
         }
 
         // Define id annotations
-- 
1.7.9.5


From 8119fbd7bd11bbfe6e7b6bc63ef02584ef9242d0 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 17 Jul 2012 09:22:48 +0800
Subject: [PATCH 208/903] MDL-34265 SCORM: Removing sorting from unsortable
 columns

---
 mod/scorm/report/interactions/report.php |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/mod/scorm/report/interactions/report.php b/mod/scorm/report/interactions/report.php
index b251127..43c5395 100644
--- a/mod/scorm/report/interactions/report.php
+++ b/mod/scorm/report/interactions/report.php
@@ -221,6 +221,18 @@ class scorm_interactions_report extends scorm_default_report {
                 $table->no_sorting('finish');
                 $table->no_sorting('score');
 
+                for($id = 0; $id < $questioncount; $id++) {
+                    if ($displayoptions['qtext']) {
+                        $table->no_sorting('question'.$id);
+                    }
+                    if ($displayoptions['resp']) {
+                        $table->no_sorting('response'.$id);
+                    }
+                    if ($displayoptions['right']) {
+                        $table->no_sorting('right'.$id);
+                    }
+                }
+
                 foreach ($scoes as $sco) {
                     if ($sco->launch != '') {
                         $table->no_sorting('scograde'.$sco->id);
-- 
1.7.9.5


From 62145412bba4f73cd0a68c3f90fe645ce96ec492 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 12 Jul 2012 11:27:46 +1200
Subject: [PATCH 209/903] MDL-33448 javascript: Added caching for the YUI
 instance used for debug in get_string

---
 lib/javascript-static.js |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 66af621..463f824 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -716,7 +716,13 @@ M.util.get_string = function(identifier, component, a) {
         // creating new instance if YUI is not optimal but it seems to be better way then
         // require the instance via the function API - note that it is used in rare cases
         // for debugging only anyway
-        var Y = new YUI({ debug : true });
+        // To ensure we don't kill browser performance if hundreds of get_string requests
+        // are made we cache the instance we generate within the M.util namespace.
+        // We don't publicly define the variable so that it doesn't get abused.
+        if (typeof M.util.get_string_yui_instance === 'undefined') {
+            M.util.get_string_yui_instance = new YUI({ debug : true });
+        }
+        var Y = M.util.get_string_yui_instance;
     }
 
     if (!M.str.hasOwnProperty(component) || !M.str[component].hasOwnProperty(identifier)) {
-- 
1.7.9.5


From 36e22a820c1a22abd656ec0d4221982bafdd6e5a Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Wed, 18 Jul 2012 08:37:23 +0800
Subject: [PATCH 210/903] MDL-28568 message: added a warning message when the
 user is about to message someone who cant reply

---
 lang/en/message.php           |    3 ++-
 message/index.php             |   15 +++++++++++++--
 theme/standard/style/core.css |    1 +
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/lang/en/message.php b/lang/en/message.php
index fd25102..10c83e8 100644
--- a/lang/en/message.php
+++ b/lang/en/message.php
@@ -82,6 +82,7 @@ $string['messagehistory'] = 'Message history';
 $string['messagehistoryfull'] = 'All messages';
 $string['messages'] = 'Messages';
 $string['messaging'] = 'Messaging';
+$string['messagingblockednoncontact'] = '{$a} will not be able to reply as you have blocked non-contacts';
 $string['messagingdisabled'] = 'Messaging is disabled on this site, emails will be sent instead';
 $string['mycontacts'] = 'My contacts';
 $string['newonlymsg'] = 'Show only new';
@@ -140,5 +141,5 @@ $string['unreadnewmessage'] = 'New message from {$a}';
 $string['unreadnewnotification'] = 'New notification';
 $string['unreadnewnotifications'] = 'New notifications ({$a})';
 $string['userisblockingyou'] = 'This user has blocked you from sending messages to them';
-$string['userisblockingyounoncontact'] = 'This user is only accepting messages from people listed as contacts, and you are not currently on the list.';
+$string['userisblockingyounoncontact'] = '{$a} only accepts messages from their contacts.';
 $string['userssearchresults'] = 'Users found: {$a}';
diff --git a/message/index.php b/message/index.php
index a695b27..daaa5ff 100644
--- a/message/index.php
+++ b/message/index.php
@@ -153,7 +153,7 @@ if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage',
 
     if (!empty($userpreferences['message_blocknoncontacts'])) {  // User is blocking non-contacts
         if (empty($contact)) {   // We are not a contact!
-            $messageerror = get_string('userisblockingyounoncontact', 'message');
+            $messageerror = get_string('userisblockingyounoncontact', 'message', fullname($user2));
         }
     }
 
@@ -287,8 +287,19 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
         if ($currentuser && has_capability('moodle/site:sendmessage', $context)) {
             echo html_writer::start_tag('div', array('class' => 'mdl-align messagesend'));
                 if (!empty($messageerror)) {
-                    echo $OUTPUT->heading($messageerror, 3);
+                    echo html_writer::tag('span', $messageerror, array('id' => 'messagewarning'));
                 } else {
+                    // Display a warning if the current user is blocking non-contacts and is about to message to a non-contact
+                    // Otherwise they may wonder why they never get a reply
+                    $blocknoncontacts = get_user_preferences('message_blocknoncontacts', '', $user1->id);
+                    if (!empty($blocknoncontacts)) {
+                        $contact = $DB->get_record('message_contacts', array('userid' => $user1->id, 'contactid' => $user2->id));
+                        if (empty($contact)) {
+                            $msg = get_string('messagingblockednoncontact', 'message', fullname($user2));
+                            echo html_writer::tag('span', $msg, array('id' => 'messagewarning'));
+                        }
+                    }
+
                     $mform = new send_form();
                     $defaultmessage = new stdClass;
                     $defaultmessage->id = $user2->id;
diff --git a/theme/standard/style/core.css b/theme/standard/style/core.css
index cb73115..d3410e7 100644
--- a/theme/standard/style/core.css
+++ b/theme/standard/style/core.css
@@ -453,3 +453,4 @@ table#tag-management-list {margin: 10px auto;width: 80%;}
 #page-message-edit table.generaltable th.c0 {text-align: left;}
 #page-message-edit table.generaltable td.c0 {text-align: right;}
 #page-message-edit table.generaltable td.disallowed {text-align: center;vertical-align:middle;}
+#messagewarning {font-style:italic;}
-- 
1.7.9.5


From 0656c0a4033a4cd3d231e330d58ddccb568d0541 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 16 Jul 2012 14:30:12 +0100
Subject: [PATCH 211/903] MDL-34226 multichoice qtype: correct
 is_complete_response for multianswer

The multianswer qtype uses the multi-choice one, and the way it does its
responses array breaks an assumption that multi-choice was making.
---
 question/type/multichoice/question.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/type/multichoice/question.php b/question/type/multichoice/question.php
index f31ceb6..afca6a4 100644
--- a/question/type/multichoice/question.php
+++ b/question/type/multichoice/question.php
@@ -199,7 +199,7 @@ class qtype_multichoice_single_question extends qtype_multichoice_base {
     }
 
     public function is_complete_response(array $response) {
-        return array_key_exists('answer', $response);
+        return array_key_exists('answer', $response) && $response['answer'] !== '';
     }
 
     public function is_gradable_response(array $response) {
-- 
1.7.9.5


From 0288eb2151b017674a8978440e2e67c544130a35 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 16 Jul 2012 14:32:25 +0100
Subject: [PATCH 212/903] MDL-34226 multianswer qtype: basic unit test.

This verifies the previous fix, and gets rid of a rather embarassing TODO.
---
 question/type/multianswer/tests/helper.php         |   75 +++++++++++++++++++-
 .../type/multianswer/tests/walkthrough_test.php    |   57 ++++++---------
 2 files changed, 94 insertions(+), 38 deletions(-)

diff --git a/question/type/multianswer/tests/helper.php b/question/type/multianswer/tests/helper.php
index 90f78ef..75a3d7d 100644
--- a/question/type/multianswer/tests/helper.php
+++ b/question/type/multianswer/tests/helper.php
@@ -38,7 +38,7 @@ require_once($CFG->dirroot . '/question/type/multianswer/question.php');
  */
 class qtype_multianswer_test_helper extends question_test_helper {
     public function get_test_questions() {
-        return array('twosubq');
+        return array('twosubq', 'fourmc');
     }
 
     /**
@@ -54,6 +54,14 @@ class qtype_multianswer_test_helper extends question_test_helper {
                 'Complete this opening line of verse: "The {#1} and the {#2} went to sea".';
         $q->generalfeedback = 'General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: ' .
                 '"The owl and the pussycat went to sea';
+        $q->qtype = question_bank::get_qtype('multianswer');
+
+        $q->textfragments = array(
+            'Complete this opening line of verse: "The ',
+            ' and the ',
+            ' went to sea".',
+        );
+        $q->places = array('1' => '1', '2' => '2');
 
         // Shortanswer subquestion.
         question_bank::load_question_definition_classes('shortanswer');
@@ -214,4 +222,69 @@ class qtype_multianswer_test_helper extends question_test_helper {
 
         return $formdata;
     }
+
+    /**
+     * Makes a multianswer question about completing two blanks in some text.
+     * @return qtype_multianswer_question
+     */
+    public function make_multianswer_question_fourmc() {
+        question_bank::load_question_definition_classes('multianswer');
+        $q = new qtype_multianswer_question();
+        test_question_maker::initialise_a_question($q);
+        $q->name = 'Multianswer four multi-choice';
+        $q->questiontext = '<p>Match the following cities with the correct state:</p>
+                <ul>
+                <li>San Francisco: {#1}</li>
+                <li>Tucson: {#2}</li>
+                <li>Los Angeles: {#3}</li>
+                <li>Phoenix: {#4}</li>
+                </ul>';
+        $q->questiontextformat = FORMAT_HTML;
+        $q->generalfeedback = '';
+        $q->qtype = question_bank::get_qtype('multianswer');
+
+        $q->textfragments = array('<p>Match the following cities with the correct state:</p>
+                <ul>
+                <li>San Francisco: ', '</li>
+                <li>Tucson: ', '</li>
+                <li>Los Angeles: ', '</li>
+                <li>Phoenix: ', '</li>
+                </ul>');
+        $q->places = array('1' => '1', '2' => '2', '3' => '3', '4' => '4');
+
+        $subqdata = array(
+            1 => array('qt' => '{1:MULTICHOICE:=California#OK~Arizona#Wrong}', 'California' => 'OK', 'Arizona' => 'Wrong'),
+            2 => array('qt' => '{1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}', 'California' => 'Wrong', 'Arizona' => 'OK'),
+            3 => array('qt' => '{1:MULTICHOICE:=California#OK~Arizona#Wrong}', 'California' => 'OK', 'Arizona' => 'Wrong'),
+            4 => array('qt' => '{1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}', 'California' => 'Wrong', 'Arizona' => 'OK'),
+        );
+
+        foreach ($subqdata as $i => $data) {
+            // Multiple-choice subquestion.
+            question_bank::load_question_definition_classes('multichoice');
+            $mc = new qtype_multichoice_single_question();
+            test_question_maker::initialise_a_question($mc);
+            $mc->name = 'Multianswer four multi-choice';
+            $mc->questiontext = $data['qt'];
+            $mc->questiontextformat = FORMAT_HTML;
+            $mc->generalfeedback = '';
+            $mc->generalfeedbackformat = FORMAT_HTML;
+
+            $mc->shuffleanswers = 0; // TODO this is a cheat to make the unit tests easier to write.
+            // In reality, multianswer questions always shuffle.
+            $mc->answernumbering = 'none';
+            $mc->layout = qtype_multichoice_base::LAYOUT_DROPDOWN;
+
+            $mc->answers = array(
+                10 * $i     => new question_answer(13, 'California', $data['California'] == 'OK', $data['California'], FORMAT_HTML),
+                10 * $i + 1 => new question_answer(14, 'Arizona', $data['Arizona'] == 'OK', $data['Arizona'], FORMAT_HTML),
+            );
+            $mc->qtype = question_bank::get_qtype('multichoice');
+            $mc->maxmark = 1;
+
+            $q->subquestions[$i] = $mc;
+        }
+
+        return $q;
+    }
 }
diff --git a/question/type/multianswer/tests/walkthrough_test.php b/question/type/multianswer/tests/walkthrough_test.php
index 65dff59..19af3c7 100644
--- a/question/type/multianswer/tests/walkthrough_test.php
+++ b/question/type/multianswer/tests/walkthrough_test.php
@@ -37,70 +37,53 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_base {
-    public function test_interactive() {
-        return; // TODO
+    public function test_deferred_feedback() {
 
         // Create a gapselect question.
-        $q = test_question_maker::make_question('calculated');
-        $q->hints = array(
-            new question_hint(1, 'This is the first hint.', FORMAT_HTML),
-            new question_hint(2, 'This is the second hint.', FORMAT_HTML),
-        );
-        $this->start_attempt_at_question($q, 'interactive', 3);
-        $values = $q->vs->get_values();
+        $q = test_question_maker::make_question('multianswer', 'fourmc');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 4);
 
         // Check the initial state.
         $this->check_current_state(question_state::$todo);
         $this->check_current_mark(null);
         $this->check_current_output(
                 $this->get_contains_marked_out_of_summary(),
-                $this->get_contains_submit_button_expectation(true),
                 $this->get_does_not_contain_feedback_expectation(),
-                $this->get_does_not_contain_validation_error_expectation(),
-                $this->get_does_not_contain_try_again_button_expectation(),
-                $this->get_no_hint_visible_expectation());
+                $this->get_does_not_contain_validation_error_expectation());
 
-        // Submit blank.
-        $this->process_submission(array('-submit' => 1, 'answer' => ''));
+        // Save in incomplete answer.
+        $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '',
+                'sub3_answer' => '', 'sub4_answer' => ''));
 
         // Verify.
         $this->check_current_state(question_state::$invalid);
         $this->check_current_mark(null);
         $this->check_current_output(
                 $this->get_contains_marked_out_of_summary(),
-                $this->get_contains_submit_button_expectation(true),
                 $this->get_does_not_contain_feedback_expectation(),
-                $this->get_contains_validation_error_expectation(),
-                $this->get_does_not_contain_try_again_button_expectation(),
-                $this->get_no_hint_visible_expectation());
+                $this->get_does_not_contain_validation_error_expectation()); // TODO, really, it should. See MDL-32049.
 
-        // Sumit something that does not look like a number.
-        $this->process_submission(array('-submit' => 1, 'answer' => 'newt'));
+        // Save a partially correct answer.
+        $this->process_submission(array('sub1_answer' => '1', 'sub2_answer' => '1',
+                'sub3_answer' => '1', 'sub4_answer' => '1'));
 
         // Verify.
-        $this->check_current_state(question_state::$invalid);
+        $this->check_current_state(question_state::$complete);
         $this->check_current_mark(null);
         $this->check_current_output(
                 $this->get_contains_marked_out_of_summary(),
-                $this->get_contains_submit_button_expectation(true),
                 $this->get_does_not_contain_feedback_expectation(),
-                $this->get_contains_validation_error_expectation(),
-                new question_pattern_expectation('/' .
-                        preg_quote(get_string('invalidnumber', 'qtype_numerical') . '/')),
-                $this->get_does_not_contain_try_again_button_expectation(),
-                $this->get_no_hint_visible_expectation());
+                $this->get_does_not_contain_validation_error_expectation());
 
-        // Now get it right.
-        $this->process_submission(array('-submit' => 1, 'answer' => $values['a'] + $values['b']));
+        // Now submit all and finish.
+        $this->process_submission(array('-finish' => 1));
 
         // Verify.
-        $this->check_current_state(question_state::$gradedright);
-        $this->check_current_mark(3);
+        $this->check_current_state(question_state::$gradedpartial);
+        $this->check_current_mark(2);
         $this->check_current_output(
-                $this->get_contains_mark_summary(3),
-                $this->get_contains_submit_button_expectation(false),
-                $this->get_contains_correct_expectation(),
-                $this->get_does_not_contain_validation_error_expectation(),
-                $this->get_no_hint_visible_expectation());
+                $this->get_contains_mark_summary(2),
+                $this->get_contains_partcorrect_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
     }
 }
-- 
1.7.9.5


From 2d7cbf59234c2d8d1976bd87d619e33405d1d600 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 17 Jul 2012 17:32:56 +0100
Subject: [PATCH 213/903] MDL-34251 question engine: possible infinite loop
 loading usages

In the case where either a question_attempt had not steps, or a
question_usage had not question_attempts, the load_from_records methods
could get stuck in an infinite loop.

This fix ensures that does not happen, with unit tests to verify it. At
the same time, I noticed an error in the existing tests, which this
patch fixes.
---
 question/engine/questionattempt.php                |    9 +++
 question/engine/questionusage.php                  |    8 +++
 .../engine/tests/questionusagebyactivity_test.php  |   68 ++++++++++++++++++--
 3 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php
index 54c4d9f..1be7df2 100644
--- a/question/engine/questionattempt.php
+++ b/question/engine/questionattempt.php
@@ -1213,6 +1213,15 @@ class question_attempt {
         $qa->behaviour = question_engine::make_behaviour(
                 $record->behaviour, $qa, $preferredbehaviour);
 
+        // If attemptstepid is null (which should not happen, but has happened
+        // due to corrupt data, see MDL-34251) then the current pointer in $records
+        // will not be advanced in the while loop below, and we get stuck in an
+        // infinite loop, since this method is supposed to always consume at
+        // least one record. Therefore, in this case, advance the record here.
+        if (is_null($record->attemptstepid)) {
+            $records->next();
+        }
+
         $i = 0;
         while ($record && $record->questionattemptid == $questionattemptid && !is_null($record->attemptstepid)) {
             $qa->steps[$i] = question_attempt_step::load_from_records($records, $record->attemptstepid);
diff --git a/question/engine/questionusage.php b/question/engine/questionusage.php
index 8d7ffa9..f9470c0 100644
--- a/question/engine/questionusage.php
+++ b/question/engine/questionusage.php
@@ -714,6 +714,14 @@ class question_usage_by_activity {
 
         $quba->observer = new question_engine_unit_of_work($quba);
 
+        // If slot is null then the current pointer in $records will not be
+        // advanced in the while loop below, and we get stuck in an infinite loop,
+        // since this method is supposed to always consume at least one record.
+        // Therefore, in this case, advance the record here.
+        if (is_null($record->slot)) {
+            $records->next();
+        }
+
         while ($record && $record->qubaid == $qubaid && !is_null($record->slot)) {
             $quba->questionattempts[$record->slot] =
                     question_attempt::load_from_records($records,
diff --git a/question/engine/tests/questionusagebyactivity_test.php b/question/engine/tests/questionusagebyactivity_test.php
index 73ff8b3..71434ee 100644
--- a/question/engine/tests/questionusagebyactivity_test.php
+++ b/question/engine/tests/questionusagebyactivity_test.php
@@ -169,16 +169,17 @@ class question_usage_by_activity_test extends advanced_testcase {
  */
 class question_usage_db_test extends data_loading_method_test_base {
     public function test_load() {
+        $scid = context_system::instance()->id;
         $records = new question_test_recordset(array(
         array('qubaid', 'contextid', 'component', 'preferredbehaviour',
-                                               'questionattemptid', 'contextid', 'questionusageid', 'slot',
+                                               'questionattemptid', 'questionusageid', 'slot',
                                                               'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
                                                                                                              'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
                                                                                                                                      'attemptstepid', 'sequencenumber', 'state', 'fraction',
                                                                                                                                                                      'timecreated', 'userid', 'name', 'value'),
-        array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo',             null, 1256233700, 1,       null, null),
-        array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233705, 1,   'answer',  '1'),
-        array(1, 1, 'unit_test', 'interactive', 1, 123, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 2, 'gradedright', 1.0000000, 1256233720, 1,  '-finish',  '1'),
+        array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo',             null, 1256233700, 1,       null, null),
+        array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'todo',             null, 1256233705, 1,   'answer',  '1'),
+        array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 2, 'gradedright', 1.0000000, 1256233720, 1,  '-finish',  '1'),
         ));
 
         $question = test_question_maker::make_question('truefalse', 'true');
@@ -221,4 +222,63 @@ class question_usage_db_test extends data_loading_method_test_base {
         $this->assertEquals(1, $step->get_user_id());
         $this->assertEquals(array('-finish' => '1'), $step->get_all_data());
     }
+
+    public function test_load_data_no_steps() {
+        // The code had a bug where if one question_attempt had no steps,
+        // load_from_records got stuck in an infinite loop. This test is to
+        // verify that no longer happens.
+        $scid = context_system::instance()->id;
+        $records = new question_test_recordset(array(
+        array('qubaid', 'contextid', 'component', 'preferredbehaviour',
+                                                   'questionattemptid', 'questionusageid', 'slot',
+                                                             'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
+                                                                                                            'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
+                                                                                                                                                                               'attemptstepid', 'sequencenumber', 'state', 'fraction',
+                                                                                                                                                                                                         'timecreated', 'userid', 'name', 'value'),
+        array(1, $scid, 'unit_test', 'interactive', 1, 1, 1, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null),
+        array(1, $scid, 'unit_test', 'interactive', 2, 1, 2, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null),
+        array(1, $scid, 'unit_test', 'interactive', 3, 1, 3, 'interactive', 0, 1, 1.0000000, 0.0000000, 0, 'This question is missing. Unable to display anything.', '', '', 0, null, null, null, null, null, null, null, null),
+        ));
+
+        question_bank::start_unit_test();
+        $quba = question_usage_by_activity::load_from_records($records, 1);
+        question_bank::end_unit_test();
+
+        $this->assertEquals('unit_test', $quba->get_owning_component());
+        $this->assertEquals(1, $quba->get_id());
+        $this->assertInstanceOf('question_engine_unit_of_work', $quba->get_observer());
+        $this->assertEquals('interactive', $quba->get_preferred_behaviour());
+
+        $this->assertEquals(array(1, 2, 3), $quba->get_slots());
+
+        $qa = $quba->get_question_attempt(1);
+        $this->assertEquals(0, $qa->get_num_steps());
+    }
+
+    public function test_load_data_no_qas() {
+        // The code had a bug where if a question_usage had no question_attempts,
+        // load_from_records got stuck in an infinite loop. This test is to
+        // verify that no longer happens.
+        $scid = context_system::instance()->id;
+        $records = new question_test_recordset(array(
+        array('qubaid', 'contextid', 'component', 'preferredbehaviour',
+                                                   'questionattemptid', 'questionusageid', 'slot',
+                                                                        'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
+                                                                                                               'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
+                                                                                                                                         'attemptstepid', 'sequencenumber', 'state', 'fraction',
+                                                                                                                                                                   'timecreated', 'userid', 'name', 'value'),
+        array(1, $scid, 'unit_test', 'interactive', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null),
+        ));
+
+        question_bank::start_unit_test();
+        $quba = question_usage_by_activity::load_from_records($records, 1);
+        question_bank::end_unit_test();
+
+        $this->assertEquals('unit_test', $quba->get_owning_component());
+        $this->assertEquals(1, $quba->get_id());
+        $this->assertInstanceOf('question_engine_unit_of_work', $quba->get_observer());
+        $this->assertEquals('interactive', $quba->get_preferred_behaviour());
+
+        $this->assertEquals(array(), $quba->get_slots());
+    }
 }
-- 
1.7.9.5


From 013c74d058005603dbb48b9b069aab752e58ea99 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 17 Jul 2012 16:18:22 +0100
Subject: [PATCH 214/903] MDL-34379 quiz reports: timetaken 'open' for never
 submitted attempts

---
 mod/quiz/report/attemptsreport_table.php |    2 --
 1 file changed, 2 deletions(-)

diff --git a/mod/quiz/report/attemptsreport_table.php b/mod/quiz/report/attemptsreport_table.php
index 03f8959..4334256 100644
--- a/mod/quiz/report/attemptsreport_table.php
+++ b/mod/quiz/report/attemptsreport_table.php
@@ -189,8 +189,6 @@ abstract class quiz_attempts_report_table extends table_sql {
     public function col_duration($attempt) {
         if ($attempt->timefinish) {
             return format_time($attempt->timefinish - $attempt->timestart);
-        } else if ($attempt->timestart) {
-            return get_string('unfinished', 'quiz');
         } else {
             return '-';
         }
-- 
1.7.9.5


From 2894157f15295354c68735c93aeb25df3628b126 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 17 Jul 2012 16:30:33 +0100
Subject: [PATCH 215/903] MDL-34351 quiz cron: one broken overdue attempt
 should not kill cron

It seems that sometimes trying to process an overdue quiz attempt can
throw an exception. In that case, we need to catch it and report it
nicely, and then carry on processing the rest of the attempts, rather
than just killing the whole of cron processing.

Also, there may be garbage quiz attempts where the associated quiz or
course has been deleted. Skip those too.
---
 mod/quiz/cronlib.php |   49 +++++++++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/mod/quiz/cronlib.php b/mod/quiz/cronlib.php
index 111419c..7913b63 100644
--- a/mod/quiz/cronlib.php
+++ b/mod/quiz/cronlib.php
@@ -57,27 +57,36 @@ class mod_quiz_overdue_attempt_updater {
         $count = 0;
         $quizcount = 0;
         foreach ($attemptstoprocess as $attempt) {
-            // If we have moved on to a different quiz, fetch the new data.
-            if (!$quiz || $attempt->quiz != $quiz->id) {
-                $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST);
-                $cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
-                $quizcount += 1;
+            try {
+
+                // If we have moved on to a different quiz, fetch the new data.
+                if (!$quiz || $attempt->quiz != $quiz->id) {
+                    $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST);
+                    $cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
+                    $quizcount += 1;
+                }
+
+                // If we have moved on to a different course, fetch the new data.
+                if (!$course || $course->id != $quiz->course) {
+                    $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
+                }
+
+                // Make a specialised version of the quiz settings, with the relevant overrides.
+                $quizforuser = clone($quiz);
+                $quizforuser->timeclose = $attempt->usertimeclose;
+                $quizforuser->timelimit = $attempt->usertimelimit;
+
+                // Trigger any transitions that are required.
+                $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
+                $attemptobj->handle_if_time_expired($timenow, false);
+                $count += 1;
+
+            } catch (moodle_exception $e) {
+                // If an error occurs while processing one attempt, don't let that kill cron.
+                mtrace("Error while processing attempt {$attempt->id} at {$attempt->quiz} quiz:");
+                mtrace($e->getMessage());
+                mtrace($e->getTraceAsString());
             }
-
-            // If we have moved on to a different course, fetch the new data.
-            if (!$course || $course->id != $quiz->course) {
-                $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
-            }
-
-            // Make a specialised version of the quiz settings, with the relevant overrides.
-            $quizforuser = clone($quiz);
-            $quizforuser->timeclose = $attempt->usertimeclose;
-            $quizforuser->timelimit = $attempt->usertimelimit;
-
-            // Trigger any transitions that are required.
-            $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
-            $attemptobj->handle_if_time_expired($timenow, false);
-            $count += 1;
         }
 
         $attemptstoprocess->close();
-- 
1.7.9.5


From 1cb637e42a249eab84e0b825312dc8c85ab2a8d4 Mon Sep 17 00:00:00 2001
From: Jason Ilicic <jason.ilicic@netspot.com.au>
Date: Fri, 20 Jul 2012 14:45:32 +0930
Subject: [PATCH 216/903] MDL-34427: Corrected language string when not
 allowed to enter the chat room.

---
 mod/chat/lang/en/chat.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/chat/lang/en/chat.php b/mod/chat/lang/en/chat.php
index 25b7b6b..662aadc 100644
--- a/mod/chat/lang/en/chat.php
+++ b/mod/chat/lang/en/chat.php
@@ -98,7 +98,7 @@ $string['nomessages'] = 'No messages yet';
 $string['normalkeepalive'] = 'KeepAlive';
 $string['normalstream'] = 'Stream';
 $string['noscheduledsession'] = 'No scheduled session';
-$string['notallowenter'] = 'You are not allow to enter the chat room.';
+$string['notallowenter'] = 'You are not allowed to enter the chat room.';
 $string['notlogged'] = 'You are not logged in!';
 $string['nopermissiontoseethechatlog'] = 'You don\'t have permission to see the chat logs.';
 $string['oldping'] = 'Disconnect timeout';
-- 
1.7.9.5


From e0cf9e280a14fd5746027fc5679cd6c7922de8c4 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Fri, 20 Jul 2012 14:56:00 +0800
Subject: [PATCH 217/903] MDL-33537 gradingform_rubric Adding the definition
 when retrieving grading instances

Credit to Sam Chaffee
---
 grade/grading/form/rubric/lib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/grade/grading/form/rubric/lib.php b/grade/grading/form/rubric/lib.php
index 71b38ec..ae97eee 100644
--- a/grade/grading/form/rubric/lib.php
+++ b/grade/grading/form/rubric/lib.php
@@ -556,7 +556,8 @@ class gradingform_rubric_controller extends gradingform_controller {
             return $this->get_instance($instance);
         }
         if ($itemid && $raterid) {
-            if ($rs = $DB->get_records('grading_instances', array('raterid' => $raterid, 'itemid' => $itemid), 'timemodified DESC', '*', 0, 1)) {
+            $params = array('definitionid' => $this->definition->id, 'raterid' => $raterid, 'itemid' => $itemid);
+            if ($rs = $DB->get_records('grading_instances', $params, 'timemodified DESC', '*', 0, 1)) {
                 $record = reset($rs);
                 $currentinstance = $this->get_current_instance($raterid, $itemid);
                 if ($record->status == gradingform_rubric_instance::INSTANCE_STATUS_INCOMPLETE &&
-- 
1.7.9.5


From 8545a5cc54e506b273d36ed3ad3980900bfc3031 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 20 Jul 2012 23:12:06 +0100
Subject: [PATCH 218/903] MDL-34412 theme_afterburner: defined #EEE as
 background-color in afterburner_styles.css for
 filemanager and filepicker input, select, button &
 textarea

---
 theme/afterburner/style/afterburner_styles.css |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/theme/afterburner/style/afterburner_styles.css b/theme/afterburner/style/afterburner_styles.css
index 3b51251..eb9260e 100644
--- a/theme/afterburner/style/afterburner_styles.css
+++ b/theme/afterburner/style/afterburner_styles.css
@@ -453,4 +453,16 @@ tab styles for ie6 & ie7
 }
 body#page-course-view-topics.path-course div.moodle-dialogue-base div.yui3-widget{
     z-index: 600!important;
+}
+/* Filemanager
+-------------------------*/
+.filemanager select,
+.filemanager input,
+.filemanager button,
+.filemanager textarea,
+.file-picker select,
+.file-picker input,
+.file-picker button,
+.file-picker textarea {
+    background-color: #EEE;
 }
\ No newline at end of file
-- 
1.7.9.5


From ab706cc971263103687fb3bc855c601a4a2549c3 Mon Sep 17 00:00:00 2001
From: Luke Tucker <luke.tucker@netspot.com.au>
Date: Tue, 19 Jun 2012 19:06:40 +0930
Subject: [PATCH 219/903] MDL-34396 Ensure TinyMCE editor spell checking works
 on pages with $PAGE->https_required()

---
 lib/editor/tinymce/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/editor/tinymce/lib.php b/lib/editor/tinymce/lib.php
index 10753a9..9e53fc7 100644
--- a/lib/editor/tinymce/lib.php
+++ b/lib/editor/tinymce/lib.php
@@ -155,7 +155,7 @@ class tinymce_texteditor extends texteditor {
                     'theme_advanced_resizing_min_height' => 30,
                     'theme_advanced_toolbar_location' => "top",
                     'theme_advanced_statusbar_location' => "bottom",
-                    'spellchecker_rpc_url' => $CFG->wwwroot."/lib/editor/tinymce/tiny_mce/$this->version/plugins/spellchecker/rpc.php",
+                    'spellchecker_rpc_url' => $CFG->httpswwwroot."/lib/editor/tinymce/tiny_mce/$this->version/plugins/spellchecker/rpc.php",
                     'spellchecker_languages' => $spelllanguagelist
                   );
 
-- 
1.7.9.5


From 7c87df674ef7f02370e3714a638efa2a9178a492 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 21 Jul 2012 21:00:24 +0200
Subject: [PATCH 220/903] MDL-34129 show course info on enrolment page

---
 enrol/index.php |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/enrol/index.php b/enrol/index.php
index 5c3caa8..14e7da2 100644
--- a/enrol/index.php
+++ b/enrol/index.php
@@ -84,6 +84,34 @@ $PAGE->navbar->add(get_string('enrolmentoptions','enrol'));
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('enrolmentoptions','enrol'));
 
+echo $OUTPUT->box_start('generalbox info');
+
+$summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course', 'summary', null);
+echo format_text($summary, $course->summaryformat, array('overflowdiv'=>true), $course->id);
+if (!empty($CFG->coursecontact)) {
+    $coursecontactroles = explode(',', $CFG->coursecontact);
+    foreach ($coursecontactroles as $roleid) {
+        $role = $DB->get_record('role', array('id'=>$roleid));
+        $roleid = (int) $roleid;
+        if ($users = get_role_users($roleid, $context, true)) {
+            foreach ($users as $teacher) {
+                $fullname = fullname($teacher, has_capability('moodle/site:viewfullnames', $context));
+                $namesarray[] = format_string(role_get_name($role, $context)).': <a href="'.$CFG->wwwroot.'/user/view.php?id='.
+                    $teacher->id.'&amp;course='.SITEID.'">'.$fullname.'</a>';
+            }
+        }
+    }
+
+    if (!empty($namesarray)) {
+        echo "<ul class=\"teachers\">\n<li>";
+        echo implode('</li><li>', $namesarray);
+        echo "</li></ul>";
+    }
+}
+
+echo $OUTPUT->box_end();
+
+
 //TODO: find if future enrolments present and display some info
 
 foreach ($forms as $form) {
-- 
1.7.9.5


From 1c005cbf128275217d82bc174c727532dad84a4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 15:26:15 +0200
Subject: [PATCH 221/903] MDL-34449 lazy load theme layout otpions

This should allow us to switch page layout on admin pages and elsewhere before $OUTPUT->header() call.
---
 lib/pagelib.php |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/pagelib.php b/lib/pagelib.php
index ddea039..6023314 100644
--- a/lib/pagelib.php
+++ b/lib/pagelib.php
@@ -186,7 +186,7 @@ class moodle_page {
      * @var array List of theme layout options, these are ignored by core.
      * To be used in individual theme layout files only.
      */
-    protected $_layout_options = array();
+    protected $_layout_options = null;
 
     /**
      * @var string An optional arbitrary parameter that can be set on pages where the context
@@ -496,6 +496,9 @@ class moodle_page {
      * @return array returns arrys with options for layout file
      */
     protected function magic_get_layout_options() {
+        if (!is_array($this->_layout_options)) {
+            $this->_layout_options = $this->_theme->pagelayout_options($this->pagelayout);
+        }
         return $this->_layout_options;
     }
 
@@ -1433,7 +1436,6 @@ class moodle_page {
         if (is_null($this->_theme)) {
             $themename = $this->resolve_theme();
             $this->_theme = theme_config::load($themename);
-            $this->_layout_options = $this->_theme->pagelayout_options($this->pagelayout);
         }
 
         $this->_theme->setup_blocks($this->pagelayout, $this->blocks);
-- 
1.7.9.5


From a14ef47b44ac9dfef75175ddac3c1fa79468ba9f Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Sun, 22 Jul 2012 12:22:28 -0400
Subject: [PATCH 222/903] MDL-34451 quiz Fixed problem where attempt page is
 updated for ALL attempts, not just current.

---
 mod/quiz/attempt.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php
index bb8c01f..cdff54e 100644
--- a/mod/quiz/attempt.php
+++ b/mod/quiz/attempt.php
@@ -103,7 +103,7 @@ if ($attemptobj->get_currentpage() != $page) {
         // Prevent out of sequence access.
         redirect($attemptobj->start_attempt_url(null, $attemptobj->get_currentpage()));
     }
-    $DB->set_field('quiz_attempts', 'currentpage', $page);
+    $DB->set_field('quiz_attempts', 'currentpage', $page, array('id' => $attemptid));
 }
 
 // Initialise the JavaScript.
-- 
1.7.9.5


From 4b195fe9e92de0a77beeda86d438d2ce9cd2c270 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 10:37:11 +0200
Subject: [PATCH 223/903] MDL-34441 cleanup dtl related phpdocs and minor
 style improvements

---
 admin/tool/dbtransfer/database_export_form.php    |    9 ++++--
 admin/tool/dbtransfer/database_transfer_form.php  |    9 ++++--
 admin/tool/dbtransfer/dbexport.php                |    9 +++---
 admin/tool/dbtransfer/index.php                   |    9 +++---
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |    5 ++--
 admin/tool/dbtransfer/locallib.php                |   24 +++++++++++-----
 admin/tool/dbtransfer/settings.php                |    9 +++---
 admin/tool/dbtransfer/version.php                 |    5 ++--
 lib/dtl/database_exporter.php                     |   13 ++++-----
 lib/dtl/database_importer.php                     |   20 ++++++-------
 lib/dtl/database_mover.php                        |   32 ++++++++++-----------
 lib/dtl/file_xml_database_exporter.php            |   10 +++----
 lib/dtl/file_xml_database_importer.php            |    7 ++---
 lib/dtl/string_xml_database_exporter.php          |    8 ++----
 lib/dtl/string_xml_database_importer.php          |    9 ++----
 lib/dtl/xml_database_exporter.php                 |    5 +---
 lib/dtl/xml_database_importer.php                 |    9 ++----
 17 files changed, 90 insertions(+), 102 deletions(-)

diff --git a/admin/tool/dbtransfer/database_export_form.php b/admin/tool/dbtransfer/database_export_form.php
index 72b7c52..0bfe989 100644
--- a/admin/tool/dbtransfer/database_export_form.php
+++ b/admin/tool/dbtransfer/database_export_form.php
@@ -17,9 +17,8 @@
 /**
  * Transfer form
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -27,6 +26,10 @@ defined('MOODLE_INTERNAL') || die;
 
 require_once $CFG->libdir.'/formslib.php';
 
+
+/**
+ * Definition of db export settings form.
+ */
 class database_export_form extends moodleform {
 
     function definition() {
diff --git a/admin/tool/dbtransfer/database_transfer_form.php b/admin/tool/dbtransfer/database_transfer_form.php
index 9b699e9..9e7382d7 100644
--- a/admin/tool/dbtransfer/database_transfer_form.php
+++ b/admin/tool/dbtransfer/database_transfer_form.php
@@ -17,9 +17,8 @@
 /**
  * Transfer form
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -27,6 +26,10 @@ defined('MOODLE_INTERNAL') || die;
 
 require_once $CFG->libdir.'/formslib.php';
 
+
+/**
+ * Definition of db transfer settings form.
+ */
 class database_transfer_form extends moodleform {
 
     function definition() {
diff --git a/admin/tool/dbtransfer/dbexport.php b/admin/tool/dbtransfer/dbexport.php
index 40f35ff..2672cfd 100644
--- a/admin/tool/dbtransfer/dbexport.php
+++ b/admin/tool/dbtransfer/dbexport.php
@@ -17,9 +17,8 @@
 /**
  * Export
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -32,11 +31,11 @@ require_once('database_export_form.php');
 require_login();
 admin_externalpage_setup('tooldbexport');
 
-//create form
+// Create form.
 $form = new database_export_form();
 
 if ($data = $form->get_data()) {
-    dbtransfer_export_xml_database($data->description, $DB);
+    tool_dbtransfer_export_xml_database($data->description, $DB);
     die;
 }
 
diff --git a/admin/tool/dbtransfer/index.php b/admin/tool/dbtransfer/index.php
index 2b1a2c5..d806dfb 100644
--- a/admin/tool/dbtransfer/index.php
+++ b/admin/tool/dbtransfer/index.php
@@ -17,9 +17,8 @@
 /**
  * Transfer tool
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -32,7 +31,7 @@ require_once('database_transfer_form.php');
 require_login();
 admin_externalpage_setup('tooldbtransfer');
 
-// Create the form
+// Create the form.
 $form = new database_transfer_form();
 
 // If we have valid input.
@@ -61,7 +60,7 @@ if ($data = $form->get_data()) {
 
     // Do the transfer.
     $feedback = new html_list_progress_trace();
-    dbtransfer_transfer_database($DB, $targetdb, $feedback);
+    tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
     $feedback->finished();
 
     // Finish up.
diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index 1279af5..41bf639 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -17,9 +17,8 @@
 /**
  * Strings for component 'tool_generator', language 'en', branch 'MOODLE_22_STABLE'
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2011 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2011 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
diff --git a/admin/tool/dbtransfer/locallib.php b/admin/tool/dbtransfer/locallib.php
index f36ceef..140691d 100644
--- a/admin/tool/dbtransfer/locallib.php
+++ b/admin/tool/dbtransfer/locallib.php
@@ -17,9 +17,8 @@
 /**
  * Export db content to file.
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda {@link http://skodak.org}
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -44,8 +43,13 @@ TODO:
 require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->libdir.'/dtllib.php');
 
-
-function dbtransfer_export_xml_database($description, $mdb) {
+/**
+ * Initiate database export.
+ * @param string $description
+ * @param moodle_database $mdb
+ * @return does not return, calls die()
+ */
+function tool_dbtransfer_export_xml_database($description, $mdb) {
     @set_time_limit(0);
 
     session_get_instance()->write_close(); // release session
@@ -65,8 +69,14 @@ function dbtransfer_export_xml_database($description, $mdb) {
     die;
 }
 
-
-function dbtransfer_transfer_database($sourcedb, $targetdb, $feedback = null) {
+/**
+ * Initiate database transfer.
+ * @param moodle_database $sourcedb
+ * @param moodle_database $targetdb
+ * @param progress_trace $feedback
+ * @return void
+ */
+function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_database $targetdb, progress_trace $feedback = null) {
     @set_time_limit(0);
 
     session_get_instance()->write_close(); // release session
diff --git a/admin/tool/dbtransfer/settings.php b/admin/tool/dbtransfer/settings.php
index 13c45b8..70db648 100644
--- a/admin/tool/dbtransfer/settings.php
+++ b/admin/tool/dbtransfer/settings.php
@@ -15,11 +15,10 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Link to InnoDB conversion tool
+ * Add hidden links db transfer tool
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2011 Petr Skoda {@link http://skodak.org}
+ * @package    tool_dbtransfer
+ * @copyright  2011 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
@@ -29,4 +28,4 @@ if ($hassiteconfig) {
     // DB transfer related pages
     $ADMIN->add('experimental', new admin_externalpage('tooldbtransfer', get_string('dbtransfer', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/index.php', 'moodle/site:config', true));
     $ADMIN->add('experimental', new admin_externalpage('tooldbexport', get_string('dbexport', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/dbexport.php', 'moodle/site:config', true));
-}
\ No newline at end of file
+}
diff --git a/admin/tool/dbtransfer/version.php b/admin/tool/dbtransfer/version.php
index 61aa6ec..18cd386 100644
--- a/admin/tool/dbtransfer/version.php
+++ b/admin/tool/dbtransfer/version.php
@@ -17,9 +17,8 @@
 /**
  * Version details.
  *
- * @package    tool
- * @subpackage dbtransfer
- * @copyright  2008 Petr Skoda
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
diff --git a/lib/dtl/database_exporter.php b/lib/dtl/database_exporter.php
index bac7394..7051c82 100644
--- a/lib/dtl/database_exporter.php
+++ b/lib/dtl/database_exporter.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * General database export class
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -41,16 +38,17 @@ defined('MOODLE_INTERNAL') || die();
  * @see export_table_data for the same table.
  */
 abstract class database_exporter {
-    /** Connection to the source database (a @see moodle_database object). */
+    /** @var moodle_database Connection to the source database (a @see moodle_database object). */
     protected $mdb;
-    /** Database manager of the source database (a @see database_manager object). */
+    /** @var database_manager Database manager of the source database (a @see database_manager object). */
     protected $manager;
-    /** Source database schema in XMLDB format (a @see xmldb_structure object). */
+    /** @var xmldb_structure Source database schema in XMLDB format (a @see xmldb_structure object). */
     protected $schema;
     /**
      * Boolean flag - whether or not to check that XML database schema matches
      * the RDBMS database schema before exporting (used by
      * @see export_database).
+     * @var bool
      */
     protected $check_schema;
 
@@ -158,5 +156,4 @@ abstract class database_exporter {
         }
         $this->finish_database_export();
     }
-
 }
diff --git a/lib/dtl/database_importer.php b/lib/dtl/database_importer.php
index b7f6a2d..92b9ff2 100644
--- a/lib/dtl/database_importer.php
+++ b/lib/dtl/database_importer.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * General database importer class
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -43,23 +40,22 @@ defined('MOODLE_INTERNAL') || die();
  * is respected.
  */
 class database_importer {
-    /** Connection to the target database (a @see moodle_database object). */
+    /** @var moodle_database Connection to the target database (a @see moodle_database object). */
     protected $mdb;
-    /** Database manager of the target database (a @see database_manager object). */
+    /** @var database_manager Database manager of the target database (a @see database_manager object). */
     protected $manager;
-    /** Target database schema in XMLDB format (a @see xmldb_structure object). */
+    /** @var xmldb_structure Target database schema in XMLDB format (a @see xmldb_structure object). */
     protected $schema;
     /**
      * Boolean flag - whether or not to check that XML database schema matches
      * the RDBMS database schema before importing (used by
      * @see begin_database_import).
+     * @var bool
      */
     protected $check_schema;
-    /**
-     * How to use transactions.
-     */
+    /** @var string How to use transactions. */
     protected $transactionmode = 'allinone';
-    /** Transaction object */
+    /** @var moodle_transaction Transaction object */
     protected $transaction;
 
     /**
@@ -105,7 +101,7 @@ class database_importer {
         global $CFG;
 
         if (!$this->mdb->get_tables()) {
-            // not tables yet, time to create all tables
+            // No tables present yet, time to create all tables.
             $this->manager->install_from_xmldb_structure($this->schema);
         }
 
diff --git a/lib/dtl/database_mover.php b/lib/dtl/database_mover.php
index d61d416..419080e 100644
--- a/lib/dtl/database_mover.php
+++ b/lib/dtl/database_mover.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * General database mover class
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -28,33 +25,35 @@
 defined('MOODLE_INTERNAL') || die();
 
 class database_mover extends database_exporter {
-    /** Importer object used to transfer data. */
+    /** @var database_importer Importer object used to transfer data. */
     protected $importer;
-    protected $feeback;
+    /** @var progress_trace Progress tracing object */
+    protected $feedback;
 
     /**
      * Object constructor.
      *
-     * @param moodle_database $mdb Connection to the source database (a
+     * @param moodle_database $mdb_source Connection to the source database (a
      * @see moodle_database object).
      * @param moodle_database $mdb_target Connection to the target database (a
      * @see moodle_database object).
      * @param boolean $check_schema - whether or not to check that XML database
      * schema matches the RDBMS database schema before exporting (used by
+     * @param progress_trace $feedback Progress tracing object
      * @see export_database).
      */
     public function __construct(moodle_database $mdb_source, moodle_database $mdb_target,
-            $check_schema = true, progress_trace $feeback = null) {
-        if (empty($feeback)) {
-            $this->feeback = new null_progress_trace();
+            $check_schema = true, progress_trace $feedback = null) {
+        if (empty($feedback)) {
+            $this->feedback = new null_progress_trace();
         } else {
-            $this->feeback = $feeback;
+            $this->feedback = $feedback;
         }
         if ($check_schema) {
-            $this->feeback->output(get_string('checkingsourcetables', 'core_dbtransfer'));
+            $this->feedback->output(get_string('checkingsourcetables', 'core_dbtransfer'));
         }
         parent::__construct($mdb_source, $check_schema);
-        $this->feeback->output(get_string('creatingtargettables', 'core_dbtransfer'));
+        $this->feedback->output(get_string('creatingtargettables', 'core_dbtransfer'));
         $this->importer = new database_importer($mdb_target, $check_schema);
     }
 
@@ -70,12 +69,13 @@ class database_mover extends database_exporter {
      * Callback function. Calls importer's begin_database_import callback method.
      *
      * @param float $version the version of the system which generating the data
+     * @param string $release moodle release info
      * @param string $timestamp the timestamp of the data (in ISO 8601) format.
      * @param string $description a user description of the data.
      * @return void
      */
     public function begin_database_export($version, $release, $timestamp, $description) {
-        $this->feeback->output(get_string('copyingtables', 'core_dbtransfer'));
+        $this->feedback->output(get_string('copyingtables', 'core_dbtransfer'));
         $this->importer->begin_database_import($version, $timestamp, $description);
     }
 
@@ -86,7 +86,7 @@ class database_mover extends database_exporter {
      * @return void
      */
     public function begin_table_export(xmldb_table $table) {
-        $this->feeback->output(get_string('copyingtable', 'core_dbtransfer', $table->getName()), 1);
+        $this->feedback->output(get_string('copyingtable', 'core_dbtransfer', $table->getName()), 1);
         $this->importer->begin_table_import($table->getName(), $table->getHash());
     }
 
@@ -108,7 +108,7 @@ class database_mover extends database_exporter {
      * @return void
      */
     public function finish_table_export(xmldb_table $table) {
-        $this->feeback->output(get_string('done', 'core_dbtransfer', $table->getName()), 2);
+        $this->feedback->output(get_string('done', 'core_dbtransfer', $table->getName()), 2);
         $this->importer->finish_table_import($table->getName());
     }
 
diff --git a/lib/dtl/file_xml_database_exporter.php b/lib/dtl/file_xml_database_exporter.php
index 9f93cb3..498609f 100644
--- a/lib/dtl/file_xml_database_exporter.php
+++ b/lib/dtl/file_xml_database_exporter.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format exporter class to file storage
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -31,9 +28,9 @@ defined('MOODLE_INTERNAL') || die();
  * XML format exporter class to file storage.
  */
 class file_xml_database_exporter extends xml_database_exporter {
-    /** Path to the XML data file. */
+    /** @var string Path to the XML data file. */
     protected $filepath;
-    /** File descriptor for the output file. */
+    /** @var resource File descriptor for the output file. */
     protected $file;
 
     /**
@@ -53,6 +50,7 @@ class file_xml_database_exporter extends xml_database_exporter {
 
     /**
      * Specific output method for the file XML sink.
+     * @param string $text
      */
     protected function output($text) {
         fwrite($this->file, $text);
diff --git a/lib/dtl/file_xml_database_importer.php b/lib/dtl/file_xml_database_importer.php
index a4362f3..cf34f3a 100644
--- a/lib/dtl/file_xml_database_importer.php
+++ b/lib/dtl/file_xml_database_importer.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format importer class from file storage
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -31,7 +28,7 @@ defined('MOODLE_INTERNAL') || die();
  * XML format importer class from file storage.
  */
 class file_xml_database_importer extends xml_database_importer {
-    /** Path to the XML data file. */
+    /** @var string Path to the XML data file. */
     protected $filepath;
 
     /**
diff --git a/lib/dtl/string_xml_database_exporter.php b/lib/dtl/string_xml_database_exporter.php
index 85ce030..cc2dc58 100644
--- a/lib/dtl/string_xml_database_exporter.php
+++ b/lib/dtl/string_xml_database_exporter.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format exporter class to memory storage
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -31,11 +28,12 @@ defined('MOODLE_INTERNAL') || die();
  * XML format exporter class to memory storage (i.e. a string).
  */
 class string_xml_database_exporter extends xml_database_exporter {
-    /** String with XML data. */
+    /** @var string String with XML data. */
     protected $data;
 
     /**
      * Specific output method for the memory XML sink.
+     * @param string $text
      */
     protected function output($text) {
         $this->data .= $text;
diff --git a/lib/dtl/string_xml_database_importer.php b/lib/dtl/string_xml_database_importer.php
index fc80593..94095e9 100644
--- a/lib/dtl/string_xml_database_importer.php
+++ b/lib/dtl/string_xml_database_importer.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format importer class from memory storage
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -31,13 +28,13 @@ defined('MOODLE_INTERNAL') || die();
  * XML format importer class from memory storage (i.e. string).
  */
 class string_xml_database_importer extends xml_database_importer {
-    /** String with XML data. */
+    /** @var string String with XML data. */
     protected $data;
 
     /**
      * Object constructor.
      *
-     * @param string data - string with XML data
+     * @param string $data - string with XML data
      * @param moodle_database $mdb Connection to the target database
      * @see xml_database_importer::__construct()
      * @param boolean $check_schema - whether or not to check that XML database
diff --git a/lib/dtl/xml_database_exporter.php b/lib/dtl/xml_database_exporter.php
index ae76a7a..7789dbd 100644
--- a/lib/dtl/xml_database_exporter.php
+++ b/lib/dtl/xml_database_exporter.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format exporter class
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/lib/dtl/xml_database_importer.php b/lib/dtl/xml_database_importer.php
index 24ca87a..da522dd 100644
--- a/lib/dtl/xml_database_importer.php
+++ b/lib/dtl/xml_database_importer.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -15,12 +14,10 @@
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
 /**
  * XML format importer class
  *
- * @package    core
- * @subpackage dtl
+ * @package    core_dtl
  * @copyright  2008 Andrei Bautu
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -150,9 +147,9 @@ abstract class xml_database_importer extends database_importer {
      * @param string $data character data to be processed
      * @return void
      */
-    protected function cdata($parser, $cdata) {
+    protected function cdata($parser, $data) {
         if (isset($this->current_field)) {
-            $this->current_data .= $cdata;
+            $this->current_data .= $data;
         }
     }
 }
-- 
1.7.9.5


From 6b986b7b6aa38725684814633e1b7880423f6c5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 10:38:39 +0200
Subject: [PATCH 224/903] MDL-34441 always use proper charset in
 htmlspecialchars() calls

---
 lib/dtl/xml_database_exporter.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/dtl/xml_database_exporter.php b/lib/dtl/xml_database_exporter.php
index 7789dbd..374a735 100644
--- a/lib/dtl/xml_database_exporter.php
+++ b/lib/dtl/xml_database_exporter.php
@@ -48,7 +48,7 @@ abstract class xml_database_exporter extends database_exporter {
     public function begin_database_export($version, $release, $timestamp, $description) {
         $this->output('<?xml version="1.0" encoding="utf-8"?>');
         //TODO add xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" and schema information
-        $this->output('<moodle_database version="'.$version.'" release="'.$release.'" timestamp="'.$timestamp.'"'.(empty ($description) ? '' : ' comment="'.htmlspecialchars($description, ENT_QUOTES).'"').'>');
+        $this->output('<moodle_database version="'.$version.'" release="'.$release.'" timestamp="'.$timestamp.'"'.(empty ($description) ? '' : ' comment="'.htmlspecialchars($description, ENT_QUOTES, 'UTF-8').'"').'>');
     }
 
     /**
@@ -90,7 +90,7 @@ abstract class xml_database_exporter extends database_exporter {
             if (is_null($value)) {
                 $this->output('<field name="'.$key.'" value="null" />');
             } else {
-                $this->output('<field name="'.$key.'">'.htmlspecialchars($value, ENT_NOQUOTES).'</field>');
+                $this->output('<field name="'.$key.'">'.htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8').'</field>');
             }
         }
         $this->output('</record>');
-- 
1.7.9.5


From 937777f3fed75d45f77a80a7533478f358334714 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 10:54:46 +0200
Subject: [PATCH 225/903] MDL-34441 fix switched lang strings

---
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index 41bf639..a117117 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -22,8 +22,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-$string['dbexport'] = 'Database transfer';
-$string['dbtransfer'] = 'Database export';
+$string['dbexport'] = 'Database export';
+$string['dbtransfer'] = 'Database transfer';
 $string['exportdata'] = 'Export data';
 $string['notargetconectexception'] = 'Can not connect target database, sorry.';
 $string['pluginname'] = 'Database transfer';
-- 
1.7.9.5


From c8e5d9c9eb19e88604df84fa4c2cf6d7a227d426 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 11:01:01 +0200
Subject: [PATCH 226/903] MDL-34441 show db transfer in experimental section

DB export and import is not ready yet, sorry.
---
 admin/tool/dbtransfer/settings.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/admin/tool/dbtransfer/settings.php b/admin/tool/dbtransfer/settings.php
index 70db648..a1390ef 100644
--- a/admin/tool/dbtransfer/settings.php
+++ b/admin/tool/dbtransfer/settings.php
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die;
 
 if ($hassiteconfig) {
-    // DB transfer related pages
-    $ADMIN->add('experimental', new admin_externalpage('tooldbtransfer', get_string('dbtransfer', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/index.php', 'moodle/site:config', true));
+    $ADMIN->add('experimental', new admin_externalpage('tooldbtransfer', get_string('dbtransfer', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/index.php', 'moodle/site:config', false));
+    // DB export/import is not ready yet - keep it hidden for now.
     $ADMIN->add('experimental', new admin_externalpage('tooldbexport', get_string('dbexport', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/dbexport.php', 'moodle/site:config', true));
 }
-- 
1.7.9.5


From 9134f9aa9cc28f43b64d999146f35eb40a91bae7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 11:13:14 +0200
Subject: [PATCH 227/903] MDL-34441 prevent mysqli::close() notice after
 failed mysql driver connect

---
 lib/dml/mysqli_native_moodle_database.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php
index 9294c07..1a238ba 100644
--- a/lib/dml/mysqli_native_moodle_database.php
+++ b/lib/dml/mysqli_native_moodle_database.php
@@ -380,6 +380,7 @@ class mysqli_native_moodle_database extends moodle_database {
         $errorno = @$this->mysqli->connect_errno;
 
         if ($errorno !== 0) {
+            $this->mysqli = null;
             throw new dml_connection_exception($dberr);
         }
 
-- 
1.7.9.5


From 0dd05d20b937edd7fd0beb9b30f051fdfa927e64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 13:00:24 +0200
Subject: [PATCH 228/903] MDL-34441 improve error handling when migrating
 databases

---
 admin/tool/dbtransfer/database_export_form.php    |    2 +-
 admin/tool/dbtransfer/database_transfer_form.php  |   60 +++++++++++++--------
 admin/tool/dbtransfer/index.php                   |   45 +++++++++-------
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |    1 +
 admin/tool/dbtransfer/locallib.php                |   37 +++++++++++++
 5 files changed, 105 insertions(+), 40 deletions(-)

diff --git a/admin/tool/dbtransfer/database_export_form.php b/admin/tool/dbtransfer/database_export_form.php
index 0bfe989..50646ad 100644
--- a/admin/tool/dbtransfer/database_export_form.php
+++ b/admin/tool/dbtransfer/database_export_form.php
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-require_once $CFG->libdir.'/formslib.php';
+require_once($CFG->libdir.'/formslib.php');
 
 
 /**
diff --git a/admin/tool/dbtransfer/database_transfer_form.php b/admin/tool/dbtransfer/database_transfer_form.php
index 9e7382d7..73ed927 100644
--- a/admin/tool/dbtransfer/database_transfer_form.php
+++ b/admin/tool/dbtransfer/database_transfer_form.php
@@ -24,7 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-require_once $CFG->libdir.'/formslib.php';
+require_once($CFG->libdir.'/formslib.php');
+require_once(__DIR__.'/locallib.php');
 
 
 /**
@@ -32,43 +33,60 @@ require_once $CFG->libdir.'/formslib.php';
  */
 class database_transfer_form extends moodleform {
 
-    function definition() {
+    /**
+     * Define transfer form.
+     */
+    protected function definition() {
+        global $CFG;
+
         $mform = $this->_form;
 
         $mform->addElement('header', 'database', get_string('dbtransfer', 'tool_dbtransfer'));
 
-        $supported = array (
-            'mysqli/native',
-            'pgsql/native',
-            'mssql/native',
-            'oci/native',
-            'sqlsrv/native',
-        );
-        $drivers = array();
-        foreach($supported as $driver) {
-            list($dbtype, $dblibrary) = explode('/', $driver);
-            $targetdb = moodle_database::get_driver_instance($dbtype, $dblibrary);
-            if ($targetdb->driver_installed() !== true) {
-                continue;
-            }
-            $drivers[$driver] = $driver;
-        }
+        $drivers = tool_dbtransfer_get_drivers();
+        $drivers = array_reverse($drivers, true);
+        $drivers[''] = get_string('choosedots');
+        $drivers = array_reverse($drivers, true);
 
         $mform->addElement('select', 'driver', get_string('dbtype', 'install'), $drivers);
         $mform->addElement('text', 'dbhost', get_string('dbhost', 'install'));
         $mform->addElement('text', 'dbname', get_string('database', 'install'));
         $mform->addElement('text', 'dbuser', get_string('user'));
-        $mform->addElement('text', 'dbpass', get_string('password'));
+        $mform->addElement('passwordunmask', 'dbpass', get_string('password'));
         $mform->addElement('text', 'prefix', get_string('dbprefix', 'install'));
         $mform->addElement('text', 'dbport', get_string('dbport', 'install'));
-        $mform->addElement('text', 'dbsocket', get_string('databasesocket', 'install'));
+        if ($CFG->ostype !== 'WINDOWS') {
+            $mform->addElement('text', 'dbsocket', get_string('databasesocket', 'install'));
+        } else {
+            $mform->addElement('hidden', 'dbsocket');
+        }
 
+        $mform->addRule('driver', get_string('required'), 'required', null);
         $mform->addRule('dbhost', get_string('required'), 'required', null);
         $mform->addRule('dbname', get_string('required'), 'required', null);
         $mform->addRule('dbuser', get_string('required'), 'required', null);
         $mform->addRule('dbpass', get_string('required'), 'required', null);
-        $mform->addRule('prefix', get_string('required'), 'required', null);
+        if (!isset($drivers['mysqli/native'])) {
+            $mform->addRule('prefix', get_string('required'), 'required', null);
+        }
 
         $this->add_action_buttons(false, get_string('transferdata', 'tool_dbtransfer'));
     }
+
+    /**
+     * Validate prefix is present for non-mysql drivers.
+     * @param array $data
+     * @param array $files
+     * @return array
+     */
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+        if ($data['driver'] !== 'mysqli/native') {
+            // This is a bloody hack, let's pretend we do not need to look at db family...
+            if ($data['prefix'] === '') {
+                $errors['prefix'] = get_string('required');
+            }
+        }
+        return $errors;
+    }
 }
diff --git a/admin/tool/dbtransfer/index.php b/admin/tool/dbtransfer/index.php
index d806dfb..a86d27a 100644
--- a/admin/tool/dbtransfer/index.php
+++ b/admin/tool/dbtransfer/index.php
@@ -33,6 +33,7 @@ admin_externalpage_setup('tooldbtransfer');
 
 // Create the form.
 $form = new database_transfer_form();
+$problem = '';
 
 // If we have valid input.
 if ($data = $form->get_data()) {
@@ -46,28 +47,33 @@ if ($data = $form->get_data()) {
     if ($data->dbsocket) {
         $dboptions['dbsocket'] = $data->dbsocket;
     }
-    if (!$targetdb->connect($data->dbhost, $data->dbuser, $data->dbpass, $data->dbname, $data->prefix, $dboptions)) {
-        throw new dbtransfer_exception('notargetconectexception', null, "$CFG->wwwroot/$CFG->admin/tool/dbtransfer/");
-    }
-    if ($targetdb->get_tables()) {
-        throw new dbtransfer_exception('targetdatabasenotempty', null, "$CFG->wwwroot/$CFG->admin/tool/dbtransfer/");
+    try {
+        $targetdb->connect($data->dbhost, $data->dbuser, $data->dbpass, $data->dbname, $data->prefix, $dboptions);
+        if ($targetdb->get_tables()) {
+            $problem .= get_string('targetdatabasenotempty', 'tool_dbtransfer');
+        }
+    } catch (moodle_exception $e) {
+        $problem .= html_writer::tag('h3', get_string('notargetconectexception', 'tool_dbtransfer'));
+        $problem .= $e->getMessage().'<br />'.$e->debuginfo;
     }
 
-    // Start output.
-    echo $OUTPUT->header();
-    $data->dbtype = $dbtype;
-    echo $OUTPUT->heading(get_string('transferringdbto', 'tool_dbtransfer', $data));
+    if ($problem === '') {
+        // Start output.
+        echo $OUTPUT->header();
+        $data->dbtype = $dbtype;
+        echo $OUTPUT->heading(get_string('transferringdbto', 'tool_dbtransfer', $data));
 
-    // Do the transfer.
-    $feedback = new html_list_progress_trace();
-    tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
-    $feedback->finished();
+        // Do the transfer.
+        $feedback = new html_list_progress_trace();
+        tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
+        $feedback->finished();
 
-    // Finish up.
-    echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
-    echo $OUTPUT->continue_button("$CFG->wwwroot/$CFG->admin/");
-    echo $OUTPUT->footer();
-    die;
+        // Finish up.
+        echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
+        echo $OUTPUT->continue_button("$CFG->wwwroot/$CFG->admin/");
+        echo $OUTPUT->footer();
+        die;
+    }
 }
 
 // Otherwise display the settings form.
@@ -75,4 +81,7 @@ echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('transferdbtoserver', 'tool_dbtransfer'));
 echo '<p>', get_string('transferdbintro', 'tool_dbtransfer'), "</p>\n\n";
 $form->display();
+if ($problem !== '') {
+    echo $OUTPUT->box($problem, 'generalbox error');
+}
 echo $OUTPUT->footer();
diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index a117117..448183b 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -27,6 +27,7 @@ $string['dbtransfer'] = 'Database transfer';
 $string['exportdata'] = 'Export data';
 $string['notargetconectexception'] = 'Can not connect target database, sorry.';
 $string['pluginname'] = 'Database transfer';
+$string['targetdatabasenotempty'] = 'Target database must not contain any tables with given prefix!';
 $string['transferdata'] = 'Transfer data';
 $string['transferdbintro'] = 'This script will transfer the entire contents of this database to another database server.';
 $string['transferdbtoserver'] = 'Transfer this Moodle database to another server';
diff --git a/admin/tool/dbtransfer/locallib.php b/admin/tool/dbtransfer/locallib.php
index 140691d..8e5d2d6 100644
--- a/admin/tool/dbtransfer/locallib.php
+++ b/admin/tool/dbtransfer/locallib.php
@@ -84,3 +84,40 @@ function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_dat
     $var = new database_mover($sourcedb, $targetdb, true, $feedback);
     $var->export_database(null);
 }
+
+/**
+ * Returns list of fully working database drivers present in system.
+ * @return array
+ */
+function tool_dbtransfer_get_drivers() {
+    global $CFG;
+
+    $files = new RegexIterator(new DirectoryIterator("$CFG->libdir/dml"), '|^.*_moodle_database\.php$|');
+    $drivers = array();
+
+    foreach ($files as $file) {
+        $matches = null;
+        preg_match('|^([a-z0-9]+)_([a-z]+)_moodle_database\.php$|', $file->getFilename(), $matches);
+        if (!$matches) {
+            continue;
+        }
+        $dbtype = $matches[1];
+        $dblibrary = $matches[2];
+
+        if ($dbtype === 'sqlite3') {
+            // Ignored unfinished.
+            continue;
+        }
+
+        $targetdb = moodle_database::get_driver_instance($dbtype, $dblibrary, false);
+        if ($targetdb->driver_installed() !== true) {
+            continue;
+        }
+
+        $driver = $dbtype.'/'.$dblibrary;
+
+        $drivers[$driver] = $targetdb->get_name();
+    };
+
+    return $drivers;
+}
-- 
1.7.9.5


From 05e43411659c3bbce5b50f190350d75475901db6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 13:17:15 +0200
Subject: [PATCH 229/903] MDL-34441 rewrite log display actions after db
 migration

---
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |    1 +
 admin/tool/dbtransfer/locallib.php                |   39 ++++++++++++++++++++-
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index 448183b..24c013c 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -22,6 +22,7 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['convertinglogdisplay'] = 'Converting log display actions';
 $string['dbexport'] = 'Database export';
 $string['dbtransfer'] = 'Database transfer';
 $string['exportdata'] = 'Export data';
diff --git a/admin/tool/dbtransfer/locallib.php b/admin/tool/dbtransfer/locallib.php
index 8e5d2d6..b0c27a1 100644
--- a/admin/tool/dbtransfer/locallib.php
+++ b/admin/tool/dbtransfer/locallib.php
@@ -83,6 +83,43 @@ function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_dat
 
     $var = new database_mover($sourcedb, $targetdb, true, $feedback);
     $var->export_database(null);
+
+    tool_dbtransfer_rebuild_target_log_actions($targetdb, $feedback);
+}
+
+/**
+ * Very hacky function for rebuilding of log actions in target database.
+ * @param moodle_database $target
+ * @param progress_trace $feedback
+ * @return void
+ * @throws Exception on conversion error
+ */
+function tool_dbtransfer_rebuild_target_log_actions(moodle_database $target, progress_trace $feedback = null) {
+    global $DB, $CFG;
+    require_once("$CFG->libdir/upgradelib.php");
+
+    $feedback->output(get_string('convertinglogdisplay', 'tool_dbtransfer'));
+
+    $olddb = $DB;
+    $DB = $target;
+    try {
+        $DB->delete_records('log_display', array('component'=>'moodle'));
+        log_update_descriptions('moodle');
+        $plugintypes = get_plugin_types();
+        foreach ($plugintypes as $type=>$location) {
+            $plugs = get_plugin_list($type);
+            foreach ($plugs as $plug=>$fullplug) {
+                $component = $type.'_'.$plug;
+                $DB->delete_records('log_display', array('component'=>$component));
+                log_update_descriptions($component);
+            }
+        }
+    } catch (Exception $e) {
+        $DB = $olddb;
+        throw $e;
+    }
+    $DB = $olddb;
+    $feedback->output(get_string('done', 'core_dbtransfer', null), 1);
 }
 
 /**
@@ -105,7 +142,7 @@ function tool_dbtransfer_get_drivers() {
         $dblibrary = $matches[2];
 
         if ($dbtype === 'sqlite3') {
-            // Ignored unfinished.
+            // Blacklist unfinished drivers.
             continue;
         }
 
-- 
1.7.9.5


From 56db97bb5c0ccb2adeae55eb3744b71494ac59bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 13:23:04 +0200
Subject: [PATCH 230/903] MDL-34441 scroll to the bottom when db migration
 finished

---
 admin/tool/dbtransfer/index.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/admin/tool/dbtransfer/index.php b/admin/tool/dbtransfer/index.php
index a86d27a..4dd133c 100644
--- a/admin/tool/dbtransfer/index.php
+++ b/admin/tool/dbtransfer/index.php
@@ -58,6 +58,9 @@ if ($data = $form->get_data()) {
     }
 
     if ($problem === '') {
+        // Scroll down to the bottom when finished.
+        $PAGE->requires->js_init_code("window.scrollTo(0, 5000000);");
+
         // Start output.
         echo $OUTPUT->header();
         $data->dbtype = $dbtype;
-- 
1.7.9.5


From 7b293e01260af898d5d32e20d706748202baef07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 17:49:59 +0200
Subject: [PATCH 231/903] MDL-34441 add maintenance mode to db migration and
 improve lang strings

---
 admin/tool/dbtransfer/database_transfer_form.php  |   15 ++++---
 admin/tool/dbtransfer/index.php                   |   30 ++++++++++---
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |   11 +++--
 admin/tool/dbtransfer/locallib.php                |   49 +++++++++++++++++++++
 4 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/admin/tool/dbtransfer/database_transfer_form.php b/admin/tool/dbtransfer/database_transfer_form.php
index 73ed927..9f89b50 100644
--- a/admin/tool/dbtransfer/database_transfer_form.php
+++ b/admin/tool/dbtransfer/database_transfer_form.php
@@ -41,7 +41,7 @@ class database_transfer_form extends moodleform {
 
         $mform = $this->_form;
 
-        $mform->addElement('header', 'database', get_string('dbtransfer', 'tool_dbtransfer'));
+        $mform->addElement('header', 'database', get_string('targetdatabase', 'tool_dbtransfer'));
 
         $drivers = tool_dbtransfer_get_drivers();
         $drivers = array_reverse($drivers, true);
@@ -49,10 +49,10 @@ class database_transfer_form extends moodleform {
         $drivers = array_reverse($drivers, true);
 
         $mform->addElement('select', 'driver', get_string('dbtype', 'install'), $drivers);
-        $mform->addElement('text', 'dbhost', get_string('dbhost', 'install'));
-        $mform->addElement('text', 'dbname', get_string('database', 'install'));
-        $mform->addElement('text', 'dbuser', get_string('user'));
-        $mform->addElement('passwordunmask', 'dbpass', get_string('password'));
+        $mform->addElement('text', 'dbhost', get_string('databasehost', 'install'));
+        $mform->addElement('text', 'dbname', get_string('databasename', 'install'));
+        $mform->addElement('text', 'dbuser', get_string('databaseuser', 'install'));
+        $mform->addElement('passwordunmask', 'dbpass', get_string('databasepass', 'install'));
         $mform->addElement('text', 'prefix', get_string('dbprefix', 'install'));
         $mform->addElement('text', 'dbport', get_string('dbport', 'install'));
         if ($CFG->ostype !== 'WINDOWS') {
@@ -70,6 +70,11 @@ class database_transfer_form extends moodleform {
             $mform->addRule('prefix', get_string('required'), 'required', null);
         }
 
+        $mform->addElement('header', 'database', get_string('options', 'tool_dbtransfer'));
+
+        $mform->addElement('advcheckbox', 'enablemaintenance', get_string('enablemaintenance', 'tool_dbtransfer'));
+        $mform->addHelpButton('enablemaintenance', 'enablemaintenance', 'tool_dbtransfer');
+
         $this->add_action_buttons(false, get_string('transferdata', 'tool_dbtransfer'));
     }
 
diff --git a/admin/tool/dbtransfer/index.php b/admin/tool/dbtransfer/index.php
index 4dd133c..0e6e894 100644
--- a/admin/tool/dbtransfer/index.php
+++ b/admin/tool/dbtransfer/index.php
@@ -53,23 +53,38 @@ if ($data = $form->get_data()) {
             $problem .= get_string('targetdatabasenotempty', 'tool_dbtransfer');
         }
     } catch (moodle_exception $e) {
-        $problem .= html_writer::tag('h3', get_string('notargetconectexception', 'tool_dbtransfer'));
-        $problem .= $e->getMessage().'<br />'.$e->debuginfo;
+        $problem .= get_string('notargetconectexception', 'tool_dbtransfer').'<br />'.$e->debuginfo;
     }
 
     if ($problem === '') {
         // Scroll down to the bottom when finished.
         $PAGE->requires->js_init_code("window.scrollTo(0, 5000000);");
 
+        // Enable CLI maintenance mode if requested.
+        if ($data->enablemaintenance) {
+            $PAGE->set_pagelayout('maintenance');
+            tool_dbtransfer_create_maintenance_file();
+        }
+
         // Start output.
         echo $OUTPUT->header();
         $data->dbtype = $dbtype;
         echo $OUTPUT->heading(get_string('transferringdbto', 'tool_dbtransfer', $data));
 
         // Do the transfer.
-        $feedback = new html_list_progress_trace();
-        tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
-        $feedback->finished();
+        $CFG->tool_dbransfer_migration_running = true;
+        try {
+            $feedback = new html_list_progress_trace();
+            tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
+            $feedback->finished();
+        } catch (Exception $e) {
+            if ($data->enablemaintenance) {
+                tool_dbtransfer_maintenance_callback();
+            }
+            unset($CFG->tool_dbransfer_migration_running);
+            throw $e;
+        }
+        unset($CFG->tool_dbransfer_migration_running);
 
         // Finish up.
         echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
@@ -82,7 +97,10 @@ if ($data = $form->get_data()) {
 // Otherwise display the settings form.
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('transferdbtoserver', 'tool_dbtransfer'));
-echo '<p>', get_string('transferdbintro', 'tool_dbtransfer'), "</p>\n\n";
+
+$info = format_text(get_string('transferdbintro', 'tool_dbtransfer'), FORMAT_MARKDOWN);
+echo $OUTPUT->box($info);
+
 $form->display();
 if ($problem !== '') {
     echo $OUTPUT->box($problem, 'generalbox error');
diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index 24c013c..3872879 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -15,22 +15,27 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Strings for component 'tool_generator', language 'en', branch 'MOODLE_22_STABLE'
+ * Strings for component 'tool_generator', language 'en'.
  *
  * @package    tool_dbtransfer
  * @copyright  2011 Petr Skoda {@link http://skodak.org/}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['climigrationnotice'] = 'Database migration in progress, please wait until the migration completes and server administrator updates configuration and deletes the $CFG->dataroot/climaintenance.html file.';
 $string['convertinglogdisplay'] = 'Converting log display actions';
 $string['dbexport'] = 'Database export';
-$string['dbtransfer'] = 'Database transfer';
+$string['dbtransfer'] = 'Database migration';
+$string['enablemaintenance'] = 'Enable maintenance mode';
+$string['enablemaintenance_help'] = 'This option enables maintanance mode during and after the database migration, it prevents access of all users until the migration is completed. Please note that administrator has to manually delete $CFG->dataroot/climaintenance.html file after updating config.php settings to resume normal operation.';
 $string['exportdata'] = 'Export data';
 $string['notargetconectexception'] = 'Can not connect target database, sorry.';
+$string['options'] = 'Options';
 $string['pluginname'] = 'Database transfer';
+$string['targetdatabase'] = 'Target database';
 $string['targetdatabasenotempty'] = 'Target database must not contain any tables with given prefix!';
 $string['transferdata'] = 'Transfer data';
-$string['transferdbintro'] = 'This script will transfer the entire contents of this database to another database server.';
+$string['transferdbintro'] = 'This script will transfer the entire contents of this database to another database server. It is often used for migration of data to different database type.';
 $string['transferdbtoserver'] = 'Transfer this Moodle database to another server';
 $string['transferringdbto'] = 'Transferring this database to {$a->dbtype} database {$a->dbname} on {$a->dbhost}';
 
diff --git a/admin/tool/dbtransfer/locallib.php b/admin/tool/dbtransfer/locallib.php
index b0c27a1..6a553eb 100644
--- a/admin/tool/dbtransfer/locallib.php
+++ b/admin/tool/dbtransfer/locallib.php
@@ -158,3 +158,52 @@ function tool_dbtransfer_get_drivers() {
 
     return $drivers;
 }
+
+/**
+ * Create CLI maintenance file to prevent all access.
+ */
+function tool_dbtransfer_create_maintenance_file() {
+    global $CFG;
+
+    register_shutdown_function('tool_dbtransfer_maintenance_callback');
+
+    $options = new stdClass();
+    $options->trusted = false;
+    $options->noclean = false;
+    $options->smiley = false;
+    $options->filter = false;
+    $options->para = true;
+    $options->newlines = false;
+
+    $message = format_text(get_string('climigrationnotice', 'tool_dbtransfer'), FORMAT_MARKDOWN, $options);
+    $message = bootstrap_renderer::early_error_content($message, '', '', array());
+    $html = <<<OET
+<!DOCTYPE html>
+<html>
+<header><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><header/>
+<body>$message</body>
+</html>
+OET;
+
+    file_put_contents("$CFG->dataroot/climaintenance.html", $html);
+    @chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
+}
+
+/**
+ * This callback is responsible for unsetting maintenance mode
+ * if the migration is interrupted.
+ */
+function tool_dbtransfer_maintenance_callback() {
+    global $CFG;
+
+    if (empty($CFG->tool_dbransfer_migration_running)) {
+        // Migration was finished properly - keep the maintenance file in place.
+        return;
+    }
+
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        // Failed migration, revert to normal site operation.
+        unlink("$CFG->dataroot/climaintenance.html");
+        error_log('tool_dbtransfer: Interrupted database migration detected, switching off CLI maintenance mode.');
+    }
+}
-- 
1.7.9.5


From de25ddd331c82a1ef8ce565235c6918c88758a8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 20:56:22 +0200
Subject: [PATCH 232/903] MDL-34441 add CLI database migration script

---
 admin/tool/dbtransfer/cli/migrate.php             |  186 +++++++++++++++++++++
 admin/tool/dbtransfer/index.php                   |    1 +
 admin/tool/dbtransfer/lang/en/tool_dbtransfer.php |    4 +-
 3 files changed, 190 insertions(+), 1 deletion(-)
 create mode 100644 admin/tool/dbtransfer/cli/migrate.php

diff --git a/admin/tool/dbtransfer/cli/migrate.php b/admin/tool/dbtransfer/cli/migrate.php
new file mode 100644
index 0000000..545be35
--- /dev/null
+++ b/admin/tool/dbtransfer/cli/migrate.php
@@ -0,0 +1,186 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This script migrates data from current database to another
+ *
+ * This script is not intended for beginners!
+ * Potential problems:
+ * - su to apache account or sudo before execution
+ * - already broken DB scheme or invalid data
+ *
+ * @package    tool_dbtransfer
+ * @copyright  2012 Petr Skoda {@link http://skodak.org/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(__DIR__.'/../../../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+require_once(__DIR__.'/../locallib.php');
+
+$help =
+    "Database migration script.
+
+It is strongly recommended to turn off the web server
+or enable CLI maintenance mode before starting the migration.
+
+Options:
+--dbtype=TYPE         Database type.
+--dblibrary=TYPE      Database library. Defaults to 'native'.
+--dbhost=HOST         Database host.
+--dbname=NAME         Database name.
+--dbuser=USERNAME     Database user.
+--dbpass=PASSWORD     Database password.
+--dbport=NUMBER       Database port.
+--prefix=STRING       Table prefix for above database tables.
+--dbsocket=PATH       Use database sockets. Available for some databases only.
+-h, --help            Print out this help.
+
+Example:
+\$ sudo -u www-data /usr/bin/php admin/tool/dbtransfer/cli/migrate.php
+";
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'dbtype'            => null,
+        'dblibrary'         => 'native',
+        'dbhost'            => null,
+        'dbname'            => null,
+        'dbuser'            => null,
+        'dbpass'            => null,
+        'dbport'            => null,
+        'prefix'            => null,
+        'dbsocket'          => null,
+        'maintenance'       => null,
+        'list'              => false,
+        'help'              => false,
+    ),
+    array(
+        'm' => 'maintenance',
+        'l' => 'list',
+        'h' => 'help',
+    )
+);
+
+if ($options['help']) {
+    echo $help;
+    exit(0);
+}
+
+echo "\n".get_string('cliheading', 'tool_dbtransfer')."\n\n";
+
+
+$drivers = tool_dbtransfer_get_drivers();
+
+if (!isset($options['dbtype'])) {
+    $choose = array();
+    foreach ($drivers as $driver=>$name) {
+        list($dbtype, $dblibrary) = explode('/', $driver);
+        $choose[$dbtype] = $dbtype;
+    }
+    $optionsstr = implode(', ', $choose);
+    cli_heading(get_string('databasetypehead', 'install')." ($optionsstr)");
+    $options['dbtype'] = cli_input(get_string('clitypevalue', 'admin'), '', $choose, true);
+}
+
+$choose = array();
+foreach ($drivers as $driver=>$name) {
+    list($dbtype, $dblibrary) = explode('/', $driver);
+    if ($dbtype === $options['dbtype']) {
+        $choose[$dblibrary] = $dblibrary;
+    }
+}
+if (!isset($options['dblibrary']) or !isset($choose[$options['dblibrary']])) {
+    $optionsstr = implode(', ', $choose);
+    cli_heading('Database library'." ($optionsstr)"); // note: no need to localise unless we add real PDO drivers
+    $options['dblibrary'] = cli_input(get_string('clitypevalue', 'admin'), '', $choose, true);
+}
+
+if (!isset($options['dbhost'])) {
+    cli_heading(get_string('databasehost', 'install'));
+    $options['dbhost'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if (!isset($options['dbname'])) {
+    cli_heading(get_string('databasename', 'install'));
+    $options['dbname'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if (!isset($options['dbuser'])) {
+    cli_heading(get_string('databaseuser', 'install'));
+    $options['dbuser'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if (!isset($options['dbpass'])) {
+    cli_heading(get_string('databasepass', 'install'));
+    $options['dbpass'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if (!isset($options['prefix'])) {
+    cli_heading(get_string('dbprefix', 'install'));
+    $options['prefix'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if (!isset($options['dbport'])) {
+    cli_heading(get_string('dbport', 'install'));
+    $options['dbport'] = cli_input(get_string('clitypevalue', 'admin'));
+}
+
+if ($CFG->ostype !== 'WINDOWS') {
+    if (!isset($options['dbsocket'])) {
+        cli_heading(get_string('databasesocket', 'install'));
+        $options['dbsocket'] = cli_input(get_string('clitypevalue', 'admin'));
+    }
+}
+
+$a = (object)array('dbtypefrom'=>$CFG->dbtype, 'dbtype'=>$options['dbtype'], 'dbname'=>$options['dbname'], 'dbhost'=>$options['dbhost']);
+cli_heading(get_string('transferringdbto', 'tool_dbtransfer', $a));
+
+// Try target DB connection.
+$problem = '';
+
+$targetdb = moodle_database::get_driver_instance($options['dbtype'], $options['dblibrary']);
+$dboptions = array();
+if ($options['dbport']) {
+    $dboptions['dbport'] = $options['dbport'];
+}
+if ($options['dbsocket']) {
+    $dboptions['dbsocket'] = $options['dbsocket'];
+}
+try {
+    $targetdb->connect($options['dbhost'], $options['dbuser'], $options['dbpass'], $options['dbname'], $options['prefix'], $dboptions);
+    if ($targetdb->get_tables()) {
+        $problem .= get_string('targetdatabasenotempty', 'tool_dbtransfer');
+    }
+} catch (moodle_exception $e) {
+    $problem .= $e->debuginfo."\n\n";
+    $problem .= get_string('notargetconectexception', 'tool_dbtransfer');
+}
+
+if ($problem !== '') {
+    echo $problem."\n\n";
+    exit(1);
+}
+
+$feedback = new text_progress_trace();
+tool_dbtransfer_transfer_database($DB, $targetdb, $feedback);
+$feedback->finished();
+
+cli_heading(get_string('success'));
+exit(0);
diff --git a/admin/tool/dbtransfer/index.php b/admin/tool/dbtransfer/index.php
index 0e6e894..aa8b5b3 100644
--- a/admin/tool/dbtransfer/index.php
+++ b/admin/tool/dbtransfer/index.php
@@ -69,6 +69,7 @@ if ($data = $form->get_data()) {
         // Start output.
         echo $OUTPUT->header();
         $data->dbtype = $dbtype;
+        $data->dbtypefrom = $CFG->dbtype;
         echo $OUTPUT->heading(get_string('transferringdbto', 'tool_dbtransfer', $data));
 
         // Do the transfer.
diff --git a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
index 3872879..a67a3e9 100644
--- a/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
+++ b/admin/tool/dbtransfer/lang/en/tool_dbtransfer.php
@@ -22,6 +22,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['clidriverlist'] = 'Available database drivers for migration';
+$string['cliheading'] = 'Database migration - make sure nobody is accessing the server during migration!';
 $string['climigrationnotice'] = 'Database migration in progress, please wait until the migration completes and server administrator updates configuration and deletes the $CFG->dataroot/climaintenance.html file.';
 $string['convertinglogdisplay'] = 'Converting log display actions';
 $string['dbexport'] = 'Database export';
@@ -37,5 +39,5 @@ $string['targetdatabasenotempty'] = 'Target database must not contain any tables
 $string['transferdata'] = 'Transfer data';
 $string['transferdbintro'] = 'This script will transfer the entire contents of this database to another database server. It is often used for migration of data to different database type.';
 $string['transferdbtoserver'] = 'Transfer this Moodle database to another server';
-$string['transferringdbto'] = 'Transferring this database to {$a->dbtype} database {$a->dbname} on {$a->dbhost}';
+$string['transferringdbto'] = 'Transferring this {$a->dbtypefrom} database to {$a->dbtype} database "{$a->dbname}" on "{$a->dbhost}"';
 
-- 
1.7.9.5


From 38e269ead9243eba1b81a04cdef3ad1278ee9784 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 22 Jul 2012 21:01:31 +0200
Subject: [PATCH 233/903] MDL-34441  bump up version to trigger cache purging

---
 admin/tool/dbtransfer/version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/admin/tool/dbtransfer/version.php b/admin/tool/dbtransfer/version.php
index 18cd386..53113be 100644
--- a/admin/tool/dbtransfer/version.php
+++ b/admin/tool/dbtransfer/version.php
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012061700; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012062200; // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012061700; // Requires this Moodle version
 $plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics)
-- 
1.7.9.5


From b843a44e1672a4e5357adcf6707fe0748be2a08e Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 22 Jul 2012 17:55:59 +0100
Subject: [PATCH 234/903] MDL-34370 theme_fusion: added CSS in style/core.css
 to enable weeks to be moved when editing

---
 theme/fusion/style/core.css |   22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/theme/fusion/style/core.css b/theme/fusion/style/core.css
index cfdb62b..bc31d35 100644
--- a/theme/fusion/style/core.css
+++ b/theme/fusion/style/core.css
@@ -58,7 +58,7 @@ blockquote {
     font-size: 1.2em;
     border: 1px solid #eee;
     padding: 2px 5px;
-    background: #fff;
+    background-color: #fff;
 }
 
 img{
@@ -276,12 +276,20 @@ h2.headingblock {
     margin-left: 0;
 }
 
+.editing .course-content .weeks .section.main .content {
+    margin-left: 40px;
+}
+
 .course-content .weeks .section.main .left {
     display: none;
 }
 
+.editing .course-content .weeks .section.main .left {
+    display: block;
+}
+
 .course-content .section.main.current {
-    background:#fffcdc;
+    background-color: #fffcdc;
 }
 
 .course-content .weeks .section.main h3.weekdates {
@@ -289,9 +297,10 @@ h2.headingblock {
 }
 
 .course-content .current .left,
-.course-content .current h3.weekdates {
-    color: #2d83d5 !important;
+.course-content .current h3.sectionname {
+    color: #2d83d5;
 }
+
 /* Forum
 --------------------------*/
 
@@ -318,12 +327,11 @@ h2.headingblock {
     padding: 5px 10px 10px;
 }
 
-
 /* Dock
 ----------------------*/
 
 #dock {
-    background: #eee;
+    background-color: #eee;
     border: none;
 }
 
@@ -354,7 +362,7 @@ h2.headingblock {
 #dockeditempanel .dockeditempanel_hd {
     border-bottom: none;
     padding: 3px 5px;
-    background: #eee;
+    background-color: #eee;
     text-align: left;
 }
 
-- 
1.7.9.5


From a6fa8a7265d96c3d161575f5793856eeb10dda01 Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaron.barnes@hbcosmo.com>
Date: Tue, 10 Jul 2012 21:05:41 +1200
Subject: [PATCH 235/903] MDL-34243 completion: get_criteria() incorrectly
 passing object

---
 lib/completion/completion_criteria_completion.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/completion/completion_criteria_completion.php b/lib/completion/completion_criteria_completion.php
index 7f44800..dabe552 100644
--- a/lib/completion/completion_criteria_completion.php
+++ b/lib/completion/completion_criteria_completion.php
@@ -153,7 +153,7 @@ class completion_criteria_completion extends data_object {
 
             $record = $DB->get_record('course_completion_criteria', $params);
 
-            $this->attach_criteria(completion_criteria::factory($record));
+            $this->attach_criteria(completion_criteria::factory((array) $record));
         }
 
         return $this->_criteria;
-- 
1.7.9.5


From 5b37ed3dda36a0a468b4a81a977a8959e9fb7044 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 23 Jul 2012 09:38:28 +1200
Subject: [PATCH 236/903] MDL-34243 completion: Fixed up call to
 completion_criteria::factory that was passing
 object

---
 course/togglecompletion.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/togglecompletion.php b/course/togglecompletion.php
index d720144..19a584b 100644
--- a/course/togglecompletion.php
+++ b/course/togglecompletion.php
@@ -53,7 +53,7 @@ if ($courseid) {
     if ($user && $rolec) {
         require_sesskey();
 
-        completion_criteria::factory((object) array('id'=>$rolec, 'criteriatype'=>COMPLETION_CRITERIA_TYPE_ROLE)); //TODO: this is dumb, because it does not fetch the data?!?!
+        completion_criteria::factory(array('id'=>$rolec, 'criteriatype'=>COMPLETION_CRITERIA_TYPE_ROLE)); //TODO: this is dumb, because it does not fetch the data?!?!
         $criteria = completion_criteria_role::fetch(array('id'=>$rolec));
 
         if ($criteria and user_has_role_assignment($USER->id, $criteria->role, $context->id)) {
-- 
1.7.9.5


From 7fac90712bdc03840390c1512b4ecac24e03498f Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Fri, 13 Jul 2012 15:01:37 +0100
Subject: [PATCH 237/903] MDL-34322 Don't display empty navigation nodes which
 have no link

---
 blocks/navigation/renderer.php |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/blocks/navigation/renderer.php b/blocks/navigation/renderer.php
index fe91aed..4c3d28c 100644
--- a/blocks/navigation/renderer.php
+++ b/blocks/navigation/renderer.php
@@ -77,6 +77,11 @@ class block_navigation_renderer extends plugin_renderer_base {
             $isexpandable = (empty($expansionlimit) || ($item->type > navigation_node::TYPE_ACTIVITY || $item->type < $expansionlimit) || ($item->contains_active_node() && $item->children->count() > 0));
             $isbranch = $isexpandable && ($item->children->count() > 0 || ($item->has_children() && (isloggedin() || $item->type <= navigation_node::TYPE_CATEGORY)));
 
+            // Skip elements which have no content and no action - no point in showing them
+            if (!$isexpandable && empty($item->action)) {
+                continue;
+            }
+
             $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY || $item->type == navigation_node::TYPE_RESOURCE) && $item->icon instanceof renderable);
 
             if ($hasicon) {
-- 
1.7.9.5


From 392ee02d6c53e3a9f497308f1e15591e0a345211 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 13:11:46 +0800
Subject: [PATCH 238/903] MDL-2283: Display number of assignment submissions
 that need grading in the grading summary

---
 mod/assign/lang/en/assign.php |    1 +
 mod/assign/locallib.php       |   24 +++++++++++++++++++++++-
 mod/assign/renderable.php     |    7 ++++++-
 mod/assign/renderer.php       |    2 ++
 4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index 47b6d89..5b2438b 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -173,6 +173,7 @@ $string['nousersselected'] = 'No users selected';
 $string['numberofdraftsubmissions'] = 'Drafts';
 $string['numberofparticipants'] = 'Participants';
 $string['numberofsubmittedassignments'] = 'Submitted';
+$string['numberofsubmissionsneedgrading'] = 'Needs grading';
 $string['offline'] = 'No online submissions required';
 $string['overdue'] = '<font color="red">Assignment is overdue by: {$a}</font>';
 $string['outlinegrade'] = 'Grade: {$a}';
diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 85ff77e..2fc4195 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -968,6 +968,27 @@ class assign {
     }
 
     /**
+     * Load a count of users submissions in the current module that require grading
+     * This means the submission modification time is more recent than the
+     * grading modification time.
+     *
+     * @return int number of matching submissions
+     */
+    public function count_submissions_need_grading() {
+        global $DB;
+
+        $params = array($this->get_course_module()->instance);
+
+        return $DB->count_records_sql("SELECT COUNT('x')
+                                       FROM {assign_submission} s
+                                       LEFT JOIN {assign_grades} g ON s.assignment = g.assignment AND s.userid = g.userid
+                                       WHERE s.assignment = ?
+                                           AND s.timemodified IS NOT NULL
+                                           AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)",
+                                       $params);
+    }
+
+    /**
      * Load a count of users enrolled in the current course with the specified permission and group (optional)
      *
      * @param string $status The submission status - should match one of the constants
@@ -2091,7 +2112,8 @@ class assign {
                                                             $this->is_any_submission_plugin_enabled(),
                                                             $this->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED),
                                                             $this->get_instance()->duedate,
-                                                            $this->get_course_module()->id
+                                                            $this->get_course_module()->id,
+                                                            $this->count_submissions_need_grading()
                                                             ));
         }
         $grade = $this->get_user_grade($USER->id, false);
diff --git a/mod/assign/renderable.php b/mod/assign/renderable.php
index cb1daf9..5e710a4 100644
--- a/mod/assign/renderable.php
+++ b/mod/assign/renderable.php
@@ -405,6 +405,8 @@ class assign_grading_summary implements renderable {
     var $submissionsenabled = false;
     /** @var int submissionssubmittedcount - The number of submissions in submitted status */
     var $submissionssubmittedcount = 0;
+    /** @var int submissionsneedgradingcount - The number of submissions that need grading */
+    var $submissionsneedgradingcount = 0;
     /** @var int duedate - The assignment due date (if one is set) */
     var $duedate = 0;
     /** @var int coursemoduleid - The assignment course module id */
@@ -421,7 +423,9 @@ class assign_grading_summary implements renderable {
      * @param int $duedate
      * @param int $coursemoduleid
      */
-    public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount, $submissionsenabled, $submissionssubmittedcount, $duedate, $coursemoduleid) {
+    public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount,
+                                $submissionsenabled, $submissionssubmittedcount,
+                                $duedate, $coursemoduleid, $submissionsneedgradingcount) {
         $this->participantcount = $participantcount;
         $this->submissiondraftsenabled = $submissiondraftsenabled;
         $this->submissiondraftscount = $submissiondraftscount;
@@ -429,6 +433,7 @@ class assign_grading_summary implements renderable {
         $this->submissionssubmittedcount = $submissionssubmittedcount;
         $this->duedate = $duedate;
         $this->coursemoduleid = $coursemoduleid;
+        $this->submissionsneedgradingcount = $submissionsneedgradingcount;
     }
 
 
diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php
index ab3af8a..8ffe18f 100644
--- a/mod/assign/renderer.php
+++ b/mod/assign/renderer.php
@@ -248,6 +248,8 @@ class mod_assign_renderer extends plugin_renderer_base {
         if ($summary->submissionsenabled) {
             $this->add_table_row_tuple($t, get_string('numberofsubmittedassignments', 'assign'),
                                        $summary->submissionssubmittedcount);
+            $this->add_table_row_tuple($t, get_string('numberofsubmissionsneedgrading', 'assign'),
+                                       $summary->submissionsneedgradingcount);
         }
 
         $time = time();
-- 
1.7.9.5


From 145a300b73379b71a104f296ef779290825df897 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 11:44:55 +0800
Subject: [PATCH 239/903] MDL-34256: Grading table shows users with no
 submissions with "requires grading" filter

Also hide the filters completely if there are no submission plugins enabled (offline assignment).
---
 mod/assign/gradingoptionsform.php |    4 +++-
 mod/assign/gradingtable.php       |    2 +-
 mod/assign/locallib.php           |    7 ++++++-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/mod/assign/gradingoptionsform.php b/mod/assign/gradingoptionsform.php
index cf90c86..3e6e54b 100644
--- a/mod/assign/gradingoptionsform.php
+++ b/mod/assign/gradingoptionsform.php
@@ -52,7 +52,9 @@ class mod_assign_grading_options_form extends moodleform {
         $options = array('' => get_string('filternone', 'assign'),
                          ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'),
                          ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign'));
-        $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+        if ($instance['submissionsenabled']) {
+            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+        }
 
         // quickgrading
         if ($instance['showquickgrading']) {
diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index abd5b72..be0eb3d 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -105,7 +105,7 @@ class assign_grading_table extends table_sql implements renderable {
             $where .= ' AND s.timecreated > 0 ';
         }
         if ($filter == ASSIGN_FILTER_REQUIRE_GRADING) {
-            $where .= ' AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)';
+            $where .= ' AND (s.timemodified > g.timemodified OR (s.timemodified IS NOT NULL AND g.timemodified IS NULL))';
         }
         if (strpos($filter, ASSIGN_FILTER_SINGLE_USER) === 0) {
             $userfilter = (int) array_pop(explode('=', $filter));
diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 2fc4195..8c538fd 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -1745,6 +1745,7 @@ class assign {
                                                                   array('cm'=>$this->get_course_module()->id,
                                                                         'contextid'=>$this->context->id,
                                                                         'userid'=>$USER->id,
+                                                                        'submissionsenabled'=>$this->is_any_submission_plugin_enabled(),
                                                                         'showquickgrading'=>$showquickgrading,
                                                                         'quickgrading'=>$quickgrading),
                                                                   'post', '',
@@ -2673,7 +2674,11 @@ class assign {
         // Need submit permission to submit an assignment
         require_capability('mod/assign:grade', $this->context);
 
-        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id, 'showquickgrading'=>false));
+        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id,
+                                                                 'contextid'=>$this->context->id,
+                                                                 'userid'=>$USER->id,
+                                                                 'submissionsenabled'=>$this->is_any_submission_plugin_enabled(),
+                                                                 'showquickgrading'=>false));
         if ($formdata = $mform->get_data()) {
             set_user_preference('assign_perpage', $formdata->perpage);
             set_user_preference('assign_filter', $formdata->filter);
-- 
1.7.9.5


From 943036314f6b8f15c0a7a0f3f5be7c7347ac8511 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 10:38:13 +0800
Subject: [PATCH 240/903] MDL-34272: Assignment module displays all
 assignments on my moodle instead of just open ones

---
 mod/assign/lib.php |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index caccf10..a6cdba7 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -212,16 +212,13 @@ function assign_print_overview($courses, &$htmlarray) {
     // Do assignment_base::isopen() here without loading the whole thing for speed
     foreach ($assignments as $key => $assignment) {
         $time = time();
+        $isopen = $assignment->allowsubmissionsfromdate <= $time;
         if ($assignment->duedate) {
             if ($assignment->preventlatesubmissions) {
-                $isopen = ($assignment->allowsubmissionsfromdate <= $time && $time <= $assignment->duedate);
-            } else {
-                $isopen = ($assignment->allowsubmissionsfromdate <= $time);
+                $isopen = ($isopen && $time <= $assignment->duedate);
             }
         }
-        if (empty($isopen) || empty($assignment->duedate)) {
-            $assignmentids[] = $assignment->id;
-        } else {
+        if ($isopen) {
             $assignmentids[] = $assignment->id;
         }
     }
@@ -265,6 +262,10 @@ function assign_print_overview($courses, &$htmlarray) {
                             AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
 
     foreach ($assignments as $assignment) {
+        // Do not show assignments that are not open
+        if (!in_array($assignment->id, $assignmentids)) {
+            continue;
+        }
         $str = '<div class="assign overview"><div class="name">'.$strassignment. ': '.
                '<a '.($assignment->visible ? '':' class="dimmed"').
                'title="'.$strassignment.'" href="'.$CFG->wwwroot.
-- 
1.7.9.5


From c8ac7e7938a90a27669bcdcd48882d05e562f39e Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 13 Jul 2012 12:40:25 +0800
Subject: [PATCH 241/903] MDL-34313: Deleting assignfeedback plugins deletes
 config for assignsubmission_plugin instead.

---
 mod/assign/adminlib.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mod/assign/adminlib.php b/mod/assign/adminlib.php
index a6b2eb1..43c1e7d 100644
--- a/mod/assign/adminlib.php
+++ b/mod/assign/adminlib.php
@@ -269,7 +269,7 @@ class assign_plugin_manager {
 
         if ($confirm) {
             // Delete any configuration records.
-            if (!unset_all_config_for_plugin('assignsubmission_' . $plugin)) {
+            if (!unset_all_config_for_plugin($this->subtype . '_' . $plugin)) {
                 $this->error = $OUTPUT->notification(get_string('errordeletingconfig', 'admin', $this->subtype . '_' . $plugin));
             }
 
@@ -282,7 +282,8 @@ class assign_plugin_manager {
             $DB->delete_records('assign_plugin_config', array('plugin'=>$plugin, 'subtype'=>$this->subtype));
 
             // Then the tables themselves
-            drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $this->subtype . '/' .$plugin. '/db/install.xml', false);
+            $shortsubtype = substr($this->subtype, strlen('assign'));
+            drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $shortsubtype . '/' .$plugin. '/db/install.xml', false);
 
             // Remove event handlers and dequeue pending events
             events_uninstall($this->subtype . '_' . $plugin);
-- 
1.7.9.5


From 548f536a00ccc484086f235989ed618f76854d3c Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Mon, 9 Jul 2012 20:50:35 +0100
Subject: [PATCH 242/903] MDL-33927 Filemanager - enforce the maxfiles limit
 on form submission

---
 lang/en/form.php |    1 +
 lib/formslib.php |   16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/lang/en/form.php b/lang/en/form.php
index fbd8c9d..d55667d 100644
--- a/lang/en/form.php
+++ b/lang/en/form.php
@@ -30,6 +30,7 @@ $string['display'] = 'Display';
 $string['err_alphanumeric'] = 'You must enter only letters or numbers here.';
 $string['err_email'] = 'You must enter a valid email address here.';
 $string['err_lettersonly'] = 'You must enter only letters here.';
+$string['err_maxfiles'] = 'You must not attach more than {$a} files here.';
 $string['err_maxlength'] = 'You must enter not more than {$a->format} characters here.';
 $string['err_minlength'] = 'You must enter at least {$a->format} characters here.';
 $string['err_nonzero'] = 'You must enter a number not starting with a 0 here.';
diff --git a/lib/formslib.php b/lib/formslib.php
index d02d332..77b960e 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -406,6 +406,22 @@ abstract class moodleform {
                 }
             }
         }
+        // Check all the filemanager elements to make sure they do not have too many
+        // files in them.
+        foreach ($mform->_elements as $element) {
+            if ($element->_type == 'filemanager') {
+                $maxfiles = $element->getMaxfiles();
+                if ($maxfiles > 0) {
+                    $draftid = (int)$element->getValue();
+                    $fs = get_file_storage();
+                    $context = context_user::instance($USER->id);
+                    $files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, '', false);
+                    if (count($files) > $maxfiles) {
+                        $errors[$element->getName()] = get_string('err_maxfiles', 'form', $maxfiles);
+                    }
+                }
+            }
+        }
         if (empty($errors)) {
             return true;
         } else {
-- 
1.7.9.5


From 252bd1871ba5ada341545ecf644b47224ae3a46a Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Mon, 9 Jul 2012 21:39:34 +0100
Subject: [PATCH 243/903] MDL-34221 Filepicker - disableIf now prevents drag
 and drop upload

---
 lib/form/dndupload.js            |   14 ++++++++++++++
 lib/form/form.js                 |    4 ++++
 theme/base/style/filemanager.css |    2 ++
 3 files changed, 20 insertions(+)

diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js
index 53018b9..0cdeeee 100644
--- a/lib/form/dndupload.js
+++ b/lib/form/dndupload.js
@@ -166,10 +166,21 @@ M.form_dndupload.init = function(Y, options) {
         },
 
         /**
+         * Check if the filemanager / filepicker is disabled
+         * @return bool - true if disabled
+         */
+        is_disabled: function() {
+            return this.container.hasClass('disabled');
+        },
+
+        /**
          * Show the 'drop files here' message when file(s) are dragged
          * onto the page
          */
         drag_enter_page: function(e) {
+            if (this.is_disabled()) {
+                return false;
+            }
             if (!this.has_files(e)) {
                 return false;
             }
@@ -210,6 +221,9 @@ M.form_dndupload.init = function(Y, options) {
          * @return boolean true if a valid file drag event
          */
         check_drag: function(e) {
+            if (this.is_disabled()) {
+                return false;
+            }
             if (!this.has_files(e)) {
                 return false;
             }
diff --git a/lib/form/form.js b/lib/form/form.js
index 938fab6..2dd75f4 100644
--- a/lib/form/form.js
+++ b/lib/form/form.js
@@ -211,10 +211,14 @@ M.form.initFormDependencies = function(Y, formid, dependencies) {
                     if (this.getAttribute('class') == 'filepickerhidden'){
                         var pickerbuttons = form.elementsByName(name + 'choose');
                         pickerbuttons.each(function(){
+                            var clientid = this.get('id').split('-')[2];
+                            var filepicker = Y.one('#file_info_'+clientid);
                             if (disabled){
                                 this.setAttribute('disabled','disabled');
+                                filepicker.addClass('disabled');
                             } else {
                                 this.removeAttribute('disabled');
+                                filepicker.removeClass('disabled');
                             }
                         });
                     }
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 5fbacc3..99cdb99 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -326,6 +326,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*
  * Drag and drop support (File Manager only)
  */
+.filepicker-filelist.disabled {background-color:#ddd;}
+.filepicker-filelist.disabled .filepicker-filename {display:none;}
 .filepicker-filelist .filepicker-container,
 .filemanager.fm-noitems .fm-empty-container {display:block;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #BBBBBB;padding-top:85px;text-align:center;z-index: 3000;}
 .filepicker-filelist .dndupload-target,
-- 
1.7.9.5


From 9ff506d165b5e7c05529f8e70f889bb5507e1272 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Fri, 13 Jul 2012 16:02:21 +0800
Subject: [PATCH 244/903] MDL-34221 disabledIf support for filemanager and
 filepicker elements

---
 lib/form/dndupload.js            |    2 +-
 lib/form/filemanager.js          |   21 +++++++++++++++++++--
 lib/form/filepicker.js           |    4 +++-
 lib/form/form.js                 |   22 ++++++++--------------
 lib/outputrenderers.php          |    2 +-
 theme/base/style/filemanager.css |   12 +++++++++---
 6 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js
index 0cdeeee..bbadd5c 100644
--- a/lib/form/dndupload.js
+++ b/lib/form/dndupload.js
@@ -170,7 +170,7 @@ M.form_dndupload.init = function(Y, options) {
          * @return bool - true if disabled
          */
         is_disabled: function() {
-            return this.container.hasClass('disabled');
+            return (this.container.ancestor('.fitem.disabled') != null);
         },
 
         /**
diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js
index 164c683..cbd528a 100644
--- a/lib/form/filemanager.js
+++ b/lib/form/filemanager.js
@@ -255,6 +255,9 @@ M.form_filemanager.init = function(Y, options) {
             this.msg_dlg_node.one('.fp-msg-text').setContent(msg);
             this.msg_dlg.show();
         },
+        is_disabled: function() {
+            return this.filemanager.ancestor('.fitem.disabled') != null;
+        },
         setup_buttons: function() {
             var button_download = this.filemanager.one('.fp-btn-download');
             var button_create   = this.filemanager.one('.fp-btn-mkdir');
@@ -272,6 +275,9 @@ M.form_filemanager.init = function(Y, options) {
             if (this.options.subdirs) {
                 button_create.on('click',function(e) {
                     e.preventDefault();
+                    if (this.is_disabled()) {
+                        return;
+                    }
                     var scope = this;
                     // a function used to perform an ajax request
                     var perform_action = function(e) {
@@ -325,6 +331,9 @@ M.form_filemanager.init = function(Y, options) {
             // setup 'download this folder' button
             button_download.on('click',function(e) {
                 e.preventDefault();
+                if (this.is_disabled()) {
+                    return;
+                }
                 var scope = this;
                 // perform downloaddir ajax request
                 this.request({
@@ -351,7 +360,7 @@ M.form_filemanager.init = function(Y, options) {
                 on('click', function(e) {
                     e.preventDefault();
                     var viewbar = this.filemanager.one('.fp-viewbar')
-                    if (!viewbar || !viewbar.hasClass('disabled')) {
+                    if (!this.is_disabled() && (!viewbar || !viewbar.hasClass('disabled'))) {
                         this.filemanager.all('.fp-vb-icons,.fp-vb-tree,.fp-vb-details').removeClass('checked')
                         if (e.currentTarget.hasClass('fp-vb-tree')) {
                             this.viewmode = 2;
@@ -369,6 +378,9 @@ M.form_filemanager.init = function(Y, options) {
         show_filepicker: function (e) {
             // if maxfiles == -1, the no limit
             e.preventDefault();
+            if (this.is_disabled()) {
+                return;
+            }
             var options = this.filepicker_options;
             options.formcallback = this.filepicker_callback;
             // XXX: magic here, to let filepicker use filemanager scope
@@ -400,7 +412,9 @@ M.form_filemanager.init = function(Y, options) {
                     el.one('.fp-path-folder-name').setContent(p[i].name).
                         on('click', function(e, path) {
                             e.preventDefault();
-                            this.refresh(path);
+                            if (!this.is_disabled()) {
+                                this.refresh(path);
+                            }
                         }, this, p[i].path);
                 }
                 this.pathbar.removeClass('empty');
@@ -873,6 +887,9 @@ M.form_filemanager.init = function(Y, options) {
             return node.filepath;
         },
         select_file: function(node) {
+            if (this.is_disabled()) {
+                return;
+            }
             var selectnode = this.selectnode;
             selectnode.removeClass('loading').removeClass('fp-folder').
                 removeClass('fp-file').removeClass('fp-zip').removeClass('fp-cansetmain');
diff --git a/lib/form/filepicker.js b/lib/form/filepicker.js
index e372a23..b2811a2 100644
--- a/lib/form/filepicker.js
+++ b/lib/form/filepicker.js
@@ -32,7 +32,9 @@ M.form_filepicker.init = function(Y, options) {
     }
     Y.on('click', function(e, client_id) {
         e.preventDefault();
-        M.core_filepicker.instances[client_id].show();
+        if (this.ancestor('.fitem.disabled') == null) {
+            M.core_filepicker.instances[client_id].show();
+        }
     }, '#filepicker-button-'+options.client_id, null, options.client_id);
 
     var item = document.getElementById('nonjs-filepicker-'+options.client_id);
diff --git a/lib/form/form.js b/lib/form/form.js
index 2dd75f4..b49d76a 100644
--- a/lib/form/form.js
+++ b/lib/form/form.js
@@ -207,20 +207,14 @@ M.form.initFormDependencies = function(Y, formid, dependencies) {
                         this.removeAttribute('disabled');
                     }
 
-                    // Extra code to disable a filepicker
-                    if (this.getAttribute('class') == 'filepickerhidden'){
-                        var pickerbuttons = form.elementsByName(name + 'choose');
-                        pickerbuttons.each(function(){
-                            var clientid = this.get('id').split('-')[2];
-                            var filepicker = Y.one('#file_info_'+clientid);
-                            if (disabled){
-                                this.setAttribute('disabled','disabled');
-                                filepicker.addClass('disabled');
-                            } else {
-                                this.removeAttribute('disabled');
-                                filepicker.removeClass('disabled');
-                            }
-                        });
+                    // Extra code to disable filepicker or filemanager form elements
+                    var fitem = this.ancestor('.fitem');
+                    if (fitem && (fitem.hasClass('fitem_ffilemanager') || fitem.hasClass('fitem_ffilepicker'))) {
+                        if (disabled){
+                            fitem.addClass('disabled');
+                        } else {
+                            fitem.removeClass('disabled');
+                        }
                     }
                 })
             },
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index b2d0e49..e800b8f 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -2050,7 +2050,7 @@ $icon_progress
 </div>
 <div id="filepicker-wrapper-{$client_id}" class="mdl-left" style="display:none">
     <div>
-        <input type="button" id="filepicker-button-{$client_id}" value="{$straddfile}"{$buttonname}/>
+        <input type="button" class="fp-btn-choose" id="filepicker-button-{$client_id}" value="{$straddfile}"{$buttonname}/>
         <span> $maxsize </span>
     </div>
 EOD;
diff --git a/theme/base/style/filemanager.css b/theme/base/style/filemanager.css
index 99cdb99..ed52934 100644
--- a/theme/base/style/filemanager.css
+++ b/theme/base/style/filemanager.css
@@ -275,6 +275,10 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager.fm-updating .filemanager-updating {display:block;margin-top: 37px;}
 .filemanager.fm-updating .fm-content-wrapper {display:none;}
 .filemanager.fm-nomkdir .fp-btn-mkdir {display:none;}
+.fitem.disabled .filemanager .filemanager-toolbar,
+.fitem.disabled .filemanager .fp-pathbar,
+.fitem.disabled .filemanager .fp-restrictions,
+.fitem.disabled .filemanager .fm-content-wrapper {display:none;}
 
  /*
  * File Manager layout
@@ -292,6 +296,9 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager-container ul li a{padding:0}*/
 .filemanager .fp-content{overflow: auto;max-height: 472px;min-height: 157px;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
+.fitem.disabled .filepicker-filelist, .fitem.disabled .filemanager-container {background-color:#EBEBE4;}
+.fitem.disabled .fp-btn-choose {color:graytext;}
+.fitem.disabled .filepicker-filelist .filepicker-filename {display:none;}
 
 /*
  * Icon view (File Manager only)
@@ -324,10 +331,8 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager .fp-tableview .fp-folder.fp-hascontextmenu .fp-contextmenu {display: inline;position: absolute;left: 14px;margin-right: -20px;top: 6px;}
 
 /*
- * Drag and drop support (File Manager only)
+ * Drag and drop support (filemanager and filepicker form elements)
  */
-.filepicker-filelist.disabled {background-color:#ddd;}
-.filepicker-filelist.disabled .filepicker-filename {display:none;}
 .filepicker-filelist .filepicker-container,
 .filemanager.fm-noitems .fm-empty-container {display:block;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #BBBBBB;padding-top:85px;text-align:center;z-index: 3000;}
 .filepicker-filelist .dndupload-target,
@@ -341,6 +346,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .dndupload-uploadinprogress {display:none;text-align:center;}
 .dndupload-uploading .dndupload-uploadinprogress {display:block;}
 .dndupload-arrow {background:url([[pix:theme|fp/dnd_arrow]]) center no-repeat;width:60px;height:80px;position:absolute;margin-left: -28px;top: 5px;}
+.fitem.disabled .filepicker-container, .fitem.disabled .fm-empty-container {display:none;}
 
 /*
  * Select Dialogue (File Manager only)
-- 
1.7.9.5


From e7a3fe032f66a9826198522c09dd2fbf3504e93f Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Fri, 20 Jul 2012 13:32:47 +0800
Subject: [PATCH 245/903] MDL-34428 Private files repository should have a
 'manage' link

---
 repository/user/lib.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/repository/user/lib.php b/repository/user/lib.php
index 98c7384..c7d7f3c 100644
--- a/repository/user/lib.php
+++ b/repository/user/lib.php
@@ -56,6 +56,8 @@ class repository_user extends repository {
         $ret['dynload'] = true;
         $ret['nosearch'] = true;
         $ret['nologin'] = true;
+        $manageurl = new moodle_url('/user/files.php');
+        $ret['manage'] = $manageurl->out();
         $list = array();
 
         if (!empty($encodedpath)) {
-- 
1.7.9.5


From 60a1365d28f859f35f01f1c088fe95ec5302d0ab Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 23 Jul 2012 11:27:28 +0800
Subject: [PATCH 246/903] MDL-26969 Assignment module - upload: fixed
 get_submission() return value to nothing when param
 is set to false.

---
 mod/assignment/lib.php                |   10 ++++++----
 mod/assignment/type/upload/upload.php |    8 ++++++--
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index eea2714..6997e28 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1820,10 +1820,10 @@ class assignment_base {
      *
      * @global object
      * @global object
-     * @param $userid int The id of the user whose submission we want or 0 in which case USER->id is used
-     * @param $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database
+     * @param int $userid int The id of the user whose submission we want or 0 in which case USER->id is used
+     * @param bool $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database
      * @param bool $teachermodified student submission set if false
-     * @return object The submission
+     * @return object|bool The submission or false if $createnew is false.
      */
     function get_submission($userid=0, $createnew=false, $teachermodified=false) {
         global $USER, $DB;
@@ -1834,8 +1834,10 @@ class assignment_base {
 
         $submission = $DB->get_record('assignment_submissions', array('assignment'=>$this->assignment->id, 'userid'=>$userid));
 
-        if ($submission || !$createnew) {
+        if ($submission) {
             return $submission;
+        } else if(!$createnew) {
+            return false;
         }
         $newsubmission = $this->prepare_new_submission($userid, $teachermodified);
         $DB->insert_record("assignment_submissions", $newsubmission);
diff --git a/mod/assignment/type/upload/upload.php b/mod/assignment/type/upload/upload.php
index 36bba5a..e0f79f4 100644
--- a/mod/assignment/type/upload/upload.php
+++ b/mod/assignment/type/upload/upload.php
@@ -59,7 +59,7 @@ $PAGE->set_title($title);
 $PAGE->set_heading($title);
 
 $instance = new assignment_upload($cm->id, $assignment, $cm, $course);
-$submission = $instance->get_submission($formdata->userid, true);
+$submission = $instance->get_submission($formdata->userid, false);
 
 $filemanager_options = array('subdirs'=>1, 'maxbytes'=>$assignment->maxbytes, 'maxfiles'=>$assignment->var1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
 
@@ -77,8 +77,12 @@ echo $OUTPUT->header();
 echo $OUTPUT->box_start('generalbox');
 if ($instance->can_upload_file($submission) && ($id==null)) {
     $data = new stdClass();
+    $submissionid = null;
+    if (is_object($submission) && isset($submission->id)) {
+        $submissionid = $submission->id;
+    }
     // move submission files to user draft area
-    $data = file_prepare_standard_filemanager($data, 'files', $filemanager_options, $context, 'mod_assignment', 'submission', $submission->id);
+    $data = file_prepare_standard_filemanager($data, 'files', $filemanager_options, $context, 'mod_assignment', 'submission', $submissionid);
     // set file manager itemid, so it will find the files in draft area
     $mform->set_data($data);
     $mform->display();
-- 
1.7.9.5


From 82a0137aa54131287512ad5a894bb001391c0018 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 19 Jul 2012 17:09:50 +0800
Subject: [PATCH 247/903] MDL-27083 Questions: Orphaned questions are adopted
 on upgrade

Conflicts:

	version.php
---
 lang/en/question.php |    2 ++
 lib/db/upgrade.php   |    8 ++++++++
 lib/upgradelib.php   |   41 +++++++++++++++++++++++++++++++++++++++++
 version.php          |    2 +-
 4 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/lang/en/question.php b/lang/en/question.php
index d0cf1a4..dfa1aeb 100644
--- a/lang/en/question.php
+++ b/lang/en/question.php
@@ -230,6 +230,8 @@ $string['novirtualquestiontype'] = 'No virtual question type for question type {
 $string['numqas'] = 'No. question attempts';
 $string['numquestions'] = 'No. questions';
 $string['numquestionsandhidden'] = '{$a->numquestions} (+{$a->numhidden} hidden)';
+$string['orphanedquestionscategory'] = 'Questions saved from deleted categories';
+$string['orphanedquestionscategoryinfo'] = 'Occasionally, typically due to old software bugs, questions can remain in the database even though the corresponding question category has been deleted. Of course, this should not happen, it has happened in the past on this site. This category has been created automatically, and the orphaned questions moved here so that you can manage them. Note that any images or media files used by these questions have probably been lost.';
 $string['page-question-x'] = 'Any question page';
 $string['page-question-edit'] = 'Question editing page';
 $string['page-question-category'] = 'Question category page';
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 75e165f..9dd53d2 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -914,6 +914,14 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.01);
     }
 
+    if ($oldversion < 2012062501.04) {
+
+        // Saves orphaned questions from the Dark Side
+        upgrade_save_orphaned_questions();
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012062501.04);
+    }
 
     return true;
 }
diff --git a/lib/upgradelib.php b/lib/upgradelib.php
index aa6ee8f..c299ffe 100644
--- a/lib/upgradelib.php
+++ b/lib/upgradelib.php
@@ -1839,3 +1839,44 @@ function upgrade_course_completion_remove_duplicates($table, $uniques, $fieldsto
         }
     }
 }
+
+/**
+ * Find questions missing an existing category and associate them with
+ * a category which purpose is to gather them.
+ *
+ * @return void
+ */
+function upgrade_save_orphaned_questions() {
+    global $DB;
+
+    // Looking for orphaned questions
+    $orphans = $DB->record_exists_select('question',
+            'NOT EXISTS (SELECT 1 FROM {question_categories} WHERE {question_categories}.id = {question}.category)');
+    if (!$orphans) {
+        return;
+    }
+
+    // Generate a unique stamp for the orphaned questions category, easier to identify it later on
+    $uniquestamp = "unknownhost+120719170400+orphan";
+    $systemcontext = context_system::instance();
+
+    // Create the orphaned category at system level
+    $cat = $DB->get_record('question_categories', array('stamp' => $uniquestamp,
+            'contextid' => $systemcontext->id));
+    if (!$cat) {
+        $cat = new stdClass();
+        $cat->parent = 0;
+        $cat->contextid = $systemcontext->id;
+        $cat->name = get_string('orphanedquestionscategory', 'question');
+        $cat->info = get_string('orphanedquestionscategoryinfo', 'question');
+        $cat->sortorder = 999;
+        $cat->stamp = $uniquestamp;
+        $cat->id = $DB->insert_record("question_categories", $cat);
+    }
+
+    // Set a category to those orphans
+    $params = array('catid' => $cat->id);
+    $DB->execute('UPDATE {question} SET category = :catid WHERE NOT EXISTS
+            (SELECT 1 FROM {question_categories} WHERE {question_categories}.id = {question}.category)', $params);
+}
+
diff --git a/version.php b/version.php
index 1e9ff4b..0e39207 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.03;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.04;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 5147d726b23655d516bfb8b38fe125d4529283aa Mon Sep 17 00:00:00 2001
From: Erik Lundberg <lundbergerik@gmail.com>
Date: Tue, 10 Jul 2012 18:51:23 +0200
Subject: [PATCH 248/903] MDL-34148: Instead of using the module name from the
 filesystem, the blog menu now fetches the module
 name with get_string().

---
 blog/lib.php |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/blog/lib.php b/blog/lib.php
index ab9fd52..6ed50a7 100644
--- a/blog/lib.php
+++ b/blog/lib.php
@@ -608,11 +608,14 @@ function blog_get_options_for_module($module, $user=null) {
     $canparticipate = (is_enrolled($modcontext) or is_viewing($modcontext));
 
     if (has_capability('moodle/blog:view', $modcontext)) {
+        // Save the correct module name for later usage
+        $module_name = strtolower(get_string('modulename', $module->modname)); 
+
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
             // View all entries about this module
             $a = new stdClass;
-            $a->type = $module->modname;
+            $a->type = $module_name;
             $options['moduleview'] = array(
                 'string' => get_string('viewallmodentries', 'blog', $a),
                 'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id))
@@ -620,13 +623,13 @@ function blog_get_options_for_module($module, $user=null) {
         }
         // View MY entries about this module
         $options['moduleviewmine'] = array(
-            'string' => get_string('viewmyentriesaboutmodule', 'blog', $module->modname),
+            'string' => get_string('viewmyentriesaboutmodule', 'blog', $module_name),
             'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
             // View the given users entries about this module
             $a = new stdClass;
-            $a->mod = $module->modname;
+            $a->mod = $module_name;
             $a->user = fullname($user);
             $options['moduleviewuser'] = array(
                 'string' => get_string('blogentriesbyuseraboutmodule', 'blog', $a),
@@ -638,7 +641,7 @@ function blog_get_options_for_module($module, $user=null) {
     if (has_capability('moodle/blog:create', $sitecontext) and $canparticipate) {
         // The user can blog about this module
         $options['moduleadd'] = array(
-            'string' => get_string('blogaboutthismodule', 'blog', $module->modname),
+            'string' => get_string('blogaboutthismodule', 'blog', $module_name),
             'link' => new moodle_url('/blog/edit.php', array('action'=>'add', 'modid'=>$module->id))
         );
     }
-- 
1.7.9.5


From e4f2ea1a429150b74a94e01c3797e9b32fc57622 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 17 Jul 2012 15:21:27 +0800
Subject: [PATCH 249/903] MDL-34148 Blog: Fixed variable name used for saving
 module name

Updated Erik's patch to match coding style
---
 blog/lib.php |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/blog/lib.php b/blog/lib.php
index 6ed50a7..8a3b687 100644
--- a/blog/lib.php
+++ b/blog/lib.php
@@ -608,14 +608,14 @@ function blog_get_options_for_module($module, $user=null) {
     $canparticipate = (is_enrolled($modcontext) or is_viewing($modcontext));
 
     if (has_capability('moodle/blog:view', $modcontext)) {
-        // Save the correct module name for later usage
-        $module_name = strtolower(get_string('modulename', $module->modname)); 
+        // Save correct module name for later usage.
+        $modulename = get_string('modulename', $module->modname);
 
         // We can view!
         if ($CFG->bloglevel >= BLOG_SITE_LEVEL) {
             // View all entries about this module
             $a = new stdClass;
-            $a->type = $module_name;
+            $a->type = $modulename;
             $options['moduleview'] = array(
                 'string' => get_string('viewallmodentries', 'blog', $a),
                 'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id))
@@ -623,13 +623,13 @@ function blog_get_options_for_module($module, $user=null) {
         }
         // View MY entries about this module
         $options['moduleviewmine'] = array(
-            'string' => get_string('viewmyentriesaboutmodule', 'blog', $module_name),
+            'string' => get_string('viewmyentriesaboutmodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
             // View the given users entries about this module
             $a = new stdClass;
-            $a->mod = $module_name;
+            $a->mod = $modulename;
             $a->user = fullname($user);
             $options['moduleviewuser'] = array(
                 'string' => get_string('blogentriesbyuseraboutmodule', 'blog', $a),
@@ -641,7 +641,7 @@ function blog_get_options_for_module($module, $user=null) {
     if (has_capability('moodle/blog:create', $sitecontext) and $canparticipate) {
         // The user can blog about this module
         $options['moduleadd'] = array(
-            'string' => get_string('blogaboutthismodule', 'blog', $module_name),
+            'string' => get_string('blogaboutthismodule', 'blog', $modulename),
             'link' => new moodle_url('/blog/edit.php', array('action'=>'add', 'modid'=>$module->id))
         );
     }
-- 
1.7.9.5


From bb9b19a7fddf6dfe4195071bba2910add38ffec2 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Mon, 23 Jul 2012 16:39:25 +0800
Subject: [PATCH 250/903] MDL-34449 phpdoc typo correction

---
 lib/pagelib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pagelib.php b/lib/pagelib.php
index 6023314..36172c7 100644
--- a/lib/pagelib.php
+++ b/lib/pagelib.php
@@ -492,8 +492,8 @@ class moodle_page {
     }
 
     /**
-     * Please do not call this method directly, use the ->layout_tions syntax. {@link moodle_page::__get()}.
-     * @return array returns arrys with options for layout file
+     * Please do not call this method directly, use the ->layout_options syntax. {@link moodle_page::__get()}.
+     * @return array returns arrays with options for layout file
      */
     protected function magic_get_layout_options() {
         if (!is_array($this->_layout_options)) {
-- 
1.7.9.5


From 53e2f1aad80ba1f49b5e1819e685c73b29566041 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 23 Jul 2012 11:08:37 +0100
Subject: [PATCH 251/903] MDL-34484 unit tests: stop phpunit using testcase
 names as class names

---
 lib/phpunit/classes/util.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index 93aecf7..3380549 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -925,7 +925,7 @@ class phpunit_util {
         global $CFG;
 
         $template = '
-        <testsuite name="@component@">
+        <testsuite name="@component@ test suite">
             <directory suffix="_test.php">@dir@</directory>
         </testsuite>';
         $data = file_get_contents("$CFG->dirroot/phpunit.xml.dist");
-- 
1.7.9.5


From e2ecc7c6cc5066e6ecfe97f8cb55cd10c5799611 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Mon, 23 Jul 2012 20:48:14 +0200
Subject: [PATCH 252/903] MDL-34475 add default value to xmldb_field hash
 calculation

---
 lib/xmldb/xmldb_field.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/xmldb/xmldb_field.php b/lib/xmldb/xmldb_field.php
index ce919d9..7c69407 100644
--- a/lib/xmldb/xmldb_field.php
+++ b/lib/xmldb/xmldb_field.php
@@ -493,9 +493,10 @@ class xmldb_field extends xmldb_object {
         if (!$this->loaded) {
             $this->hash = null;
         } else {
+            $defaulthash = is_null($this->default) ? '' : sha1($this->default);
             $key = $this->name . $this->type . $this->length .
                    $this->notnull . $this->sequence .
-                   $this->decimals . $this->comment;
+                   $this->decimals . $this->comment . $defaulthash;
             $this->hash = md5($key);
         }
     }
-- 
1.7.9.5


From 2902afd555fe1bc03a5e711fc761da49c9d64858 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 24 Jul 2012 00:31:53 +0000
Subject: [PATCH 253/903] Automatically generated installer lang files

---
 install/lang/sw/langconfig.php |   34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 install/lang/sw/langconfig.php

diff --git a/install/lang/sw/langconfig.php b/install/lang/sw/langconfig.php
new file mode 100644
index 0000000..2c93731
--- /dev/null
+++ b/install/lang/sw/langconfig.php
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = 'Kiswahili';
-- 
1.7.9.5


From 81fa4095f282b980a5dc18faf0313415a967a404 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Tue, 24 Jul 2012 16:35:41 +0800
Subject: [PATCH 254/903] MDL-26969 assignment : clarified phpdoc and fixed
 whitespace.

---
 mod/assignment/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index 6997e28..99d29c8 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1823,7 +1823,7 @@ class assignment_base {
      * @param int $userid int The id of the user whose submission we want or 0 in which case USER->id is used
      * @param bool $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database
      * @param bool $teachermodified student submission set if false
-     * @return object|bool The submission or false if $createnew is false.
+     * @return object|bool The submission or false (if $createnew is false and there is no existing submission).
      */
     function get_submission($userid=0, $createnew=false, $teachermodified=false) {
         global $USER, $DB;
@@ -1836,7 +1836,7 @@ class assignment_base {
 
         if ($submission) {
             return $submission;
-        } else if(!$createnew) {
+        } else if (!$createnew) {
             return false;
         }
         $newsubmission = $this->prepare_new_submission($userid, $teachermodified);
-- 
1.7.9.5


From f1631871b8b92fd284156aa498d097f6dd2a1781 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Tue, 24 Jul 2012 12:01:11 -0700
Subject: [PATCH 255/903] MDL-34519 - Course reset not protected by proper
 capability

---
 course/reset.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/reset.php b/course/reset.php
index cd0a66b..088c203 100644
--- a/course/reset.php
+++ b/course/reset.php
@@ -39,7 +39,7 @@ if (!$course = $DB->get_record('course', array('id'=>$id))) {
 $PAGE->set_url('/course/reset.php', array('id'=>$id));
 
 require_login($course);
-require_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id));
+require_capability('moodle/course:reset', get_context_instance(CONTEXT_COURSE, $course->id));
 
 $strreset       = get_string('reset');
 $strresetcourse = get_string('resetcourse');
-- 
1.7.9.5


From c237be89fbf3bae6ed885b3d10a456349050ed72 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 25 Jul 2012 10:43:37 +0800
Subject: [PATCH 256/903] MDL-34441 tool_dbtranfer - fix codechecker warnings

Since we were so close to perfection.
---
 admin/tool/dbtransfer/cli/migrate.php            |   12 +++++++-----
 admin/tool/dbtransfer/database_export_form.php   |   10 ++++++++--
 admin/tool/dbtransfer/database_transfer_form.php |    3 +++
 admin/tool/dbtransfer/dbexport.php               |    2 +-
 admin/tool/dbtransfer/locallib.php               |   10 +++++-----
 admin/tool/dbtransfer/settings.php               |    6 ++++--
 admin/tool/dbtransfer/version.php                |    6 +++---
 7 files changed, 31 insertions(+), 18 deletions(-)

diff --git a/admin/tool/dbtransfer/cli/migrate.php b/admin/tool/dbtransfer/cli/migrate.php
index 545be35..35b3be7 100644
--- a/admin/tool/dbtransfer/cli/migrate.php
+++ b/admin/tool/dbtransfer/cli/migrate.php
@@ -90,7 +90,7 @@ $drivers = tool_dbtransfer_get_drivers();
 
 if (!isset($options['dbtype'])) {
     $choose = array();
-    foreach ($drivers as $driver=>$name) {
+    foreach ($drivers as $driver => $name) {
         list($dbtype, $dblibrary) = explode('/', $driver);
         $choose[$dbtype] = $dbtype;
     }
@@ -100,7 +100,7 @@ if (!isset($options['dbtype'])) {
 }
 
 $choose = array();
-foreach ($drivers as $driver=>$name) {
+foreach ($drivers as $driver => $name) {
     list($dbtype, $dblibrary) = explode('/', $driver);
     if ($dbtype === $options['dbtype']) {
         $choose[$dblibrary] = $dblibrary;
@@ -108,7 +108,7 @@ foreach ($drivers as $driver=>$name) {
 }
 if (!isset($options['dblibrary']) or !isset($choose[$options['dblibrary']])) {
     $optionsstr = implode(', ', $choose);
-    cli_heading('Database library'." ($optionsstr)"); // note: no need to localise unless we add real PDO drivers
+    cli_heading('Database library'." ($optionsstr)"); // Note: no need to localise unless we add real PDO drivers.
     $options['dblibrary'] = cli_input(get_string('clitypevalue', 'admin'), '', $choose, true);
 }
 
@@ -149,7 +149,8 @@ if ($CFG->ostype !== 'WINDOWS') {
     }
 }
 
-$a = (object)array('dbtypefrom'=>$CFG->dbtype, 'dbtype'=>$options['dbtype'], 'dbname'=>$options['dbname'], 'dbhost'=>$options['dbhost']);
+$a = (object)array('dbtypefrom' => $CFG->dbtype, 'dbtype' => $options['dbtype'],
+    'dbname' => $options['dbname'], 'dbhost' => $options['dbhost']);
 cli_heading(get_string('transferringdbto', 'tool_dbtransfer', $a));
 
 // Try target DB connection.
@@ -164,7 +165,8 @@ if ($options['dbsocket']) {
     $dboptions['dbsocket'] = $options['dbsocket'];
 }
 try {
-    $targetdb->connect($options['dbhost'], $options['dbuser'], $options['dbpass'], $options['dbname'], $options['prefix'], $dboptions);
+    $targetdb->connect($options['dbhost'], $options['dbuser'], $options['dbpass'], $options['dbname'],
+        $options['prefix'], $dboptions);
     if ($targetdb->get_tables()) {
         $problem .= get_string('targetdatabasenotempty', 'tool_dbtransfer');
     }
diff --git a/admin/tool/dbtransfer/database_export_form.php b/admin/tool/dbtransfer/database_export_form.php
index 50646ad..1fb8b9c 100644
--- a/admin/tool/dbtransfer/database_export_form.php
+++ b/admin/tool/dbtransfer/database_export_form.php
@@ -29,10 +29,16 @@ require_once($CFG->libdir.'/formslib.php');
 
 /**
  * Definition of db export settings form.
+ *
+ * @package    tool_dbtransfer
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class database_export_form extends moodleform {
-
-    function definition() {
+    /**
+     * Define the export form.
+     */
+    public function definition() {
         $mform = $this->_form;
 
         $mform->addElement('header', 'database', get_string('dbexport', 'tool_dbtransfer'));
diff --git a/admin/tool/dbtransfer/database_transfer_form.php b/admin/tool/dbtransfer/database_transfer_form.php
index 9f89b50..d8a9923 100644
--- a/admin/tool/dbtransfer/database_transfer_form.php
+++ b/admin/tool/dbtransfer/database_transfer_form.php
@@ -30,6 +30,9 @@ require_once(__DIR__.'/locallib.php');
 
 /**
  * Definition of db transfer settings form.
+ *
+ * @copyright  2008 Petr Skoda {@link http://skodak.org/}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class database_transfer_form extends moodleform {
 
diff --git a/admin/tool/dbtransfer/dbexport.php b/admin/tool/dbtransfer/dbexport.php
index 2672cfd..f55b29d 100644
--- a/admin/tool/dbtransfer/dbexport.php
+++ b/admin/tool/dbtransfer/dbexport.php
@@ -40,6 +40,6 @@ if ($data = $form->get_data()) {
 }
 
 echo $OUTPUT->header();
-// TODO: add some more info here
+// TODO: add some more info here.
 $form->display();
 echo $OUTPUT->footer();
diff --git a/admin/tool/dbtransfer/locallib.php b/admin/tool/dbtransfer/locallib.php
index 6a553eb..8b0b062 100644
--- a/admin/tool/dbtransfer/locallib.php
+++ b/admin/tool/dbtransfer/locallib.php
@@ -52,7 +52,7 @@ require_once($CFG->libdir.'/dtllib.php');
 function tool_dbtransfer_export_xml_database($description, $mdb) {
     @set_time_limit(0);
 
-    session_get_instance()->write_close(); // release session
+    session_get_instance()->write_close(); // Release session.
 
     header('Content-Type: application/xhtml+xml; charset=utf-8');
     header('Content-Disposition: attachment; filename=database.xml');
@@ -65,7 +65,7 @@ function tool_dbtransfer_export_xml_database($description, $mdb) {
     $var = new file_xml_database_exporter('php://output', $mdb);
     $var->export_database($description);
 
-    // no more output
+    // No more output.
     die;
 }
 
@@ -79,7 +79,7 @@ function tool_dbtransfer_export_xml_database($description, $mdb) {
 function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_database $targetdb, progress_trace $feedback = null) {
     @set_time_limit(0);
 
-    session_get_instance()->write_close(); // release session
+    session_get_instance()->write_close(); // Release session.
 
     $var = new database_mover($sourcedb, $targetdb, true, $feedback);
     $var->export_database(null);
@@ -106,9 +106,9 @@ function tool_dbtransfer_rebuild_target_log_actions(moodle_database $target, pro
         $DB->delete_records('log_display', array('component'=>'moodle'));
         log_update_descriptions('moodle');
         $plugintypes = get_plugin_types();
-        foreach ($plugintypes as $type=>$location) {
+        foreach ($plugintypes as $type => $location) {
             $plugs = get_plugin_list($type);
-            foreach ($plugs as $plug=>$fullplug) {
+            foreach ($plugs as $plug => $fullplug) {
                 $component = $type.'_'.$plug;
                 $DB->delete_records('log_display', array('component'=>$component));
                 log_update_descriptions($component);
diff --git a/admin/tool/dbtransfer/settings.php b/admin/tool/dbtransfer/settings.php
index a1390ef..4717542 100644
--- a/admin/tool/dbtransfer/settings.php
+++ b/admin/tool/dbtransfer/settings.php
@@ -25,7 +25,9 @@
 defined('MOODLE_INTERNAL') || die;
 
 if ($hassiteconfig) {
-    $ADMIN->add('experimental', new admin_externalpage('tooldbtransfer', get_string('dbtransfer', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/index.php', 'moodle/site:config', false));
+    $ADMIN->add('experimental', new admin_externalpage('tooldbtransfer', get_string('dbtransfer', 'tool_dbtransfer'),
+        $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/index.php', 'moodle/site:config', false));
     // DB export/import is not ready yet - keep it hidden for now.
-    $ADMIN->add('experimental', new admin_externalpage('tooldbexport', get_string('dbexport', 'tool_dbtransfer'), $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/dbexport.php', 'moodle/site:config', true));
+    $ADMIN->add('experimental', new admin_externalpage('tooldbexport', get_string('dbexport', 'tool_dbtransfer'),
+        $CFG->wwwroot.'/'.$CFG->admin.'/tool/dbtransfer/dbexport.php', 'moodle/site:config', true));
 }
diff --git a/admin/tool/dbtransfer/version.php b/admin/tool/dbtransfer/version.php
index 53113be..59bafe5 100644
--- a/admin/tool/dbtransfer/version.php
+++ b/admin/tool/dbtransfer/version.php
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012062200; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2012061700; // Requires this Moodle version
-$plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2012062200; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2012061700; // Requires this Moodle version.
+$plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics).
-- 
1.7.9.5


From c54a83d8bd3552ba17e065c7f847664f1729ba4c Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 25 Jul 2012 11:26:55 +0800
Subject: [PATCH 257/903] MDL-34441 dbtransfer - do not attempt migration if
 moodle is not installed.

---
 admin/tool/dbtransfer/cli/migrate.php |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/admin/tool/dbtransfer/cli/migrate.php b/admin/tool/dbtransfer/cli/migrate.php
index 35b3be7..0d32e2a 100644
--- a/admin/tool/dbtransfer/cli/migrate.php
+++ b/admin/tool/dbtransfer/cli/migrate.php
@@ -83,8 +83,11 @@ if ($options['help']) {
     exit(0);
 }
 
-echo "\n".get_string('cliheading', 'tool_dbtransfer')."\n\n";
+if (empty($CFG->version)) {
+    cli_error(get_string('missingconfigversion', 'debug'));
+}
 
+echo "\n".get_string('cliheading', 'tool_dbtransfer')."\n\n";
 
 $drivers = tool_dbtransfer_get_drivers();
 
-- 
1.7.9.5


From a11b507f507084716875fb377b6f752458e1b7be Mon Sep 17 00:00:00 2001
From: Michael Aherne <michael.aherne@strath.ac.uk>
Date: Fri, 6 Jul 2012 15:14:10 +0100
Subject: [PATCH 258/903] MDL-34534 Backport activity chooser default setting
 to 2.3 stable

---
 admin/settings/appearance.php |    1 +
 course/lib.php                |    2 +-
 lang/en/admin.php             |    2 ++
 lib/navigationlib.php         |    2 +-
 4 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/admin/settings/appearance.php b/admin/settings/appearance.php
index b0272b8..9995af3 100644
--- a/admin/settings/appearance.php
+++ b/admin/settings/appearance.php
@@ -185,6 +185,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $setting = new admin_setting_configcheckbox('cachejs', new lang_string('cachejs', 'admin'), new lang_string('cachejs_help', 'admin'), 1);
     $setting->set_updatedcallback('js_reset_all_caches');
     $temp->add($setting);
+    $temp->add(new admin_setting_configcheckbox('modchooserdefault', new lang_string('modchooserdefault', 'admin'), new lang_string('configmodchooserdefault', 'admin'), 1));
     $ADMIN->add('appearance', $temp);
 
     // link to tag management interface
diff --git a/course/lib.php b/course/lib.php
index 36ef842..7565c45 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1869,7 +1869,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
         $modchooser.= html_writer::end_tag('div');
 
         // Wrap the normal output in a noscript div
-        $usemodchooser = get_user_preferences('usemodchooser', 1);
+        $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault);
         if ($usemodchooser) {
             $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown'));
             $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser'));
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 30253fd..974b2bc 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -253,6 +253,7 @@ $string['configminpasswordlength'] = 'Passwords must be at least these many char
 $string['configminpasswordlower'] = 'Passwords must have at least these many lower case letters.';
 $string['configminpasswordnonalphanum'] = 'Passwords must have at least these many non-alphanumeric characters.';
 $string['configminpasswordupper'] = 'Passwords must have at least these many upper case letters.';
+$string['configmodchooserdefault'] = 'Should the activity chooser be presented to users by default?';
 $string['configmycoursesperpage'] = 'Maximum number of courses to display in any list of a user\'s own courses';
 $string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
 $string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
@@ -679,6 +680,7 @@ $string['mnetrestore_extusers_admin'] = '<strong>Note:</strong> This backup file
 $string['mnetrestore_extusers_mismatch'] = '<strong>Note:</strong> This backup file apparently originates from a different Moodle installation and contains remote Moodle Network user accounts that may fail to restore. This operation is unsupported. If you are certain that it was created on this Moodle installation, or you can ensure that all the needed Moodle Network Hosts are configured, you may want to still try the restore.';
 $string['mnetrestore_extusers_noadmin'] = '<strong>Note:</strong> This backup file seems to come from a different Moodle installation and contains remote Moodle Network user accounts. You are not allowed to execute this type of restore. Contact the administrator of the site or, alternatively, restore this course without any user information (modules, files...)';
 $string['mnetrestore_extusers_switchuserauth'] = 'Remote Moodle Network user {$a->username} (coming from {$a->mnethosturl}) switched to local {$a->auth} authenticated user.';
+$string['modchooserdefault'] = 'Activity chooser default';
 $string['modeditdefaults'] = 'Default values for activity settings';
 $string['modsettings'] = 'Manage activities';
 $string['modulesecurity'] = 'Module security';
diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 82b3ad9..92f9029 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -3573,7 +3573,7 @@ class settings_navigation extends navigation_node {
             // Add the module chooser toggle
             $modchoosertoggleurl = clone($baseurl);
             if ($this->page->user_is_editing() && course_ajax_enabled($course)) {
-                if ($usemodchooser = get_user_preferences('usemodchooser', 1)) {
+                if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) {
                     $modchoosertogglestring = get_string('modchooserdisable', 'moodle');
                     $modchoosertoggleurl->param('modchooser', 'off');
                 } else {
-- 
1.7.9.5


From 993a4b8f5c40cdf5caa20bc45d92f527541708aa Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 26 Jul 2012 00:31:43 +0000
Subject: [PATCH 259/903] Automatically generated installer lang files

---
 install/lang/ga/langconfig.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/ga/langconfig.php b/install/lang/ga/langconfig.php
index cd9ab38..9cea86c 100644
--- a/install/lang/ga/langconfig.php
+++ b/install/lang/ga/langconfig.php
@@ -32,4 +32,4 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
-$string['thislanguage'] = 'Béarla';
+$string['thislanguage'] = 'Gaeilge';
-- 
1.7.9.5


From ffdccab055a923e45f389b1bef517a259ebdc3d2 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 26 Jul 2012 14:23:39 +0800
Subject: [PATCH 260/903] MDL-34255 group calendar events: fixed adding group
 calendar event for students

---
 calendar/event.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/calendar/event.php b/calendar/event.php
index 130e682..dbc0c32 100644
--- a/calendar/event.php
+++ b/calendar/event.php
@@ -123,10 +123,10 @@ if ($eventid !== 0) {
     $event = new stdClass();
     $event->action = $action;
     $event->course = $courseid;
+    $event->courseid = $courseid;
     $event->timeduration = 0;
     if ($formoptions->eventtypes->courses) {
         if (!$issite) {
-            $event->courseid = $courseid;
             $event->eventtype = 'course';
         } else {
             unset($formoptions->eventtypes->courses);
-- 
1.7.9.5


From 69752163364cc49dae5775839847b2375cc2b510 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Thu, 26 Jul 2012 14:25:58 +0800
Subject: [PATCH 261/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 0e39207..4d57f57 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.04;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.05;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120719)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120726)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 40ae563beeb2865258735b7b892f6137d635217f Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 26 Jul 2012 10:07:09 +0100
Subject: [PATCH 262/903] MDL-34532 quiz reports: error when showing users
 without attempts.

We were not checking if attempt state was null before trying to convert it to a string.
---
 mod/quiz/report/attemptsreport_table.php |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/report/attemptsreport_table.php b/mod/quiz/report/attemptsreport_table.php
index 4334256..f119da0 100644
--- a/mod/quiz/report/attemptsreport_table.php
+++ b/mod/quiz/report/attemptsreport_table.php
@@ -152,7 +152,11 @@ abstract class quiz_attempts_report_table extends table_sql {
      * @return string HTML content to go inside the td.
      */
     public function col_state($attempt) {
-        return quiz_attempt::state_name($attempt->state);
+        if (!is_null($attempt->attempt)) {
+            return quiz_attempt::state_name($attempt->state);
+        } else {
+            return  '-';
+        }
     }
 
     /**
-- 
1.7.9.5


From 59b983a5d9d642ff2541469fe5627f92301bea1d Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 26 Jul 2012 18:47:57 +0100
Subject: [PATCH 263/903] MDL-34589 quiz report graphs: PHP5.4 issue with
 unset($array[$float]).

Thanks to Matthew Davidson for diagnosing the problem.
---
 mod/quiz/report/overview/overviewgraph.php |    4 +++-
 mod/quiz/report/reportlib.php              |    7 ++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/mod/quiz/report/overview/overviewgraph.php b/mod/quiz/report/overview/overviewgraph.php
index c450615..6583ef9 100644
--- a/mod/quiz/report/overview/overviewgraph.php
+++ b/mod/quiz/report/overview/overviewgraph.php
@@ -89,7 +89,9 @@ while ($bands > 20 || $bands <= 10) {
     }
 }
 
-$bands = ceil($bands);
+// See MDL-34589. Using doubles as array keys causes problems in PHP 5.4,
+// hence the explicit cast to int.
+$bands = (int) ceil($bands);
 $bandwidth = $quiz->grade / $bands;
 $bandlabels = array();
 for ($i = 1; $i <= $bands; $i++) {
diff --git a/mod/quiz/report/reportlib.php b/mod/quiz/report/reportlib.php
index d3e4e99..344513e 100644
--- a/mod/quiz/report/reportlib.php
+++ b/mod/quiz/report/reportlib.php
@@ -191,6 +191,11 @@ function quiz_report_qm_filter_select($quiz, $quizattemptsalias = 'quiza') {
  */
 function quiz_report_grade_bands($bandwidth, $bands, $quizid, $userids = array()) {
     global $DB;
+    if (!is_int($bands)) {
+        debugging('$bands passed to quiz_report_grade_bands must be an integer. (' .
+                gettype($bands) . ' passed.)', DEBUG_DEVELOPER);
+        $bands = (int) $bands;
+    }
 
     if ($userids) {
         list($usql, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'u');
@@ -220,7 +225,7 @@ ORDER BY
     $data = $DB->get_records_sql_menu($sql, $params);
 
     // We need to create array elements with values 0 at indexes where there is no element.
-    $data =  $data + array_fill(0, $bands+1, 0);
+    $data =  $data + array_fill(0, $bands + 1, 0);
     ksort($data);
 
     // Place the maximum (prefect grade) into the last band i.e. make last
-- 
1.7.9.5


From 2011579b26674c15b67c9203a107088ae1fe048e Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Fri, 20 Jul 2012 11:55:45 +0800
Subject: [PATCH 264/903] MDL-32499 gradingform_rubric Avoid backup/restore of
 rubric fillings without an existing criteria

---
 .../backup_gradingform_rubric_plugin.class.php     |    9 +++++++--
 .../restore_gradingform_rubric_plugin.class.php    |    6 +++++-
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/grade/grading/form/rubric/backup/moodle2/backup_gradingform_rubric_plugin.class.php b/grade/grading/form/rubric/backup/moodle2/backup_gradingform_rubric_plugin.class.php
index 78741ec..0c85ca2 100644
--- a/grade/grading/form/rubric/backup/moodle2/backup_gradingform_rubric_plugin.class.php
+++ b/grade/grading/form/rubric/backup/moodle2/backup_gradingform_rubric_plugin.class.php
@@ -106,8 +106,13 @@ class backup_gradingform_rubric_plugin extends backup_gradingform_plugin {
 
         // Set sources to populate the data
 
-        $filling->set_source_table('gradingform_rubric_fillings',
-            array('instanceid' => backup::VAR_PARENTID));
+        // MDL-32499 Binding criterionid to ensure it's existence
+        $filling->set_source_sql('SELECT rf.*
+                FROM {gradingform_rubric_fillings} rf
+                JOIN {grading_instances} gi ON gi.id = rf.instanceid
+                JOIN {gradingform_rubric_criteria} rc ON rc.id = rf.criterionid AND gi.definitionid = rc.definitionid
+                WHERE rf.instanceid = :instanceid',
+                array('instanceid' => backup::VAR_PARENTID));
 
         // no need to annotate ids or files yet (one day when remark field supports
         // embedded fileds, they must be annotated here)
diff --git a/grade/grading/form/rubric/backup/moodle2/restore_gradingform_rubric_plugin.class.php b/grade/grading/form/rubric/backup/moodle2/restore_gradingform_rubric_plugin.class.php
index 62b5c96..625b29a 100644
--- a/grade/grading/form/rubric/backup/moodle2/restore_gradingform_rubric_plugin.class.php
+++ b/grade/grading/form/rubric/backup/moodle2/restore_gradingform_rubric_plugin.class.php
@@ -109,6 +109,10 @@ class restore_gradingform_rubric_plugin extends restore_gradingform_plugin {
         $data->criterionid = $this->get_mappingid('gradingform_rubric_criterion', $data->criterionid);
         $data->levelid = $this->get_mappingid('gradingform_rubric_level', $data->levelid);
 
-        $DB->insert_record('gradingform_rubric_fillings', $data);
+        // MDL-32499 Avoid fatal errors when restoring backups created after patching MDL-32499
+        if (!empty($data->criterionid)) {
+            $DB->insert_record('gradingform_rubric_fillings', $data);
+        }
+
     }
 }
-- 
1.7.9.5


From 3b6573536c38c6176329c118069b1a5d1760f80e Mon Sep 17 00:00:00 2001
From: Tom Lanyon <tom@netspot.com.au>
Date: Wed, 9 May 2012 16:56:53 +0930
Subject: [PATCH 265/903] MDL-32931 mod_forum Change forum overview to avoid
 use of (potentially large and slow ) log table.

---
 mod/forum/lib.php |   23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 4b7a8cc..e2f59e1 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -1311,21 +1311,24 @@ function forum_print_overview($courses,&$htmlarray) {
     }
 
 
-    // get all forum logs in ONE query (much better!)
+    // look for new posts since lastaccess
+    $course_tuples = join(
+        ' OR ',
+        array_fill(0, count($visited_courses), '(f.course = ? AND p.created > ?)')
+    );
+
+    $sql = "SELECT f.id, COUNT(*) "
+                .'FROM {forum_posts} p, {forum_discussions} d, {forum} f '
+                .'WHERE p.discussion = d.id AND d.forum = f.id '
+                ."AND ($course_tuples) "
+                ."AND p.userid != ? "
+                ."GROUP BY f.id";
+
     $params = array();
-    $sql = "SELECT instance,cmid,l.course,COUNT(l.id) as count FROM {log} l "
-        ." JOIN {course_modules} cm ON cm.id = cmid "
-        ." WHERE (";
     foreach ($courses as $course) {
-        $sql .= '(l.course = ? AND l.time > ?) OR ';
         $params[] = $course->id;
         $params[] = $course->lastaccess;
     }
-    $sql = substr($sql,0,-3); // take off the last OR
-
-    $sql .= ") AND l.module = 'forum' AND action = 'add post' "
-        ." AND userid != ? GROUP BY cmid,l.course,instance";
-
     $params[] = $USER->id;
 
     if (!$new = $DB->get_records_sql($sql, $params)) {
-- 
1.7.9.5


From e8790310bb295d1439706e4a2519d312738cd14b Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 9 Jul 2012 15:29:42 +0800
Subject: [PATCH 266/903] MDL-32931 mod_forum Polishing patch and taking into
 account courses without previous accesses

---
 mod/forum/lib.php |   39 +++++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index e2f59e1..ab9a580 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -1310,26 +1310,33 @@ function forum_print_overview($courses,&$htmlarray) {
         return;
     }
 
-
-    // look for new posts since lastaccess
-    $course_tuples = join(
-        ' OR ',
-        array_fill(0, count($visited_courses), '(f.course = ? AND p.created > ?)')
-    );
-
-    $sql = "SELECT f.id, COUNT(*) "
-                .'FROM {forum_posts} p, {forum_discussions} d, {forum} f '
-                .'WHERE p.discussion = d.id AND d.forum = f.id '
-                ."AND ($course_tuples) "
-                ."AND p.userid != ? "
-                ."GROUP BY f.id";
-
+    // Courses to search for new posts
+    $coursessqls = array();
     $params = array();
     foreach ($courses as $course) {
-        $params[] = $course->id;
-        $params[] = $course->lastaccess;
+
+        // If the user has never entered into the course all posts are pending
+        if ($course->lastaccess == 0) {
+            $coursessqls[] = '(f.course = ?)';
+            $params[] = $course->id;
+
+        // Only posts created after the course last access
+        } else {
+            $coursessqls[] = '(f.course = ? AND p.created > ?)';
+            $params[] = $course->id;
+            $params[] = $course->lastaccess;
+        }
     }
     $params[] = $USER->id;
+    $coursessql = implode(' OR ', $coursessqls);
+
+    $sql = "SELECT f.id, COUNT(*) as count "
+                .'FROM {forum} f '
+                .'JOIN {forum_discussions} d ON d.forum  = f.id '
+                .'JOIN {forum_posts} p ON p.discussion = d.id '
+                ."WHERE ($coursessql) "
+                .'AND p.userid != ? '
+                .'GROUP BY f.id';
 
     if (!$new = $DB->get_records_sql($sql, $params)) {
         $new = array(); // avoid warnings
-- 
1.7.9.5


From 94800237334c77c6322387c9588220769c0e2c53 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 25 Jul 2012 15:29:47 +0800
Subject: [PATCH 267/903] MDL-34507 Repository: Better support for 'any'
 accepted filetypes

---
 repository/lib.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/repository/lib.php b/repository/lib.php
index c34dec7..44e4fe4 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -899,6 +899,9 @@ abstract class repository {
         $repositories = array();
         if (isset($args['accepted_types'])) {
             $accepted_types = $args['accepted_types'];
+            if (is_array($accepted_types) && in_array('*', $accepted_types)) {
+                $accepted_types = '*';
+            }
         } else {
             $accepted_types = '*';
         }
-- 
1.7.9.5


From b3b35530f966403962bbf5dbdd3bdc5dd3a2b058 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 23 Jul 2012 10:10:11 +0800
Subject: [PATCH 268/903] MDL-25953 Repository: Updated Amazon S3 library

---
 repository/s3/README_MOODLE.txt |   10 +
 repository/s3/S3.php            | 1233 +++++++++++++++++++++++++++++++--------
 repository/s3/lib.php           |    2 +-
 3 files changed, 1001 insertions(+), 244 deletions(-)
 create mode 100644 repository/s3/README_MOODLE.txt

diff --git a/repository/s3/README_MOODLE.txt b/repository/s3/README_MOODLE.txt
new file mode 100644
index 0000000..a6c5f92
--- /dev/null
+++ b/repository/s3/README_MOODLE.txt
@@ -0,0 +1,10 @@
+- S3.php -
+
+Amazon S3 PHP Class
+
+Cloned from git://github.com/tpyo/amazon-s3-php-class.git
+Branch master
+On July 23rd 2012
+
+https://github.com/tpyo/amazon-s3-php-class
+http://undesigned.org.za/2007/10/22/amazon-s3-php-class
diff --git a/repository/s3/S3.php b/repository/s3/S3.php
index dadfb5a..247d6c3 100644
--- a/repository/s3/S3.php
+++ b/repository/s3/S3.php
@@ -1,7 +1,8 @@
 <?php
-
 /**
-* Copyright (c) 2008, Donovan Schönknecht.  All rights reserved.
+* $Id$
+*
+* Copyright (c) 2011, Donovan Schönknecht.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
@@ -31,18 +32,37 @@
 * Amazon S3 PHP class
 *
 * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
-* @version 0.3.8
+* @version 0.5.0-dev
 */
-class S3 {
+class S3
+{
 	// ACL flags
 	const ACL_PRIVATE = 'private';
 	const ACL_PUBLIC_READ = 'public-read';
 	const ACL_PUBLIC_READ_WRITE = 'public-read-write';
+	const ACL_AUTHENTICATED_READ = 'authenticated-read';
+
+	const STORAGE_CLASS_STANDARD = 'STANDARD';
+	const STORAGE_CLASS_RRS = 'REDUCED_REDUNDANCY';
+
+	private static $__accessKey = null; // AWS Access key
+	private static $__secretKey = null; // AWS Secret key
+	private static $__sslKey = null;
+
+	public static $endpoint = 's3.amazonaws.com';
+	public static $proxy = null;
 
-	public static $useSSL = true;
+	public static $useSSL = false;
+	public static $useSSLValidation = true;
+	public static $useExceptions = false;
 
-	private static $__accessKey; // AWS Access key
-	private static $__secretKey; // AWS Secret key
+	// SSL CURL SSL options - only needed if you are experiencing problems with your OpenSSL configuration
+	public static $sslKey = null;
+	public static $sslCert = null;
+	public static $sslCACert = null;
+
+	private static $__signingKeyPairId = null; // AWS Key Pair ID
+	private static $__signingKeyResource = false; // Key resource, freeSigningKey() must be called to clear it from memory
 
 
 	/**
@@ -53,45 +73,179 @@ class S3 {
 	* @param boolean $useSSL Enable SSL
 	* @return void
 	*/
-	public function __construct($accessKey = null, $secretKey = null, $useSSL = true) {
+	public function __construct($accessKey = null, $secretKey = null, $useSSL = false, $endpoint = 's3.amazonaws.com')
+	{
 		if ($accessKey !== null && $secretKey !== null)
 			self::setAuth($accessKey, $secretKey);
 		self::$useSSL = $useSSL;
+		self::$endpoint = $endpoint;
 	}
 
 
 	/**
+	* Set the sertvice endpoint
+	*
+	* @param string $host Hostname
+	* @return void
+	*/
+	public function setEndpoint($host)
+	{
+		self::$endpoint = $host;
+	}
+
+	/**
 	* Set AWS access key and secret key
 	*
 	* @param string $accessKey Access key
 	* @param string $secretKey Secret key
 	* @return void
 	*/
-	public static function setAuth($accessKey, $secretKey) {
+	public static function setAuth($accessKey, $secretKey)
+	{
 		self::$__accessKey = $accessKey;
 		self::$__secretKey = $secretKey;
 	}
 
 
 	/**
+	* Check if AWS keys have been set
+	*
+	* @return boolean
+	*/
+	public static function hasAuth() {
+		return (self::$__accessKey !== null && self::$__secretKey !== null);
+	}
+
+
+	/**
+	* Set SSL on or off
+	*
+	* @param boolean $enabled SSL enabled
+	* @param boolean $validate SSL certificate validation
+	* @return void
+	*/
+	public static function setSSL($enabled, $validate = true)
+	{
+		self::$useSSL = $enabled;
+		self::$useSSLValidation = $validate;
+	}
+
+
+	/**
+	* Set SSL client certificates (experimental)
+	*
+	* @param string $sslCert SSL client certificate
+	* @param string $sslKey SSL client key
+	* @param string $sslCACert SSL CA cert (only required if you are having problems with your system CA cert)
+	* @return void
+	*/
+	public static function setSSLAuth($sslCert = null, $sslKey = null, $sslCACert = null)
+	{
+		self::$sslCert = $sslCert;
+		self::$sslKey = $sslKey;
+		self::$sslCACert = $sslCACert;
+	}
+
+
+	/**
+	* Set proxy information
+	*
+	* @param string $host Proxy hostname and port (localhost:1234)
+	* @param string $user Proxy username
+	* @param string $pass Proxy password
+	* @param constant $type CURL proxy type
+	* @return void
+	*/
+	public static function setProxy($host, $user = null, $pass = null, $type = CURLPROXY_SOCKS5)
+	{
+		self::$proxy = array('host' => $host, 'type' => $type, 'user' => null, 'pass' => 'null');
+	}
+
+
+	/**
+	* Set the error mode to exceptions
+	*
+	* @param boolean $enabled Enable exceptions
+	* @return void
+	*/
+	public static function setExceptions($enabled = true)
+	{
+		self::$useExceptions = $enabled;
+	}
+
+
+	/**
+	* Set signing key
+	*
+	* @param string $keyPairId AWS Key Pair ID
+	* @param string $signingKey Private Key
+	* @param boolean $isFile Load private key from file, set to false to load string
+	* @return boolean
+	*/
+	public static function setSigningKey($keyPairId, $signingKey, $isFile = true)
+	{
+		self::$__signingKeyPairId = $keyPairId;
+		if ((self::$__signingKeyResource = openssl_pkey_get_private($isFile ?
+		file_get_contents($signingKey) : $signingKey)) !== false) return true;
+		self::__triggerError('S3::setSigningKey(): Unable to open load private key: '.$signingKey, __FILE__, __LINE__);
+		return false;
+	}
+
+
+	/**
+	* Free signing key from memory, MUST be called if you are using setSigningKey()
+	*
+	* @return void
+	*/
+	public static function freeSigningKey()
+	{
+		if (self::$__signingKeyResource !== false)
+			openssl_free_key(self::$__signingKeyResource);
+	}
+
+
+	/**
+	* Internal error handler
+	*
+	* @internal Internal error handler
+	* @param string $message Error message
+	* @param string $file Filename
+	* @param integer $line Line number
+	* @param integer $code Error code
+	* @return void
+	*/
+	private static function __triggerError($message, $file, $line, $code = 0)
+	{
+		if (self::$useExceptions)
+			throw new S3Exception($message, $file, $line, $code);
+		else
+			trigger_error($message, E_USER_WARNING);
+	}
+
+
+	/**
 	* Get a list of buckets
 	*
 	* @param boolean $detailed Returns detailed bucket list when true
 	* @return array | false
 	*/
-	public static function listBuckets($detailed = false) {
-		$rest = new S3Request('GET', '', '');
+	public static function listBuckets($detailed = false)
+	{
+		$rest = new S3Request('GET', '', '', self::$endpoint);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'],
+			$rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
-		$results = array(); //var_dump($rest->body);
+		$results = array();
 		if (!isset($rest->body->Buckets)) return $results;
 
-		if ($detailed) {
+		if ($detailed)
+		{
 			if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
 			$results['owner'] = array(
 				'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
@@ -118,10 +272,13 @@ class S3 {
 	* @param string $marker Marker (last file listed)
 	* @param string $maxKeys Max keys (maximum number of keys to return)
 	* @param string $delimiter Delimiter
+	* @param boolean $returnCommonPrefixes Set to true to return CommonPrefixes
 	* @return array | false
 	*/
-	public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null) {
-		$rest = new S3Request('GET', $bucket, '');
+	public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null, $delimiter = null, $returnCommonPrefixes = false)
+	{
+		$rest = new S3Request('GET', $bucket, '', self::$endpoint);
+		if ($maxKeys == 0) $maxKeys = null;
 		if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
 		if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker);
 		if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys);
@@ -129,49 +286,68 @@ class S3 {
 		$response = $rest->getResponse();
 		if ($response->error === false && $response->code !== 200)
 			$response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
-		if ($response->error !== false) {
-			trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING);
+		if ($response->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getBucket(): [%s] %s",
+			$response->error['code'], $response->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 
 		$results = array();
 
-		$lastMarker = null;
+		$nextMarker = null;
 		if (isset($response->body, $response->body->Contents))
-			foreach ($response->body->Contents as $c) {
+		foreach ($response->body->Contents as $c)
+		{
+			$results[(string)$c->Key] = array(
+				'name' => (string)$c->Key,
+				'time' => strtotime((string)$c->LastModified),
+				'size' => (int)$c->Size,
+				'hash' => substr((string)$c->ETag, 1, -1)
+			);
+			$nextMarker = (string)$c->Key;
+		}
+
+		if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
+			foreach ($response->body->CommonPrefixes as $c)
+				$results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
+
+		if (isset($response->body, $response->body->IsTruncated) &&
+		(string)$response->body->IsTruncated == 'false') return $results;
+
+		if (isset($response->body, $response->body->NextMarker))
+			$nextMarker = (string)$response->body->NextMarker;
+
+		// Loop through truncated results if maxKeys isn't specified
+		if ($maxKeys == null && $nextMarker !== null && (string)$response->body->IsTruncated == 'true')
+		do
+		{
+			$rest = new S3Request('GET', $bucket, '', self::$endpoint);
+			if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
+			$rest->setParameter('marker', $nextMarker);
+			if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
+
+			if (($response = $rest->getResponse()) == false || $response->code !== 200) break;
+
+			if (isset($response->body, $response->body->Contents))
+			foreach ($response->body->Contents as $c)
+			{
 				$results[(string)$c->Key] = array(
 					'name' => (string)$c->Key,
 					'time' => strtotime((string)$c->LastModified),
 					'size' => (int)$c->Size,
 					'hash' => substr((string)$c->ETag, 1, -1)
 				);
-				$lastMarker = (string)$c->Key;
-				//$response->body->IsTruncated = 'true'; break;
+				$nextMarker = (string)$c->Key;
 			}
 
+			if ($returnCommonPrefixes && isset($response->body, $response->body->CommonPrefixes))
+				foreach ($response->body->CommonPrefixes as $c)
+					$results[(string)$c->Prefix] = array('prefix' => (string)$c->Prefix);
 
-		if (isset($response->body->IsTruncated) &&
-		(string)$response->body->IsTruncated == 'false') return $results;
+			if (isset($response->body, $response->body->NextMarker))
+				$nextMarker = (string)$response->body->NextMarker;
 
-		// Loop through truncated results if maxKeys isn't specified
-		if ($maxKeys == null && $lastMarker !== null && (string)$response->body->IsTruncated == 'true')
-		do {
-			$rest = new S3Request('GET', $bucket, '');
-			if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
-			$rest->setParameter('marker', $lastMarker);
-			if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
-
-			if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
-			if (isset($response->body, $response->body->Contents))
-				foreach ($response->body->Contents as $c) {
-					$results[(string)$c->Key] = array(
-						'name' => (string)$c->Key,
-						'time' => strtotime((string)$c->LastModified),
-						'size' => (int)$c->Size,
-						'hash' => substr((string)$c->ETag, 1, -1)
-					);
-					$lastMarker = (string)$c->Key;
-				}
 		} while ($response !== false && (string)$response->body->IsTruncated == 'true');
 
 		return $results;
@@ -186,14 +362,16 @@ class S3 {
 	* @param string $location Set as "EU" to create buckets hosted in Europe
 	* @return boolean
 	*/
-	public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false) {
-		$rest = new S3Request('PUT', $bucket, '');
+	public static function putBucket($bucket, $acl = self::ACL_PRIVATE, $location = false)
+	{
+		$rest = new S3Request('PUT', $bucket, '', self::$endpoint);
 		$rest->setAmzHeader('x-amz-acl', $acl);
 
-		if ($location !== false) {
+		if ($location !== false)
+		{
 			$dom = new DOMDocument;
 			$createBucketConfiguration = $dom->createElement('CreateBucketConfiguration');
-			$locationConstraint = $dom->createElement('LocationConstraint', strtoupper($location));
+			$locationConstraint = $dom->createElement('LocationConstraint', $location);
 			$createBucketConfiguration->appendChild($locationConstraint);
 			$dom->appendChild($createBucketConfiguration);
 			$rest->data = $dom->saveXML();
@@ -204,9 +382,10 @@ class S3 {
 
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::putBucket({$bucket}, {$acl}, {$location}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -219,14 +398,16 @@ class S3 {
 	* @param string $bucket Bucket name
 	* @return boolean
 	*/
-	public static function deleteBucket($bucket) {
-		$rest = new S3Request('DELETE', $bucket);
+	public static function deleteBucket($bucket)
+	{
+		$rest = new S3Request('DELETE', $bucket, '', self::$endpoint);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 204)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -240,14 +421,15 @@ class S3 {
 	* @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
 	* @return array | false
 	*/
-	public static function inputFile($file, $md5sum = true) {
-		if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
-			trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING);
+	public static function inputFile($file, $md5sum = true)
+	{
+		if (!file_exists($file) || !is_file($file) || !is_readable($file))
+		{
+			self::__triggerError('S3::inputFile(): Unable to open input file: '.$file, __FILE__, __LINE__);
 			return false;
 		}
-		return array('file' => $file, 'size' => filesize($file),
-		'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum :
-		base64_encode(md5_file($file, true))) : '');
+		return array('file' => $file, 'size' => filesize($file), 'md5sum' => $md5sum !== false ?
+		(is_string($md5sum) ? $md5sum : base64_encode(md5_file($file, true))) : '');
 	}
 
 
@@ -259,9 +441,11 @@ class S3 {
 	* @param string $md5sum MD5 hash to send (optional)
 	* @return array | false
 	*/
-	public static function inputResource(&$resource, $bufferSize, $md5sum = '') {
-		if (!is_resource($resource) || $bufferSize <= 0) {
-			trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING);
+	public static function inputResource(&$resource, $bufferSize, $md5sum = '')
+	{
+		if (!is_resource($resource) || $bufferSize < 0)
+		{
+			self::__triggerError('S3::inputResource(): Invalid resource or buffer size', __FILE__, __LINE__);
 			return false;
 		}
 		$input = array('size' => $bufferSize, 'md5sum' => $md5sum);
@@ -279,13 +463,15 @@ class S3 {
 	* @param constant $acl ACL constant
 	* @param array $metaHeaders Array of x-amz-meta-* headers
 	* @param array $requestHeaders Array of request headers or content type as a string
+	* @param constant $storageClass Storage class constant
 	* @return boolean
 	*/
-	public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array()) {
-		if ($input == false) return false;
-		$rest = new S3Request('PUT', $bucket, $uri);
+	public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array(), $storageClass = self::STORAGE_CLASS_STANDARD)
+	{
+		if ($input === false) return false;
+		$rest = new S3Request('PUT', $bucket, $uri, self::$endpoint);
 
-		if (is_string($input)) $input = array(
+		if (!is_array($input)) $input = array(
 			'data' => $input, 'size' => strlen($input),
 			'md5sum' => base64_encode(md5($input, true))
 		);
@@ -299,7 +485,7 @@ class S3 {
 			$rest->data = $input['data'];
 
 		// Content-Length (required)
-		if (isset($input['size']) && $input['size'] > -1)
+		if (isset($input['size']) && $input['size'] >= 0)
 			$rest->size = $input['size'];
 		else {
 			if (isset($input['file']))
@@ -315,7 +501,8 @@ class S3 {
 			$input['type'] = $requestHeaders;
 
 		// Content-Type
-		if (!isset($input['type'])) {
+		if (!isset($input['type']))
+		{
 			if (isset($requestHeaders['Content-Type']))
 				$input['type'] =& $requestHeaders['Content-Type'];
 			elseif (isset($input['file']))
@@ -324,8 +511,12 @@ class S3 {
 				$input['type'] = 'application/octet-stream';
 		}
 
+		if ($storageClass !== self::STORAGE_CLASS_STANDARD) // Storage class
+			$rest->setAmzHeader('x-amz-storage-class', $storageClass);
+
 		// We need to post with Content-Length and Content-Type, MD5 is optional
-		if ($rest->size > 0 && ($rest->fp !== false || $rest->data !== false)) {
+		if ($rest->size >= 0 && ($rest->fp !== false || $rest->data !== false))
+		{
 			$rest->setHeader('Content-Type', $input['type']);
 			if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
 
@@ -337,8 +528,10 @@ class S3 {
 
 		if ($rest->response->error === false && $rest->response->code !== 200)
 			$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->response->error !== false) {
-			trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
+		if ($rest->response->error !== false)
+		{
+			self::__triggerError(sprintf("S3::putObject(): [%s] %s",
+			$rest->response->error['code'], $rest->response->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -356,7 +549,8 @@ class S3 {
 	* @param string $contentType Content type
 	* @return boolean
 	*/
-	public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
+	public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null)
+	{
 		return self::putObject(self::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
 	}
 
@@ -372,7 +566,8 @@ class S3 {
 	* @param string $contentType Content type
 	* @return boolean
 	*/
-	public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') {
+	public static function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain')
+	{
 		return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
 	}
 
@@ -385,9 +580,11 @@ class S3 {
 	* @param mixed $saveTo Filename or resource to write to
 	* @return mixed
 	*/
-	public static function getObject($bucket, $uri, $saveTo = false) {
-		$rest = new S3Request('GET', $bucket, $uri);
-		if ($saveTo !== false) {
+	public static function getObject($bucket, $uri, $saveTo = false)
+	{
+		$rest = new S3Request('GET', $bucket, $uri, self::$endpoint);
+		if ($saveTo !== false)
+		{
 			if (is_resource($saveTo))
 				$rest->fp =& $saveTo;
 			else
@@ -400,9 +597,10 @@ class S3 {
 
 		if ($rest->response->error === false && $rest->response->code !== 200)
 			$rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->response->error !== false) {
-			trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
-			$rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
+		if ($rest->response->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
+			$rest->response->error['code'], $rest->response->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return $rest->response;
@@ -417,14 +615,16 @@ class S3 {
 	* @param boolean $returnInfo Return response information
 	* @return mixed | false
 	*/
-	public static function getObjectInfo($bucket, $uri, $returnInfo = true) {
-		$rest = new S3Request('HEAD', $bucket, $uri);
+	public static function getObjectInfo($bucket, $uri, $returnInfo = true)
+	{
+		$rest = new S3Request('HEAD', $bucket, $uri, self::$endpoint);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
@@ -439,18 +639,31 @@ class S3 {
 	* @param string $bucket Destination bucket name
 	* @param string $uri Destination object URI
 	* @param constant $acl ACL constant
+	* @param array $metaHeaders Optional array of x-amz-meta-* headers
+	* @param array $requestHeaders Optional array of request headers (content type, disposition, etc.)
+	* @param constant $storageClass Storage class constant
 	* @return mixed | false
 	*/
-	public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE) {
-		$rest = new S3Request('PUT', $bucket, $uri);
+	public static function copyObject($srcBucket, $srcUri, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $requestHeaders = array(), $storageClass = self::STORAGE_CLASS_STANDARD)
+	{
+		$rest = new S3Request('PUT', $bucket, $uri, self::$endpoint);
+		$rest->setHeader('Content-Length', 0);
+		foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
+		foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
+		if ($storageClass !== self::STORAGE_CLASS_STANDARD) // Storage class
+			$rest->setAmzHeader('x-amz-storage-class', $storageClass);
 		$rest->setAmzHeader('x-amz-acl', $acl);
-		$rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, $srcUri));
+		$rest->setAmzHeader('x-amz-copy-source', sprintf('/%s/%s', $srcBucket, rawurlencode($srcUri)));
+		if (sizeof($requestHeaders) > 0 || sizeof($metaHeaders) > 0)
+			$rest->setAmzHeader('x-amz-metadata-directive', 'REPLACE');
+
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::copyObject({$srcBucket}, {$srcUri}, {$bucket}, {$uri}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return isset($rest->body->LastModified, $rest->body->ETag) ? array(
@@ -468,14 +681,17 @@ class S3 {
 	* @param string $targetPrefix Log prefix (e,g; domain.com-)
 	* @return boolean
 	*/
-	public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null) {
+	public static function setBucketLogging($bucket, $targetBucket, $targetPrefix = null)
+	{
 		// The S3 log delivery group has to be added to the target bucket's ACP
-		if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false) {
+		if ($targetBucket !== null && ($acp = self::getAccessControlPolicy($targetBucket, '')) !== false)
+		{
 			// Only add permissions to the target bucket when they do not exist
 			$aclWriteSet = false;
 			$aclReadSet = false;
 			foreach ($acp['acl'] as $acl)
-			if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery') {
+			if ($acl['type'] == 'Group' && $acl['uri'] == 'http://acs.amazonaws.com/groups/s3/LogDelivery')
+			{
 				if ($acl['permission'] == 'WRITE') $aclWriteSet = true;
 				elseif ($acl['permission'] == 'READ_ACP') $aclReadSet = true;
 			}
@@ -491,7 +707,8 @@ class S3 {
 		$dom = new DOMDocument;
 		$bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
 		$bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
-		if ($targetBucket !== null) {
+		if ($targetBucket !== null)
+		{
 			if ($targetPrefix == null) $targetPrefix = $bucket . '-';
 			$loggingEnabled = $dom->createElement('LoggingEnabled');
 			$loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
@@ -501,7 +718,7 @@ class S3 {
 		}
 		$dom->appendChild($bucketLoggingStatus);
 
-		$rest = new S3Request('PUT', $bucket, '');
+		$rest = new S3Request('PUT', $bucket, '', self::$endpoint);
 		$rest->setParameter('logging', null);
 		$rest->data = $dom->saveXML();
 		$rest->size = strlen($rest->data);
@@ -509,9 +726,10 @@ class S3 {
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::setBucketLogging({$bucket}, {$targetBucket}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -527,15 +745,17 @@ class S3 {
 	* @param string $bucket Bucket name
 	* @return array | false
 	*/
-	public static function getBucketLogging($bucket) {
-		$rest = new S3Request('GET', $bucket, '');
+	public static function getBucketLogging($bucket)
+	{
+		$rest = new S3Request('GET', $bucket, '', self::$endpoint);
 		$rest->setParameter('logging', null);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		if (!isset($rest->body->LoggingEnabled)) return false; // No logging
@@ -552,7 +772,8 @@ class S3 {
 	* @param string $bucket Bucket name
 	* @return boolean
 	*/
-	public static function disableBucketLogging($bucket) {
+	public static function disableBucketLogging($bucket)
+	{
 		return self::setBucketLogging($bucket, null);
 	}
 
@@ -563,15 +784,17 @@ class S3 {
 	* @param string $bucket Bucket name
 	* @return string | false
 	*/
-	public static function getBucketLocation($bucket) {
-		$rest = new S3Request('GET', $bucket, '');
+	public static function getBucketLocation($bucket)
+	{
+		$rest = new S3Request('GET', $bucket, '', self::$endpoint);
 		$rest->setParameter('location', null);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::getBucketLocation({$bucket}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getBucketLocation({$bucket}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return (isset($rest->body[0]) && (string)$rest->body[0] !== '') ? (string)$rest->body[0] : 'US';
@@ -586,7 +809,8 @@ class S3 {
 	* @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
 	* @return boolean
 	*/
-	public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) {
+	public static function setAccessControlPolicy($bucket, $uri = '', $acp = array())
+	{
 		$dom = new DOMDocument;
 		$dom->formatOutput = true;
 		$accessControlPolicy = $dom->createElement('AccessControlPolicy');
@@ -598,17 +822,23 @@ class S3 {
 		$owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
 		$accessControlPolicy->appendChild($owner);
 
-		foreach ($acp['acl'] as $g) {
+		foreach ($acp['acl'] as $g)
+		{
 			$grant = $dom->createElement('Grant');
 			$grantee = $dom->createElement('Grantee');
 			$grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
-			if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted)
+			if (isset($g['id']))
+			{ // CanonicalUser (DisplayName is omitted)
 				$grantee->setAttribute('xsi:type', 'CanonicalUser');
 				$grantee->appendChild($dom->createElement('ID', $g['id']));
-			} elseif (isset($g['email'])) { // AmazonCustomerByEmail
+			}
+			elseif (isset($g['email']))
+			{ // AmazonCustomerByEmail
 				$grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
 				$grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
-			} elseif ($g['type'] == 'Group') { // Group
+			}
+			elseif ($g['type'] == 'Group')
+			{ // Group
 				$grantee->setAttribute('xsi:type', 'Group');
 				$grantee->appendChild($dom->createElement('URI', $g['uri']));
 			}
@@ -620,7 +850,7 @@ class S3 {
 		$accessControlPolicy->appendChild($accessControlList);
 		$dom->appendChild($accessControlPolicy);
 
-		$rest = new S3Request('PUT', $bucket, $uri);
+		$rest = new S3Request('PUT', $bucket, $uri, self::$endpoint);
 		$rest->setParameter('acl', null);
 		$rest->data = $dom->saveXML();
 		$rest->size = strlen($rest->data);
@@ -628,9 +858,10 @@ class S3 {
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -644,28 +875,33 @@ class S3 {
 	* @param string $uri Object URI
 	* @return mixed | false
 	*/
-	public static function getAccessControlPolicy($bucket, $uri = '') {
-		$rest = new S3Request('GET', $bucket, $uri);
+	public static function getAccessControlPolicy($bucket, $uri = '')
+	{
+		$rest = new S3Request('GET', $bucket, $uri, self::$endpoint);
 		$rest->setParameter('acl', null);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 
 		$acp = array();
-		if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) {
+		if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
 			$acp['owner'] = array(
 				'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
 			);
-		}
-		if (isset($rest->body->AccessControlList)) {
+
+		if (isset($rest->body->AccessControlList))
+		{
 			$acp['acl'] = array();
-			foreach ($rest->body->AccessControlList->Grant as $grant) {
-				foreach ($grant->Grantee as $grantee) {
+			foreach ($rest->body->AccessControlList->Grant as $grant)
+			{
+				foreach ($grant->Grantee as $grantee)
+				{
 					if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
 						$acp['acl'][] = array(
 							'type' => 'CanonicalUser',
@@ -700,14 +936,16 @@ class S3 {
 	* @param string $uri Object URI
 	* @return boolean
 	*/
-	public static function deleteObject($bucket, $uri) {
-		$rest = new S3Request('DELETE', $bucket, $uri);
+	public static function deleteObject($bucket, $uri)
+	{
+		$rest = new S3Request('DELETE', $bucket, $uri, self::$endpoint);
 		$rest = $rest->getResponse();
 		if ($rest->error === false && $rest->code !== 204)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::deleteObject(): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::deleteObject(): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -724,37 +962,169 @@ class S3 {
 	* @param boolean $https Use HTTPS ($hostBucket should be false for SSL verification)
 	* @return string
 	*/
-	public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false) {
+	public static function getAuthenticatedURL($bucket, $uri, $lifetime, $hostBucket = false, $https = false)
+	{
 		$expires = time() + $lifetime;
-		$uri = str_replace('%2F', '/', rawurlencode($uri)); // URI should be encoded (thanks Sean O'Dea)
+		$uri = str_replace(array('%2F', '%2B'), array('/', '+'), rawurlencode($uri));
 		return sprintf(($https ? 'https' : 'http').'://%s/%s?AWSAccessKeyId=%s&Expires=%u&Signature=%s',
-		$hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires,
+		// $hostBucket ? $bucket : $bucket.'.s3.amazonaws.com', $uri, self::$__accessKey, $expires,
+		$hostBucket ? $bucket : 's3.amazonaws.com/'.$bucket, $uri, self::$__accessKey, $expires,
 		urlencode(self::__getHash("GET\n\n\n{$expires}\n/{$bucket}/{$uri}")));
 	}
 
 
 	/**
+	* Get a CloudFront signed policy URL
+	*
+	* @param array $policy Policy
+	* @return string
+	*/
+	public static function getSignedPolicyURL($policy)
+	{
+		$data = json_encode($policy);
+		$signature = '';
+		if (!openssl_sign($data, $signature, self::$__signingKeyResource)) return false;
+
+		$encoded = str_replace(array('+', '='), array('-', '_', '~'), base64_encode($data));
+		$signature = str_replace(array('+', '='), array('-', '_', '~'), base64_encode($signature));
+
+		$url = $policy['Statement'][0]['Resource'] . '?';
+		foreach (array('Policy' => $encoded, 'Signature' => $signature, 'Key-Pair-Id' => self::$__signingKeyPairId) as $k => $v)
+			$url .= $k.'='.str_replace('%2F', '/', rawurlencode($v)).'&';
+		return substr($url, 0, -1);
+	}
+
+
+	/**
+	* Get a CloudFront canned policy URL
+	*
+	* @param string $string URL to sign
+	* @param integer $lifetime URL lifetime
+	* @return string
+	*/
+	public static function getSignedCannedURL($url, $lifetime)
+	{
+		return self::getSignedPolicyURL(array(
+			'Statement' => array(
+				array('Resource' => $url, 'Condition' => array(
+					'DateLessThan' => array('AWS:EpochTime' => time() + $lifetime)
+				))
+			)
+		));
+	}
+
+
+	/**
+	* Get upload POST parameters for form uploads
+	*
+	* @param string $bucket Bucket name
+	* @param string $uriPrefix Object URI prefix
+	* @param constant $acl ACL constant
+	* @param integer $lifetime Lifetime in seconds
+	* @param integer $maxFileSize Maximum filesize in bytes (default 5MB)
+	* @param string $successRedirect Redirect URL or 200 / 201 status code
+	* @param array $amzHeaders Array of x-amz-meta-* headers
+	* @param array $headers Array of request headers or content type as a string
+	* @param boolean $flashVars Includes additional "Filename" variable posted by Flash
+	* @return object
+	*/
+	public static function getHttpUploadPostParams($bucket, $uriPrefix = '', $acl = self::ACL_PRIVATE, $lifetime = 3600,
+	$maxFileSize = 5242880, $successRedirect = "201", $amzHeaders = array(), $headers = array(), $flashVars = false)
+	{
+		// Create policy object
+		$policy = new stdClass;
+		$policy->expiration = gmdate('Y-m-d\TH:i:s\Z', (time() + $lifetime));
+		$policy->conditions = array();
+		$obj = new stdClass; $obj->bucket = $bucket; array_push($policy->conditions, $obj);
+		$obj = new stdClass; $obj->acl = $acl; array_push($policy->conditions, $obj);
+
+		$obj = new stdClass; // 200 for non-redirect uploads
+		if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
+			$obj->success_action_status = (string)$successRedirect;
+		else // URL
+			$obj->success_action_redirect = $successRedirect;
+		array_push($policy->conditions, $obj);
+
+		if ($acl !== self::ACL_PUBLIC_READ)
+			array_push($policy->conditions, array('eq', '$acl', $acl));
+
+		array_push($policy->conditions, array('starts-with', '$key', $uriPrefix));
+		if ($flashVars) array_push($policy->conditions, array('starts-with', '$Filename', ''));
+		foreach (array_keys($headers) as $headerKey)
+			array_push($policy->conditions, array('starts-with', '$'.$headerKey, ''));
+		foreach ($amzHeaders as $headerKey => $headerVal)
+		{
+			$obj = new stdClass;
+			$obj->{$headerKey} = (string)$headerVal;
+			array_push($policy->conditions, $obj);
+		}
+		array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
+		$policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
+
+		// Create parameters
+		$params = new stdClass;
+		$params->AWSAccessKeyId = self::$__accessKey;
+		$params->key = $uriPrefix.'${filename}';
+		$params->acl = $acl;
+		$params->policy = $policy; unset($policy);
+		$params->signature = self::__getHash($params->policy);
+		if (is_numeric($successRedirect) && in_array((int)$successRedirect, array(200, 201)))
+			$params->success_action_status = (string)$successRedirect;
+		else
+			$params->success_action_redirect = $successRedirect;
+		foreach ($headers as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
+		foreach ($amzHeaders as $headerKey => $headerVal) $params->{$headerKey} = (string)$headerVal;
+		return $params;
+	}
+
+
+	/**
 	* Create a CloudFront distribution
 	*
 	* @param string $bucket Bucket name
 	* @param boolean $enabled Enabled (true/false)
 	* @param array $cnames Array containing CNAME aliases
 	* @param string $comment Use the bucket name as the hostname
+	* @param string $defaultRootObject Default root object
+	* @param string $originAccessIdentity Origin access identity
+	* @param array $trustedSigners Array of trusted signers
 	* @return array | false
 	*/
-	public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = '') {
+	public static function createDistribution($bucket, $enabled = true, $cnames = array(), $comment = null, $defaultRootObject = null, $originAccessIdentity = null, $trustedSigners = array())
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", [], '$comment'): %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+		$useSSL = self::$useSSL;
+
 		self::$useSSL = true; // CloudFront requires SSL
-		$rest = new S3Request('POST', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
-		$rest->data = self::__getCloudFrontDistributionConfigXML($bucket.'.s3.amazonaws.com', $enabled, $comment, (string)microtime(true), $cnames);
+		$rest = new S3Request('POST', '', '2010-11-01/distribution', 'cloudfront.amazonaws.com');
+		$rest->data = self::__getCloudFrontDistributionConfigXML(
+			$bucket.'.s3.amazonaws.com',
+			$enabled,
+			(string)$comment,
+			(string)microtime(true),
+			$cnames,
+			$defaultRootObject,
+			$originAccessIdentity,
+			$trustedSigners
+		);
+
 		$rest->size = strlen($rest->data);
 		$rest->setHeader('Content-Type', 'application/xml');
 		$rest = self::__getCloudFrontResponse($rest);
 
+		self::$useSSL = $useSSL;
+
 		if ($rest->error === false && $rest->code !== 201)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", '$comment'): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::createDistribution({$bucket}, ".(int)$enabled.", [], '$comment'): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		} elseif ($rest->body instanceof SimpleXMLElement)
 			return self::__parseCloudFrontDistributionConfig($rest->body);
@@ -768,20 +1138,35 @@ class S3 {
 	* @param string $distributionId Distribution ID from listDistributions()
 	* @return array | false
 	*/
-	public static function getDistribution($distributionId) {
+	public static function getDistribution($distributionId)
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::getDistribution($distributionId): %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+		$useSSL = self::$useSSL;
+
 		self::$useSSL = true; // CloudFront requires SSL
-		$rest = new S3Request('GET', '', '2008-06-30/distribution/'.$distributionId, 'cloudfront.amazonaws.com');
+		$rest = new S3Request('GET', '', '2010-11-01/distribution/'.$distributionId, 'cloudfront.amazonaws.com');
 		$rest = self::__getCloudFrontResponse($rest);
 
+		self::$useSSL = $useSSL;
+
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::getDistribution($distributionId): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::getDistribution($distributionId): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
-		} elseif ($rest->body instanceof SimpleXMLElement) {
+		}
+		elseif ($rest->body instanceof SimpleXMLElement)
+		{
 			$dist = self::__parseCloudFrontDistributionConfig($rest->body);
 			$dist['hash'] = $rest->headers['hash'];
+			$dist['id'] = $distributionId;
 			return $dist;
 		}
 		return false;
@@ -794,19 +1179,42 @@ class S3 {
 	* @param array $dist Distribution array info identical to output of getDistribution()
 	* @return array | false
 	*/
-	public static function updateDistribution($dist) {
+	public static function updateDistribution($dist)
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::updateDistribution({$dist['id']}): %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		$useSSL = self::$useSSL;
+
 		self::$useSSL = true; // CloudFront requires SSL
-		$rest = new S3Request('PUT', '', '2008-06-30/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com');
-		$rest->data = self::__getCloudFrontDistributionConfigXML($dist['origin'], $dist['enabled'], $dist['comment'], $dist['callerReference'], $dist['cnames']);
+		$rest = new S3Request('PUT', '', '2010-11-01/distribution/'.$dist['id'].'/config', 'cloudfront.amazonaws.com');
+		$rest->data = self::__getCloudFrontDistributionConfigXML(
+			$dist['origin'],
+			$dist['enabled'],
+			$dist['comment'],
+			$dist['callerReference'],
+			$dist['cnames'],
+			$dist['defaultRootObject'],
+			$dist['originAccessIdentity'],
+			$dist['trustedSigners']
+		);
+
 		$rest->size = strlen($rest->data);
 		$rest->setHeader('If-Match', $dist['hash']);
 		$rest = self::__getCloudFrontResponse($rest);
 
+		self::$useSSL = $useSSL;
+
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::updateDistribution({$dist['id']}, ".(int)$enabled.", '$comment'): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::updateDistribution({$dist['id']}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		} else {
 			$dist = self::__parseCloudFrontDistributionConfig($rest->body);
@@ -823,17 +1231,30 @@ class S3 {
 	* @param array $dist Distribution array info identical to output of getDistribution()
 	* @return boolean
 	*/
-	public static function deleteDistribution($dist) {
+	public static function deleteDistribution($dist)
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::deleteDistribution({$dist['id']}): %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		$useSSL = self::$useSSL;
+
 		self::$useSSL = true; // CloudFront requires SSL
 		$rest = new S3Request('DELETE', '', '2008-06-30/distribution/'.$dist['id'], 'cloudfront.amazonaws.com');
 		$rest->setHeader('If-Match', $dist['hash']);
 		$rest = self::__getCloudFrontResponse($rest);
 
+		self::$useSSL = $useSSL;
+
 		if ($rest->error === false && $rest->code !== 204)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::deleteDistribution({$dist['id']}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
 		}
 		return true;
@@ -845,27 +1266,189 @@ class S3 {
 	*
 	* @return array
 	*/
-	public static function listDistributions() {
+	public static function listDistributions()
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::listDistributions(): [%s] %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		$useSSL = self::$useSSL;
 		self::$useSSL = true; // CloudFront requires SSL
-		$rest = new S3Request('GET', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com');
+		$rest = new S3Request('GET', '', '2010-11-01/distribution', 'cloudfront.amazonaws.com');
 		$rest = self::__getCloudFrontResponse($rest);
+		self::$useSSL = $useSSL;
 
 		if ($rest->error === false && $rest->code !== 200)
 			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
-		if ($rest->error !== false) {
-			trigger_error(sprintf("S3::listDistributions(): [%s] %s",
-			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+		if ($rest->error !== false)
+		{
+			self::__triggerError(sprintf("S3::listDistributions(): [%s] %s",
+			$rest->error['code'], $rest->error['message']), __FILE__, __LINE__);
 			return false;
-		} elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary)) {
+		}
+		elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary))
+		{
 			$list = array();
-			if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated)) {
+			if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated))
+			{
 				//$info['marker'] = (string)$rest->body->Marker;
 				//$info['maxItems'] = (int)$rest->body->MaxItems;
 				//$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false;
 			}
-			foreach ($rest->body->DistributionSummary as $summary) {
+			foreach ($rest->body->DistributionSummary as $summary)
 				$list[(string)$summary->Id] = self::__parseCloudFrontDistributionConfig($summary);
-			}
+
+			return $list;
+		}
+		return array();
+	}
+
+	/**
+	* List CloudFront Origin Access Identities
+	*
+	* @return array
+	*/
+	public static function listOriginAccessIdentities()
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::listOriginAccessIdentities(): [%s] %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		self::$useSSL = true; // CloudFront requires SSL
+		$rest = new S3Request('GET', '', '2010-11-01/origin-access-identity/cloudfront', 'cloudfront.amazonaws.com');
+		$rest = self::__getCloudFrontResponse($rest);
+		$useSSL = self::$useSSL;
+
+		if ($rest->error === false && $rest->code !== 200)
+			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+		if ($rest->error !== false)
+		{
+			trigger_error(sprintf("S3::listOriginAccessIdentities(): [%s] %s",
+			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+			return false;
+		}
+
+		if (isset($rest->body->CloudFrontOriginAccessIdentitySummary))
+		{
+			$identities = array();
+			foreach ($rest->body->CloudFrontOriginAccessIdentitySummary as $identity)
+				if (isset($identity->S3CanonicalUserId))
+					$identities[(string)$identity->Id] = array('id' => (string)$identity->Id, 's3CanonicalUserId' => (string)$identity->S3CanonicalUserId);
+			return $identities;
+		}
+		return false;
+	}
+
+
+	/**
+	* Invalidate objects in a CloudFront distribution
+	*
+	* Thanks to Martin Lindkvist for S3::invalidateDistribution()
+	*
+	* @param string $distributionId Distribution ID from listDistributions()
+	* @param array $paths Array of object paths to invalidate
+	* @return boolean
+	*/
+	public static function invalidateDistribution($distributionId, $paths)
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::invalidateDistribution(): [%s] %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		$useSSL = self::$useSSL;
+		self::$useSSL = true; // CloudFront requires SSL
+		$rest = new S3Request('POST', '', '2010-08-01/distribution/'.$distributionId.'/invalidation', 'cloudfront.amazonaws.com');
+		$rest->data = self::__getCloudFrontInvalidationBatchXML($paths, (string)microtime(true));
+		$rest->size = strlen($rest->data);
+		$rest = self::__getCloudFrontResponse($rest);
+		self::$useSSL = $useSSL;
+
+		if ($rest->error === false && $rest->code !== 201)
+			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+		if ($rest->error !== false)
+		{
+			trigger_error(sprintf("S3::invalidate('{$distributionId}',{$paths}): [%s] %s",
+			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+			return false;
+		}
+		return true;
+	}
+
+
+	/**
+	* Get a InvalidationBatch DOMDocument
+	*
+	* @internal Used to create XML in invalidateDistribution()
+	* @param array $paths Paths to objects to invalidateDistribution
+	* @return string
+	*/
+	private static function __getCloudFrontInvalidationBatchXML($paths, $callerReference = '0') {
+		$dom = new DOMDocument('1.0', 'UTF-8');
+		$dom->formatOutput = true;
+		$invalidationBatch = $dom->createElement('InvalidationBatch');
+		foreach ($paths as $path)
+			$invalidationBatch->appendChild($dom->createElement('Path', $path));
+
+		$invalidationBatch->appendChild($dom->createElement('CallerReference', $callerReference));
+		$dom->appendChild($invalidationBatch);
+		return $dom->saveXML();
+	}
+
+
+	/**
+	* List your invalidation batches for invalidateDistribution() in a CloudFront distribution
+	*
+	* http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/ListInvalidation.html
+	* returned array looks like this:
+	*	Array
+	*	(
+	*		[I31TWB0CN9V6XD] => InProgress
+	*		[IT3TFE31M0IHZ] => Completed
+	*		[I12HK7MPO1UQDA] => Completed
+	*		[I1IA7R6JKTC3L2] => Completed
+	*	)
+    *
+	* @param string $distributionId Distribution ID from listDistributions()
+	* @return array
+	*/
+	public static function getDistributionInvalidationList($distributionId)
+	{
+		if (!extension_loaded('openssl'))
+		{
+			self::__triggerError(sprintf("S3::getDistributionInvalidationList(): [%s] %s",
+			"CloudFront functionality requires SSL"), __FILE__, __LINE__);
+			return false;
+		}
+
+		$useSSL = self::$useSSL;
+		self::$useSSL = true; // CloudFront requires SSL
+		$rest = new S3Request('GET', '', '2010-11-01/distribution/'.$distributionId.'/invalidation', 'cloudfront.amazonaws.com');
+		$rest = self::__getCloudFrontResponse($rest);
+		self::$useSSL = $useSSL;
+
+		if ($rest->error === false && $rest->code !== 200)
+			$rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+		if ($rest->error !== false)
+		{
+			trigger_error(sprintf("S3::getDistributionInvalidationList('{$distributionId}'): [%s]",
+			$rest->error['code'], $rest->error['message']), E_USER_WARNING);
+			return false;
+		}
+		elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->InvalidationSummary))
+		{
+			$list = array();
+			foreach ($rest->body->InvalidationSummary as $summary)
+				$list[(string)$summary->Id] = (string)$summary->Status;
+
 			return $list;
 		}
 		return array();
@@ -875,26 +1458,46 @@ class S3 {
 	/**
 	* Get a DistributionConfig DOMDocument
 	*
+	* http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/index.html?PutConfig.html
+	*
 	* @internal Used to create XML in createDistribution() and updateDistribution()
-	* @param string $bucket Origin bucket
+	* @param string $bucket S3 Origin bucket
 	* @param boolean $enabled Enabled (true/false)
 	* @param string $comment Comment to append
 	* @param string $callerReference Caller reference
 	* @param array $cnames Array of CNAME aliases
+	* @param string $defaultRootObject Default root object
+	* @param string $originAccessIdentity Origin access identity
+	* @param array $trustedSigners Array of trusted signers
 	* @return string
 	*/
-	private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array()) {
+	private static function __getCloudFrontDistributionConfigXML($bucket, $enabled, $comment, $callerReference = '0', $cnames = array(), $defaultRootObject = null, $originAccessIdentity = null, $trustedSigners = array())
+	{
 		$dom = new DOMDocument('1.0', 'UTF-8');
 		$dom->formatOutput = true;
 		$distributionConfig = $dom->createElement('DistributionConfig');
-		$distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2008-06-30/');
-		$distributionConfig->appendChild($dom->createElement('Origin', $bucket));
+		$distributionConfig->setAttribute('xmlns', 'http://cloudfront.amazonaws.com/doc/2010-11-01/');
+
+		$origin = $dom->createElement('S3Origin');
+		$origin->appendChild($dom->createElement('DNSName', $bucket));
+		if ($originAccessIdentity !== null) $origin->appendChild($dom->createElement('OriginAccessIdentity', $originAccessIdentity));
+		$distributionConfig->appendChild($origin);
+
+		if ($defaultRootObject !== null) $distributionConfig->appendChild($dom->createElement('DefaultRootObject', $defaultRootObject));
+
 		$distributionConfig->appendChild($dom->createElement('CallerReference', $callerReference));
 		foreach ($cnames as $cname)
 			$distributionConfig->appendChild($dom->createElement('CNAME', $cname));
 		if ($comment !== '') $distributionConfig->appendChild($dom->createElement('Comment', $comment));
 		$distributionConfig->appendChild($dom->createElement('Enabled', $enabled ? 'true' : 'false'));
+
+		$trusted = $dom->createElement('TrustedSigners');
+		foreach ($trustedSigners as $id => $type)
+			$trusted->appendChild($id !== '' ? $dom->createElement($type, $id) : $dom->createElement($type));
+		$distributionConfig->appendChild($trusted);
+
 		$dom->appendChild($distributionConfig);
+		//var_dump($dom->saveXML());
 		return $dom->saveXML();
 	}
 
@@ -902,32 +1505,61 @@ class S3 {
 	/**
 	* Parse a CloudFront distribution config
 	*
+	* See http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/index.html?GetDistribution.html
+	*
 	* @internal Used to parse the CloudFront DistributionConfig node to an array
 	* @param object &$node DOMNode
 	* @return array
 	*/
-	private static function __parseCloudFrontDistributionConfig(&$node) {
+	private static function __parseCloudFrontDistributionConfig(&$node)
+	{
+		if (isset($node->DistributionConfig))
+			return self::__parseCloudFrontDistributionConfig($node->DistributionConfig);
+
 		$dist = array();
-		if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName)) {
+		if (isset($node->Id, $node->Status, $node->LastModifiedTime, $node->DomainName))
+		{
 			$dist['id'] = (string)$node->Id;
 			$dist['status'] = (string)$node->Status;
 			$dist['time'] = strtotime((string)$node->LastModifiedTime);
 			$dist['domain'] = (string)$node->DomainName;
 		}
+
 		if (isset($node->CallerReference))
 			$dist['callerReference'] = (string)$node->CallerReference;
-		if (isset($node->Comment))
-			$dist['comment'] = (string)$node->Comment;
-		if (isset($node->Enabled, $node->Origin)) {
-			$dist['origin'] = (string)$node->Origin;
+
+		if (isset($node->Enabled))
 			$dist['enabled'] = (string)$node->Enabled == 'true' ? true : false;
-		} elseif (isset($node->DistributionConfig)) {
-			$dist = array_merge($dist, self::__parseCloudFrontDistributionConfig($node->DistributionConfig));
-		}
-		if (isset($node->CNAME)) {
-			$dist['cnames'] = array();
-			foreach ($node->CNAME as $cname) $dist['cnames'][(string)$cname] = (string)$cname;
+
+		if (isset($node->S3Origin))
+		{
+			if (isset($node->S3Origin->DNSName))
+				$dist['origin'] = (string)$node->S3Origin->DNSName;
+
+			$dist['originAccessIdentity'] = isset($node->S3Origin->OriginAccessIdentity) ?
+			(string)$node->S3Origin->OriginAccessIdentity : null;
 		}
+
+		$dist['defaultRootObject'] = isset($node->DefaultRootObject) ? (string)$node->DefaultRootObject : null;
+
+		$dist['cnames'] = array();
+		if (isset($node->CNAME))
+			foreach ($node->CNAME as $cname)
+				$dist['cnames'][(string)$cname] = (string)$cname;
+
+		$dist['trustedSigners'] = array();
+		if (isset($node->TrustedSigners))
+			foreach ($node->TrustedSigners as $signer)
+			{
+				if (isset($signer->Self))
+					$dist['trustedSigners'][''] = 'Self';
+				elseif (isset($signer->KeyPairId))
+					$dist['trustedSigners'][(string)$signer->KeyPairId] = 'KeyPairId';
+				elseif (isset($signer->AwsAccountNumber))
+					$dist['trustedSigners'][(string)$signer->AwsAccountNumber] = 'AwsAccountNumber';
+			}
+
+		$dist['comment'] = isset($node->Comment) ? (string)$node->Comment : null;
 		return $dist;
 	}
 
@@ -939,14 +1571,17 @@ class S3 {
 	* @param object &$rest S3Request instance
 	* @return object
 	*/
-	private static function __getCloudFrontResponse(&$rest) {
+	private static function __getCloudFrontResponse(&$rest)
+	{
 		$rest->getResponse();
 		if ($rest->response->error === false && isset($rest->response->body) &&
-		is_string($rest->response->body) && substr($rest->response->body, 0, 5) == '<?xml') {
+		is_string($rest->response->body) && substr($rest->response->body, 0, 5) == '<?xml')
+		{
 			$rest->response->body = simplexml_load_string($rest->response->body);
 			// Grab CloudFront errors
 			if (isset($rest->response->body->Error, $rest->response->body->Error->Code,
-			$rest->response->body->Error->Message)) {
+			$rest->response->body->Error->Message))
+			{
 				$rest->response->error = array(
 					'code' => (string)$rest->response->body->Error->Code,
 					'message' => (string)$rest->response->body->Error->Message
@@ -965,13 +1600,16 @@ class S3 {
 	* @param string &$file File path
 	* @return string
 	*/
-	public static function __getMimeType(&$file) {
+	public static function __getMimeType(&$file)
+	{
 		$type = false;
 		// Fileinfo documentation says fileinfo_open() will use the
 		// MAGIC env var for the magic file
 		if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
-		($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) {
-			if (($type = finfo_file($finfo, $file)) !== false) {
+		($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false)
+		{
+			if (($type = finfo_file($finfo, $file)) !== false)
+			{
 				// Remove the charset and grab the last content-type
 				$type = explode(' ', str_replace('; charset=', ';charset=', $type));
 				$type = array_pop($type);
@@ -1001,7 +1639,7 @@ class S3 {
 			'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
 			'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
 		);
-		$ext = strToLower(pathInfo($file, PATHINFO_EXTENSION));
+		$ext = strtolower(pathInfo($file, PATHINFO_EXTENSION));
 		return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
 	}
 
@@ -1013,7 +1651,8 @@ class S3 {
 	* @param string $string String to sign
 	* @return string
 	*/
-	public static function __getSignature($string) {
+	public static function __getSignature($string)
+	{
 		return 'AWS '.self::$__accessKey.':'.self::__getHash($string);
 	}
 
@@ -1027,7 +1666,8 @@ class S3 {
 	* @param string $string String to sign
 	* @return string
 	*/
-	private static function __getHash($string) {
+	private static function __getHash($string)
+	{
 		return base64_encode(extension_loaded('hash') ?
 		hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
 		(str_pad(self::$__secretKey, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
@@ -1037,8 +1677,9 @@ class S3 {
 
 }
 
-final class S3Request {
-	private $verb, $bucket, $uri, $resource = '', $parameters = array(),
+final class S3Request
+{
+	private $endpoint, $verb, $bucket, $uri, $resource = '', $parameters = array(),
 	$amzHeaders = array(), $headers = array(
 		'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
 	);
@@ -1053,21 +1694,42 @@ final class S3Request {
 	* @param string $uri Object URI
 	* @return mixed
 	*/
-	function __construct($verb, $bucket = '', $uri = '', $defaultHost = 's3.amazonaws.com') {
+	function __construct($verb, $bucket = '', $uri = '', $endpoint = 's3.amazonaws.com')
+	{
+		$this->endpoint = $endpoint;
 		$this->verb = $verb;
-		$this->bucket = strtolower($bucket);
+		$this->bucket = $bucket;
 		$this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/';
 
-		if ($this->bucket !== '') {
-			$this->headers['Host'] = $this->bucket.'.'.$defaultHost;
-			$this->resource = '/'.$this->bucket.$this->uri;
-		} else {
-			$this->headers['Host'] = $defaultHost;
-			//$this->resource = strlen($this->uri) > 1 ? '/'.$this->bucket.$this->uri : $this->uri;
+		//if ($this->bucket !== '')
+		//	$this->resource = '/'.$this->bucket.$this->uri;
+		//else
+		//	$this->resource = $this->uri;
+
+		if ($this->bucket !== '')
+		{
+			if ($this->__dnsBucketName($this->bucket))
+			{
+				$this->headers['Host'] = $this->bucket.'.'.$this->endpoint;
+				$this->resource = '/'.$this->bucket.$this->uri;
+			}
+			else
+			{
+				$this->headers['Host'] = $this->endpoint;
+				$this->uri = $this->uri;
+				if ($this->bucket !== '') $this->uri = '/'.$this->bucket.$this->uri;
+				$this->bucket = '';
+				$this->resource = $this->uri;
+			}
+		}
+		else
+		{
+			$this->headers['Host'] = $this->endpoint;
 			$this->resource = $this->uri;
 		}
-		$this->headers['Date'] = gmdate('D, d M Y H:i:s T');
 
+
+		$this->headers['Date'] = gmdate('D, d M Y H:i:s T');
 		$this->response = new STDClass;
 		$this->response->error = false;
 	}
@@ -1080,7 +1742,8 @@ final class S3Request {
 	* @param string $value Value
 	* @return void
 	*/
-	public function setParameter($key, $value) {
+	public function setParameter($key, $value)
+	{
 		$this->parameters[$key] = $value;
 	}
 
@@ -1092,7 +1755,8 @@ final class S3Request {
 	* @param string $value Value
 	* @return void
 	*/
-	public function setHeader($key, $value) {
+	public function setHeader($key, $value)
+	{
 		$this->headers[$key] = $value;
 	}
 
@@ -1104,7 +1768,8 @@ final class S3Request {
 	* @param string $value Value
 	* @return void
 	*/
-	public function setAmzHeader($key, $value) {
+	public function setAmzHeader($key, $value)
+	{
 		$this->amzHeaders[$key] = $value;
 	}
 
@@ -1114,13 +1779,14 @@ final class S3Request {
 	*
 	* @return object | false
 	*/
-	public function getResponse() {
+	public function getResponse()
+	{
 		$query = '';
-		if (sizeof($this->parameters) > 0) {
+		if (sizeof($this->parameters) > 0)
+		{
 			$query = substr($this->uri, -1) !== '?' ? '?' : '&';
 			foreach ($this->parameters as $var => $value)
 				if ($value == null || $value == '') $query .= $var.'&';
-				// Parameters should be encoded (thanks Sean O'Dea)
 				else $query .= $var.'='.rawurlencode($value).'&';
 			$query = substr($query, 0, -1);
 			$this->uri .= $query;
@@ -1128,24 +1794,39 @@ final class S3Request {
 			if (array_key_exists('acl', $this->parameters) ||
 			array_key_exists('location', $this->parameters) ||
 			array_key_exists('torrent', $this->parameters) ||
+			array_key_exists('website', $this->parameters) ||
 			array_key_exists('logging', $this->parameters))
 				$this->resource .= $query;
 		}
-		$url = ((S3::$useSSL && extension_loaded('openssl')) ?
-		'https://':'http://').$this->headers['Host'].$this->uri;
-		//var_dump($this->bucket, $this->uri, $this->resource, $url);
+		$url = (S3::$useSSL ? 'https://' : 'http://') . ($this->headers['Host'] !== '' ? $this->headers['Host'] : $this->endpoint) . $this->uri;
+
+		//var_dump('bucket: ' . $this->bucket, 'uri: ' . $this->uri, 'resource: ' . $this->resource, 'url: ' . $url);
 
 		// Basic setup
 		$curl = curl_init();
 		curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
 
-		if (S3::$useSSL) {
-			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1);
-			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
+		if (S3::$useSSL)
+		{
+			// SSL Validation can now be optional for those with broken OpenSSL installations
+			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, S3::$useSSLValidation ? 1 : 0);
+			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, S3::$useSSLValidation ? 1 : 0);
+
+			if (S3::$sslKey !== null) curl_setopt($curl, CURLOPT_SSLKEY, S3::$sslKey);
+			if (S3::$sslCert !== null) curl_setopt($curl, CURLOPT_SSLCERT, S3::$sslCert);
+			if (S3::$sslCACert !== null) curl_setopt($curl, CURLOPT_CAINFO, S3::$sslCACert);
 		}
 
 		curl_setopt($curl, CURLOPT_URL, $url);
 
+		if (S3::$proxy != null && isset(S3::$proxy['host']))
+		{
+			curl_setopt($curl, CURLOPT_PROXY, S3::$proxy['host']);
+			curl_setopt($curl, CURLOPT_PROXYTYPE, S3::$proxy['type']);
+			if (isset(S3::$proxy['user'], S3::$proxy['pass']) && S3::$proxy['user'] != null && S3::$proxy['pass'] != null)
+				curl_setopt($curl, CURLOPT_PROXYUSERPWD, sprintf('%s:%s', S3::$proxy['user'], S3::$proxy['pass']));
+		}
+
 		// Headers
 		$headers = array(); $amz = array();
 		foreach ($this->amzHeaders as $header => $value)
@@ -1155,20 +1836,32 @@ final class S3Request {
 
 		// Collect AMZ headers for signature
 		foreach ($this->amzHeaders as $header => $value)
-			if (strlen($value) > 0) $amz[] = strToLower($header).':'.$value;
+			if (strlen($value) > 0) $amz[] = strtolower($header).':'.$value;
 
 		// AMZ headers must be sorted
-		if (sizeof($amz) > 0) {
-			sort($amz);
+		if (sizeof($amz) > 0)
+		{
+			//sort($amz);
+			usort($amz, array(&$this, '__sortMetaHeadersCmp'));
 			$amz = "\n".implode("\n", $amz);
 		} else $amz = '';
 
-		// Authorization string (CloudFront stringToSign should only contain a date)
-		$headers[] = 'Authorization: ' . S3::__getSignature(
-			$this->headers['Host'] == 'cloudfront.amazonaws.com' ? $this->headers['Date'] :
-			$this->verb."\n".$this->headers['Content-MD5']."\n".
-			$this->headers['Content-Type']."\n".$this->headers['Date'].$amz."\n".$this->resource
-		);
+		if (S3::hasAuth())
+		{
+			// Authorization string (CloudFront stringToSign should only contain a date)
+			if ($this->headers['Host'] == 'cloudfront.amazonaws.com')
+				$headers[] = 'Authorization: ' . S3::__getSignature($this->headers['Date']);
+			else
+			{
+				$headers[] = 'Authorization: ' . S3::__getSignature(
+					$this->verb."\n".
+					$this->headers['Content-MD5']."\n".
+					$this->headers['Content-Type']."\n".
+					$this->headers['Date'].$amz."\n".
+					$this->resource
+				);
+			}
+        }
 
 		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
 		curl_setopt($curl, CURLOPT_HEADER, false);
@@ -1178,20 +1871,23 @@ final class S3Request {
 		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
 
 		// Request types
-		switch ($this->verb) {
+		switch ($this->verb)
+		{
 			case 'GET': break;
 			case 'PUT': case 'POST': // POST only used for CloudFront
-				if ($this->fp !== false) {
+				if ($this->fp !== false)
+				{
 					curl_setopt($curl, CURLOPT_PUT, true);
 					curl_setopt($curl, CURLOPT_INFILE, $this->fp);
-					if ($this->size > 0)
+					if ($this->size >= 0)
 						curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
-				} elseif ($this->data !== false) {
+				}
+				elseif ($this->data !== false)
+				{
 					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
 					curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
-					if ($this->size > 0)
-						curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
-				} else
+				}
+				else
 					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
 			break;
 			case 'HEAD':
@@ -1218,12 +1914,14 @@ final class S3Request {
 
 		// Parse body into XML
 		if ($this->response->error === false && isset($this->response->headers['type']) &&
-		$this->response->headers['type'] == 'application/xml' && isset($this->response->body)) {
+		$this->response->headers['type'] == 'application/xml' && isset($this->response->body))
+		{
 			$this->response->body = simplexml_load_string($this->response->body);
 
 			// Grab S3 errors
-			if (!in_array($this->response->code, array(200, 204)) &&
-			isset($this->response->body->Code, $this->response->body->Message)) {
+			if (!in_array($this->response->code, array(200, 204, 206)) &&
+			isset($this->response->body->Code, $this->response->body->Message))
+			{
 				$this->response->error = array(
 					'code' => (string)$this->response->body->Code,
 					'message' => (string)$this->response->body->Message
@@ -1240,6 +1938,24 @@ final class S3Request {
 		return $this->response;
 	}
 
+	/**
+	* Sort compare for meta headers
+	*
+	* @internal Used to sort x-amz meta headers
+	* @param string $a String A
+	* @param string $b String B
+	* @return integer
+	*/
+	private function __sortMetaHeadersCmp($a, $b)
+	{
+		$lenA = strpos($a, ':');
+		$lenB = strpos($b, ':');
+		$minLen = min($lenA, $lenB);
+		$ncmp = strncmp($a, $b, $minLen);
+		if ($lenA == $lenB) return $ncmp;
+		if (0 == $ncmp) return $lenA < $lenB ? -1 : 1;
+		return $ncmp;
+	}
 
 	/**
 	* CURL write callback
@@ -1248,8 +1964,9 @@ final class S3Request {
 	* @param string &$data Data
 	* @return integer
 	*/
-	private function __responseWriteCallback(&$curl, &$data) {
-		if ($this->response->code == 200 && $this->fp !== false)
+	private function __responseWriteCallback(&$curl, &$data)
+	{
+		if (in_array($this->response->code, array(200, 206)) && $this->fp !== false)
 			return fwrite($this->fp, $data);
 		else
 			$this->response->body .= $data;
@@ -1258,18 +1975,39 @@ final class S3Request {
 
 
 	/**
+	* Check DNS conformity
+	*
+	* @param string $bucket Bucket name
+	* @return boolean
+	*/
+	private function __dnsBucketName($bucket)
+	{
+		if (strlen($bucket) > 63 || !preg_match("/[^a-z0-9\.-]/", $bucket)) return false;
+		if (strstr($bucket, '-.') !== false) return false;
+		if (strstr($bucket, '..') !== false) return false;
+		if (!preg_match("/^[0-9a-z]/", $bucket)) return false;
+		if (!preg_match("/[0-9a-z]$/", $bucket)) return false;
+		return true;
+	}
+
+
+	/**
 	* CURL header callback
 	*
 	* @param resource &$curl CURL resource
 	* @param string &$data Data
 	* @return integer
 	*/
-	private function __responseHeaderCallback(&$curl, &$data) {
+	private function __responseHeaderCallback(&$curl, &$data)
+	{
 		if (($strlen = strlen($data)) <= 2) return $strlen;
 		if (substr($data, 0, 4) == 'HTTP')
 			$this->response->code = (int)substr($data, 9, 3);
-		else {
-			list($header, $value) = explode(': ', trim($data), 2);
+		else
+		{
+			$data = trim($data);
+			if (strpos($data, ': ') === false) return $strlen;
+			list($header, $value) = explode(': ', $data, 2);
 			if ($header == 'Last-Modified')
 				$this->response->headers['time'] = strtotime($value);
 			elseif ($header == 'Content-Length')
@@ -1279,9 +2017,18 @@ final class S3Request {
 			elseif ($header == 'ETag')
 				$this->response->headers['hash'] = $value{0} == '"' ? substr($value, 1, -1) : $value;
 			elseif (preg_match('/^x-amz-meta-.*$/', $header))
-				$this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
+				$this->response->headers[$header] = $value;
 		}
 		return $strlen;
 	}
 
 }
+
+class S3Exception extends Exception {
+	function __construct($message, $file, $line, $code = 0)
+	{
+		parent::__construct($message, $code);
+		$this->file = $file;
+		$this->line = $line;
+	}
+}
diff --git a/repository/s3/lib.php b/repository/s3/lib.php
index c25dfc6..bf5718f 100644
--- a/repository/s3/lib.php
+++ b/repository/s3/lib.php
@@ -24,7 +24,7 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 require_once($CFG->dirroot . '/repository/lib.php');
-require_once('S3.php');
+require_once($CFG->dirroot . '/repository/s3/S3.php');
 
 /**
  * This is a repository class used to browse Amazon S3 content.
-- 
1.7.9.5


From df9b10e10a54e321a787d9d5468b940f0b04fdaf Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 23 Jul 2012 13:12:29 +0800
Subject: [PATCH 269/903] MDL-25953 Repository: Amazon S3 supports sub
 directories

---
 repository/s3/lib.php |  102 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 85 insertions(+), 17 deletions(-)

diff --git a/repository/s3/lib.php b/repository/s3/lib.php
index bf5718f..54caa3b 100644
--- a/repository/s3/lib.php
+++ b/repository/s3/lib.php
@@ -50,6 +50,23 @@ class repository_s3 extends repository {
     }
 
     /**
+     * Extracts the Bucket and URI from the path
+     *
+     * @param string $path path in this format 'bucket/path/to/folder/and/file'
+     * @return array including bucket and uri
+     */
+    protected function explode_path($path) {
+        $parts = explode('/', $path, 2);
+        if (isset($parts[1]) && $parts[1] !== '') {
+            list($bucket, $uri) = $parts;
+        } else {
+            $bucket = $parts[0];
+            $uri = '';
+        }
+        return array($bucket, $uri);
+    }
+
+    /**
      * Get S3 file list
      *
      * @param string $path
@@ -60,8 +77,13 @@ class repository_s3 extends repository {
         if (empty($this->access_key)) {
             die(json_encode(array('e'=>get_string('needaccesskey', 'repository_s3'))));
         }
+
         $list = array();
         $list['list'] = array();
+        $list['path'] = array(
+            array('name' => get_string('pluginname', 'repository_s3'), 'path' => '')
+        );
+
         // the management interface url
         $list['manage'] = false;
         // dynamically loading
@@ -71,29 +93,78 @@ class repository_s3 extends repository {
         $list['nologin'] = true;
         // set to true, the search button will be removed
         $list['nosearch'] = true;
+
         $tree = array();
+
         if (empty($path)) {
             $buckets = $this->s->listBuckets();
             foreach ($buckets as $bucket) {
                 $folder = array(
                     'title' => $bucket,
                     'children' => array(),
-                    'thumbnail'=>$OUTPUT->pix_url(file_folder_icon(90))->out(false),
-                    'path'=>$bucket
+                    'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
+                    'path' => $bucket
                     );
                 $tree[] = $folder;
             }
         } else {
-            $contents = $this->s->getBucket($path);
-            foreach ($contents as $file) {
-                $info = $this->s->getObjectInfo($path, baseName($file['name']));
-                $tree[] = array(
-                    'title'=>$file['name'],
-                    'size'=>$file['size'],
-                    'date'=>userdate($file['time']),
-                    'source'=>$path.'/'.$file['name'],
-                    'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file['name'], 90))->out(false)
+            $files = array();
+            $folders = array();
+            list($bucket, $uri) = $this->explode_path($path);
+
+            $contents = $this->s->getBucket($bucket, $uri, null, null, '/', true);
+            foreach ($contents as $object) {
+
+                // If object has a prefix, it is a 'CommonPrefix', which we consider a folder
+                if (isset($object['prefix'])) {
+                    $title = rtrim($object['prefix'], '/');
+                } else {
+                    $title = $object['name'];
+                }
+
+                // Removes the prefix (folder path) from the title
+                if (strlen($uri) > 0) {
+                    $title = substr($title, strlen($uri));
+                    // Check if title is empty and not zero
+                    if (empty($title) && !is_numeric($title)) {
+                        // Amazon returns the prefix itself, we skip it
+                        continue;
+                    }
+                }
+
+                // This is a so-called CommonPrefix, we consider it as a folder
+                if (isset($object['prefix'])) {
+                    $folders[] = array(
+                        'title' => $title,
+                        'children' => array(),
+                        'thumbnail'=> $OUTPUT->pix_url(file_folder_icon(90))->out(false),
+                        'path' => $bucket . '/' . $object['prefix']
                     );
+                } else {
+                    $files[] = array(
+                        'title' => $title,
+                        'size' => $object['size'],
+                        'datemodified' => $object['time'],
+                        'source' => $bucket . '/' . $object['name'],
+                        'thumbnail' => $OUTPUT->pix_url(file_extension_icon($title, 90))->out(false)
+                    );
+                }
+            }
+            $tree = array_merge($folders, $files);
+        }
+
+        $trail = '';
+        if (!empty($path)) {
+            $parts = explode('/', $path);
+            if (count($parts) > 1) {
+                foreach ($parts as $part) {
+                    if (!empty($part)) {
+                        $trail .= $part . '/';
+                        $list['path'][] = array('name' => $part, 'path' => $trail);
+                    }
+                }
+            } else {
+                $list['path'][] = array('name' => $path, 'path' => $path);
             }
         }
 
@@ -110,13 +181,10 @@ class repository_s3 extends repository {
      * @return array The local stored path
      */
     public function get_file($filepath, $file = '') {
-        global $CFG;
-        $arr = explode('/', $filepath);
-        $bucket   = $arr[0];
-        $filename = $arr[1];
+        list($bucket, $uri) = $this->explode_path($filepath);
         $path = $this->prepare_file($file);
-        $this->s->getObject($bucket, $filename, $path);
-        return array('path'=>$path);
+        $this->s->getObject($bucket, $uri, $path);
+        return array('path' => $path);
     }
 
     /**
-- 
1.7.9.5


From fcda7dbb893af11093422abde70439cab232ecbc Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 17 Jul 2012 14:22:18 +0800
Subject: [PATCH 270/903] MDL-32827 calendar: Fixining calender entries with
 no eventtype

---
 lib/db/upgrade.php |   23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 9dd53d2..a777170 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -85,7 +85,7 @@ defined('MOODLE_INTERNAL') || die();
  * @return bool always true
  */
 function xmldb_main_upgrade($oldversion) {
-    global $CFG, $USER, $DB, $OUTPUT;
+    global $CFG, $USER, $DB, $OUTPUT, $SITE;
 
     require_once($CFG->libdir.'/db/upgradelib.php'); // Core Upgrade-related functions
 
@@ -923,5 +923,26 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.04);
     }
 
+    if ($oldversion < 2012062501.06) {
+        $rs = $DB->get_recordset('event', array( 'eventtype' => ''), '', 'id, courseid, groupid, userid, modulename');
+        foreach ($rs as $event) {
+            if ($event->courseid == $SITE->id) {                                // Site event
+                $DB->set_field('event', 'eventtype', 'site', array('id' => $event->id));
+            } else if ($event->courseid != 0 && $event->groupid == 0 && ($event->modulename == 'assignment' || $event->modulename == 'assign')) {
+                // Course assingment event
+                $DB->set_field('event', 'eventtype', 'due', array('id' => $event->id));
+            } else if ($event->courseid != 0 && $event->groupid == 0) {      // Course event
+                $DB->set_field('event', 'eventtype', 'course', array('id' => $event->id));
+            } else if ($event->groupid) {                                      // Group event
+                $DB->set_field('event', 'eventtype', 'group', array('id' => $event->id));
+            } else if ($event->userid) {                                       // User event
+                $DB->set_field('event', 'eventtype', 'user', array('id' => $event->id));
+            }
+        }
+        $rs->close();
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2012062501.06);
+    }
+
     return true;
 }
-- 
1.7.9.5


From 0bdf18a7c91472118f4a6188963fa89b22a2bf85 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Wed, 25 Jul 2012 13:27:28 +0800
Subject: [PATCH 271/903] MDL-32827 calendar: Added logic to handle calendar
 events with empty eventtypes during restore

---
 backup/moodle2/restore_stepslib.php |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index adb3cd6..19d183a 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -1737,6 +1737,23 @@ class restore_calendarevents_structure_step extends restore_structure_step {
                 return;
             }
         }
+        // Handle events with empty eventtype //MDL-32827
+        if(empty($data->eventtype)) {
+            if ($data->courseid == $SITE->id) {                                // Site event
+                $data->eventtype = "site";
+            } else if ($data->courseid != 0 && $data->groupid == 0 && ($data->modulename == 'assignment' || $data->modulename == 'assign')) {
+                // Course assingment event
+                $data->eventtype = "due";
+            } else if ($data->courseid != 0 && $data->groupid == 0) {      // Course event
+                $data->eventtype = "course";
+            } else if ($data->groupid) {                                      // Group event
+                $data->eventtype = "group";
+            } else if ($data->userid) {                                       // User event
+                $data->eventtype = "user";
+            } else {
+                return;
+            }
+        }
 
         $params = array(
                 'name'           => $data->name,
-- 
1.7.9.5


From 41499f832b4adcf7e72cd4bbd9b939efcd3adac0 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Fri, 27 Jul 2012 11:50:37 +0800
Subject: [PATCH 272/903] MDL-32827 calendar: Bumping the version

---
 version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/version.php b/version.php
index 4d57f57..d073294 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.05;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.06;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From def687a6a26dca4c521ebc03bf9cde9c78197c47 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 24 Jul 2012 10:18:15 +0800
Subject: [PATCH 273/903] MDL-34239 Blog: Editing blog associated with module
 will be keep it's association

---
 blog/edit_form.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/blog/edit_form.php b/blog/edit_form.php
index 292d55c..55ce91d 100644
--- a/blog/edit_form.php
+++ b/blog/edit_form.php
@@ -101,6 +101,7 @@ class blog_edit_form extends moodleform {
                     $a = new stdClass();
                     $a->modtype = $DB->get_field('modules', 'name', array('id' => $cm->module));
                     $a->modname = $DB->get_field($a->modtype, 'name', array('id' => $cm->instance));
+                    $modid = $context->instanceid;
                 }
 
                 $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-- 
1.7.9.5


From a361ff56459da9dd5cb9935c0d9f93724294a77b Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 27 Jul 2012 11:42:03 +0100
Subject: [PATCH 274/903] MDL-34599 quiz attempts: more robust if page number
 out of range.

Rather than throwing an exception, we should just show the first/last
page of the quiz if the page number is out-of-range.
---
 mod/quiz/attempt.php        |    1 +
 mod/quiz/attemptlib.php     |   12 +++++++++++-
 mod/quiz/processattempt.php |   12 ++++++------
 mod/quiz/review.php         |    5 +++--
 4 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php
index cdff54e..135ae14 100644
--- a/mod/quiz/attempt.php
+++ b/mod/quiz/attempt.php
@@ -41,6 +41,7 @@ $attemptid = required_param('attempt', PARAM_INT);
 $page = optional_param('page', 0, PARAM_INT);
 
 $attemptobj = quiz_attempt::create($attemptid);
+$page = $attemptobj->force_page_number_into_range($page);
 $PAGE->set_url($attemptobj->attempt_url(null, $page));
 
 // Check login.
diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php
index 1de37c1..a4e70fa 100644
--- a/mod/quiz/attemptlib.php
+++ b/mod/quiz/attemptlib.php
@@ -555,6 +555,16 @@ class quiz_attempt {
         }
     }
 
+    /**
+     * If the given page number is out of range (before the first page, or after
+     * the last page, chnage it to be within range).
+     * @param int $page the requested page number.
+     * @return int a safe page number to use.
+     */
+    public function force_page_number_into_range($page) {
+        return min(max($page, 0), count($this->pagelayout) - 1);
+    }
+
     // Simple getters ==========================================================
     public function get_quiz() {
         return $this->quizobj->get_quiz();
@@ -1101,7 +1111,7 @@ class quiz_attempt {
     }
 
     /**
-     * Initialise the JS etc. required all the questions on a page..
+     * Initialise the JS etc. required all the questions on a page.
      * @param mixed $page a page number, or 'all'.
      */
     public function get_html_head_contributions($page = 'all', $showall = false) {
diff --git a/mod/quiz/processattempt.php b/mod/quiz/processattempt.php
index 1757eb5..9f391f0 100644
--- a/mod/quiz/processattempt.php
+++ b/mod/quiz/processattempt.php
@@ -37,13 +37,13 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 $timenow = time();
 
 // Get submitted parameters.
-$attemptid = required_param('attempt', PARAM_INT);
-$next = optional_param('next', false, PARAM_BOOL);
-$thispage = optional_param('thispage', 0, PARAM_INT);
-$nextpage = optional_param('nextpage', 0, PARAM_INT);
+$attemptid     = required_param('attempt',  PARAM_INT);
+$thispage      = required_param('thispage', PARAM_INT);
+$nextpage      = required_param('nextpage', PARAM_INT);
+$next          = optional_param('next',          false, PARAM_BOOL);
 $finishattempt = optional_param('finishattempt', false, PARAM_BOOL);
-$timeup = optional_param('timeup', 0, PARAM_BOOL); // True if form was submitted by timer.
-$scrollpos = optional_param('scrollpos', '', PARAM_RAW);
+$timeup        = optional_param('timeup',        0,      PARAM_BOOL); // True if form was submitted by timer.
+$scrollpos     = optional_param('scrollpos',     '',     PARAM_RAW);
 
 $transaction = $DB->start_delegated_transaction();
 $attemptobj = quiz_attempt::create($attemptid);
diff --git a/mod/quiz/review.php b/mod/quiz/review.php
index 7bb6335..c19afaa 100644
--- a/mod/quiz/review.php
+++ b/mod/quiz/review.php
@@ -31,8 +31,8 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
 
 $attemptid = required_param('attempt', PARAM_INT);
-$page = optional_param('page', 0, PARAM_INT);
-$showall = optional_param('showall', 0, PARAM_BOOL);
+$page      = optional_param('page', 0, PARAM_INT);
+$showall   = optional_param('showall', 0, PARAM_BOOL);
 
 $url = new moodle_url('/mod/quiz/review.php', array('attempt'=>$attemptid));
 if ($page !== 0) {
@@ -44,6 +44,7 @@ if ($showall !== 0) {
 $PAGE->set_url($url);
 
 $attemptobj = quiz_attempt::create($attemptid);
+$page = $attemptobj->force_page_number_into_range($page);
 
 // Check login.
 require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
-- 
1.7.9.5


From 53f2f306dd14bf994f98f6a8bfdc6e4ccba3eee1 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Mon, 23 Jul 2012 11:28:01 +0100
Subject: [PATCH 275/903] MDL-34483 qformat_examview: changes required to make
 it basically work.

---
 question/format/examview/format.php |   52 +++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index dc0481a..3bd0539 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -58,6 +58,10 @@ class qformat_examview extends qformat_default {
         return true;
     }
 
+    public function mime_type() {
+        return 'application/xml';
+    }
+
     /**
      * unxmlise reconstructs part of the xml data structure in order
      * to identify the actual data therein
@@ -84,6 +88,26 @@ class qformat_examview extends qformat_default {
         $text = strip_tags($text);
         return $text;
     }
+    protected function text_field($text) {
+        return array(
+            'text' => htmlspecialchars(trim($text), ENT_NOQUOTES),
+            'format' => FORMAT_HTML,
+            'files' => array(),
+        );
+    }
+
+    protected function add_blank_combined_feedback($question) {
+        $question->correctfeedback['text'] = '';
+        $question->correctfeedback['format'] = $question->questiontextformat;
+        $question->correctfeedback['files'] = array();
+        $question->partiallycorrectfeedback['text'] = '';
+        $question->partiallycorrectfeedback['format'] = $question->questiontextformat;
+        $question->partiallycorrectfeedback['files'] = array();
+        $question->incorrectfeedback['text'] = '';
+        $question->incorrectfeedback['format'] = $question->questiontextformat;
+        $question->incorrectfeedback['files'] = array();
+        return $question;
+    }
 
     function parse_matching_groups($matching_groups)
     {
@@ -115,7 +139,7 @@ class qformat_examview extends qformat_default {
         $phrase = trim($this->unxmlise($qrec['text']['0']['#']));
         $answer = trim($this->unxmlise($qrec['answer']['0']['#']));
         $answer = strip_tags( $answer );
-        $match_group->subquestions[] = $phrase;
+        $match_group->subquestions[] = $this->text_field($phrase);
         $match_group->subanswers[] = $match_group->subchoices[$answer];
         $this->matching_questions[$groupname] = $match_group;
         return NULL;
@@ -130,8 +154,11 @@ class qformat_examview extends qformat_default {
             $question = $this->defaultquestion();
             $htmltext = s($match_group->questiontext);
             $question->questiontext = $htmltext;
-            $question->name = $question->questiontext;
+            $question->questiontextformat = FORMAT_HTML;
+            $question->questiontextfiles = array();
+            $question->name = shorten_text( $question->questiontext, 250 );
             $question->qtype = MATCH;
+            $question = $this->add_blank_combined_feedback($question);
             $question->subquestions = array();
             $question->subanswers = array();
             foreach($match_group->subquestions as $key => $value) {
@@ -192,6 +219,8 @@ class qformat_examview extends qformat_default {
         // Only one answer is allowed
         $htmltext = $this->unxmlise($qrec['#']['text'][0]['#']);
         $question->questiontext = $htmltext;
+        $question->questiontextformat = FORMAT_HTML;
+        $question->questiontextfiles = array();
         $question->name = shorten_text( $question->questiontext, 250 );
 
         switch ($question->qtype) {
@@ -232,30 +261,31 @@ class qformat_examview extends qformat_default {
         $question->answer = $choices[$answer];
         $question->correctanswer = $question->answer;
         if ($question->answer == 1) {
-            $question->feedbacktrue = 'Correct';
-            $question->feedbackfalse = 'Incorrect';
+            $question->feedbacktrue = $this->text_field('Correct');
+            $question->feedbackfalse = $this->text_field('Incorrect');
         } else {
-            $question->feedbacktrue = 'Incorrect';
-            $question->feedbackfalse = 'Correct';
+            $question->feedbacktrue = $this->text_field('Incorrect');
+            $question->feedbackfalse = $this->text_field('Correct');
         }
         return $question;
     }
 
     function parse_mc($qrec, $question)
     {
+        $question = $this->add_blank_combined_feedback($question);
         $answer = 'choice-'.strtolower(trim($qrec['answer'][0]['#']));
 
         $choices = $qrec['choices'][0]['#'];
         foreach($choices as $key => $value) {
             if (strpos(trim($key),'choice-') !== FALSE) {
 
-                $question->answer[$key] = s($this->unxmlise($value[0]['#']));
+                $question->answer[$key] = $this->text_field(s($this->unxmlise($value[0]['#'])));
                 if (strcmp($key, $answer) == 0) {
                     $question->fraction[$key] = 1;
-                    $question->feedback[$key] = 'Correct';
+                    $question->feedback[$key] = $this->text_field('Correct');
                 } else {
                     $question->fraction[$key] = 0;
-                    $question->feedback[$key] = 'Incorrect';
+                    $question->feedback[$key] = $this->text_field('Incorrect');
                 }
             }
         }
@@ -274,7 +304,7 @@ class qformat_examview extends qformat_default {
             if (strlen($value) > 0) {
                 $question->answer[$key] = $value;
                 $question->fraction[$key] = 1;
-                $question->feedback[$key] = "Correct";
+                $question->feedback[$key] = $this->text_field("Correct");
             }
         }
         return $question;
@@ -299,7 +329,7 @@ class qformat_examview extends qformat_default {
                 $errormargin = 0;
                 $question->answer[$key] = $value;
                 $question->fraction[$key] = 1;
-                $question->feedback[$key] = "Correct";
+                $question->feedback[$key] = $this->text_field("Correct");
                 $question->min[$key] = $question->answer[$key] - $errormargin;
                 $question->max[$key] = $question->answer[$key] + $errormargin;
             }
-- 
1.7.9.5


From 0940ba1f16861fdf7031d44c9b7746f6765c5971 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Mon, 23 Jul 2012 11:31:32 +0100
Subject: [PATCH 276/903] MDL-34483 qformat_examview: clean the code to make
 codechecker happy

---
 question/format/examview/format.php |  139 ++++++++++++++++-------------------
 1 file changed, 63 insertions(+), 76 deletions(-)

diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index 3bd0539..f9e1975 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -26,7 +26,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-require_once ($CFG->libdir . '/xmlize.php');
+require_once($CFG->libdir . '/xmlize.php');
 
 
 /**
@@ -54,7 +54,7 @@ class qformat_examview extends qformat_default {
 
     public $matching_questions = array();
 
-    function provide_import() {
+    public function provide_import() {
         return true;
     }
 
@@ -68,23 +68,22 @@ class qformat_examview extends qformat_default {
      * @param array $xml section of the xml data structure
      * @return string data with evrything else removed
      */
-    function unxmlise( $xml ) {
-        // if it's not an array then it's probably just data
+    protected function unxmlise( $xml ) {
+        // If it's not an array then it's probably just data.
         if (!is_array($xml)) {
             $text = s($xml);
-        }
-        else {
-            // otherwise parse the array
+        } else {
+            // Otherwise parse the array.
             $text = '';
-            foreach ($xml as $tag=>$data) {
-                // if tag is '@' then it's attributes and we don't care
+            foreach ($xml as $tag => $data) {
+                // If tag is '@' then it's attributes and we don't care.
                 if ($tag!=='@') {
                     $text = $text . $this->unxmlise( $data );
                 }
             }
         }
 
-        // currently we throw the tags we found
+        // Currently we throw the tags we found.
         $text = strip_tags($text);
         return $text;
     }
@@ -109,13 +108,12 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    function parse_matching_groups($matching_groups)
-    {
+    protected function parse_matching_groups($matching_groups) {
         if (empty($matching_groups)) {
             return;
         }
-        foreach($matching_groups as $match_group) {
-            $newgroup = NULL;
+        foreach ($matching_groups as $match_group) {
+            $newgroup = null;
             $groupname = trim($match_group['@']['name']);
             $questiontext = $this->unxmlise($match_group['#']['text'][0]['#']);
             $newgroup->questiontext = trim($questiontext);
@@ -123,8 +121,8 @@ class qformat_examview extends qformat_default {
             $newgroup->subquestions = array();
             $newgroup->subanswers = array();
             $choices = $match_group['#']['choices']['0']['#'];
-            foreach($choices as $key => $value) {
-                if (strpos(trim($key),'choice-') !== FALSE) {
+            foreach ($choices as $key => $value) {
+                if (strpos(trim($key), 'choice-') !== false) {
                     $key = strtoupper(trim(str_replace('choice-', '', $key)));
                     $newgroup->subchoices[$key] = trim($value['0']['#']);
                 }
@@ -133,8 +131,7 @@ class qformat_examview extends qformat_default {
         }
     }
 
-    function parse_ma($qrec, $groupname)
-    {
+    protected function parse_ma($qrec, $groupname) {
         $match_group = $this->matching_questions[$groupname];
         $phrase = trim($this->unxmlise($qrec['text']['0']['#']));
         $answer = trim($this->unxmlise($qrec['answer']['0']['#']));
@@ -142,15 +139,14 @@ class qformat_examview extends qformat_default {
         $match_group->subquestions[] = $this->text_field($phrase);
         $match_group->subanswers[] = $match_group->subchoices[$answer];
         $this->matching_questions[$groupname] = $match_group;
-        return NULL;
+        return null;
     }
 
-    function process_matches(&$questions)
-    {
+    protected function process_matches(&$questions) {
         if (empty($this->matching_questions)) {
             return;
         }
-        foreach($this->matching_questions as $match_group) {
+        foreach ($this->matching_questions as $match_group) {
             $question = $this->defaultquestion();
             $htmltext = s($match_group->questiontext);
             $question->questiontext = $htmltext;
@@ -161,7 +157,7 @@ class qformat_examview extends qformat_default {
             $question = $this->add_blank_combined_feedback($question);
             $question->subquestions = array();
             $question->subanswers = array();
-            foreach($match_group->subquestions as $key => $value) {
+            foreach ($match_group->subquestions as $key => $value) {
                 $htmltext = s($value);
                 $question->subquestions[] = $htmltext;
 
@@ -172,28 +168,28 @@ class qformat_examview extends qformat_default {
         }
     }
 
-    function cleanUnicode($text) {
+    protected function cleanunicode($text) {
         return str_replace('&#x2019;', "'", $text);
     }
 
     protected function readquestions($lines) {
-        /// Parses an array of lines into an array of questions,
-        /// where each item is a question object as defined by
-        /// readquestion().
+        // Parses an array of lines into an array of questions,
+        // where each item is a question object as defined by
+        // readquestion().
 
         $questions = array();
         $currentquestion = array();
 
         $text = implode($lines, ' ');
-        $text = $this->cleanUnicode($text);
+        $text = $this->cleanunicode($text);
 
         $xml = xmlize($text, 0);
         if (!empty($xml['examview']['#']['matching-group'])) {
             $this->parse_matching_groups($xml['examview']['#']['matching-group']);
         }
 
-        $questionNode = $xml['examview']['#']['question'];
-        foreach($questionNode as $currentquestion) {
+        $questionnode = $xml['examview']['#']['question'];
+        foreach ($questionnode as $currentquestion) {
             if ($question = $this->readquestion($currentquestion)) {
                 $questions[] = $question;
             }
@@ -202,21 +198,18 @@ class qformat_examview extends qformat_default {
         $this->process_matches($questions);
         return $questions;
     }
-    // end readquestions
 
-    function readquestion($qrec)
-    {
+    public function readquestion($qrec) {
 
         $type = trim($qrec['@']['type']);
         $question = $this->defaultquestion();
         if (array_key_exists($type, $this->qtypes)) {
             $question->qtype = $this->qtypes[$type];
-        }
-        else {
+        } else {
             $question->qtype = null;
         }
         $question->single = 1;
-        // Only one answer is allowed
+        // Only one answer is allowed.
         $htmltext = $this->unxmlise($qrec['#']['text'][0]['#']);
         $question->questiontext = $htmltext;
         $question->questiontextformat = FORMAT_HTML;
@@ -224,38 +217,35 @@ class qformat_examview extends qformat_default {
         $question->name = shorten_text( $question->questiontext, 250 );
 
         switch ($question->qtype) {
-        case MULTICHOICE:
-            $question = $this->parse_mc($qrec['#'], $question);
-            break;
-        case MATCH:
-            $groupname = trim($qrec['@']['group']);
-            $question = $this->parse_ma($qrec['#'], $groupname);
-            break;
-        case TRUEFALSE:
-            $question = $this->parse_tf_yn($qrec['#'], $question);
-            break;
-        case SHORTANSWER:
-            $question = $this->parse_co($qrec['#'], $question);
-            break;
-        case ESSAY:
-            $question = $this->parse_sa($qrec['#'], $question);
-            break;
-        case NUMERICAL:
-            $question = $this->parse_nr($qrec['#'], $question);
-            break;
-            break;
+            case MULTICHOICE:
+                $question = $this->parse_mc($qrec['#'], $question);
+                break;
+            case MATCH:
+                $groupname = trim($qrec['@']['group']);
+                $question = $this->parse_ma($qrec['#'], $groupname);
+                break;
+            case TRUEFALSE:
+                $question = $this->parse_tf_yn($qrec['#'], $question);
+                break;
+            case SHORTANSWER:
+                $question = $this->parse_co($qrec['#'], $question);
+                break;
+            case ESSAY:
+                $question = $this->parse_sa($qrec['#'], $question);
+                break;
+            case NUMERICAL:
+                $question = $this->parse_nr($qrec['#'], $question);
+                break;
+                break;
             default:
-            print("<p>Question type ".$type." import not supported for ".$question->questiontext."<p>");
-            $question = NULL;
+                print("<p>Question type ".$type." import not supported for ".$question->questiontext."<p>");
+                $question = null;
         }
-        // end switch ($question->qtype)
 
         return $question;
     }
-    // end readquestion
 
-    function parse_tf_yn($qrec, $question)
-    {
+    protected function parse_tf_yn($qrec, $question) {
         $choices = array('T' => 1, 'Y' => 1, 'F' => 0, 'N' => 0 );
         $answer = trim($qrec['answer'][0]['#']);
         $question->answer = $choices[$answer];
@@ -270,14 +260,13 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    function parse_mc($qrec, $question)
-    {
+    protected function parse_mc($qrec, $question) {
         $question = $this->add_blank_combined_feedback($question);
         $answer = 'choice-'.strtolower(trim($qrec['answer'][0]['#']));
 
         $choices = $qrec['choices'][0]['#'];
-        foreach($choices as $key => $value) {
-            if (strpos(trim($key),'choice-') !== FALSE) {
+        foreach ($choices as $key => $value) {
+            if (strpos(trim($key), 'choice-') !== false) {
 
                 $question->answer[$key] = $this->text_field(s($this->unxmlise($value[0]['#'])));
                 if (strcmp($key, $answer) == 0) {
@@ -292,14 +281,13 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    function parse_co($qrec, $question)
-    {
+    protected function parse_co($qrec, $question) {
         $question->usecase = 0;
         $answer = trim($this->unxmlise($qrec['answer'][0]['#']));
         $answer = strip_tags( $answer );
-        $answers = explode("\n",$answer);
+        $answers = explode("\n", $answer);
 
-        foreach($answers as $key => $value) {
+        foreach ($answers as $key => $value) {
             $value = trim($value);
             if (strlen($value) > 0) {
                 $question->answer[$key] = $value;
@@ -310,20 +298,19 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    function parse_sa($qrec, $question) {
+    protected function parse_sa($qrec, $question) {
         $feedback = trim($this->unxmlise($qrec['answer'][0]['#']));
         $question->feedback = $feedback;
         $question->fraction = 0;
         return $question;
     }
 
-    function parse_nr($qrec, $question)
-    {
+    protected function parse_nr($qrec, $question) {
         $answer = trim($this->unxmlise($qrec['answer'][0]['#']));
         $answer = strip_tags( $answer );
-        $answers = explode("\n",$answer);
+        $answers = explode("\n", $answer);
 
-        foreach($answers as $key => $value) {
+        foreach ($answers as $key => $value) {
             $value = trim($value);
             if (is_numeric($value)) {
                 $errormargin = 0;
@@ -338,6 +325,6 @@ class qformat_examview extends qformat_default {
     }
 
 }
-// end class
+// End class.
 
 
-- 
1.7.9.5


From e3f79e93474bfbb98b51e2b8933ed3632e905f67 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Fri, 27 Jul 2012 12:11:41 +0100
Subject: [PATCH 277/903] MDL-34483 qformat_examview: handle more questions.

These fixes come from testing with the example file supplied by Rick
Jerz.
---
 question/format/examview/format.php |   21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index f9e1975..f1acd34 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -46,10 +46,10 @@ class qformat_examview extends qformat_default {
         'mtf' => 99,
         'nr' => NUMERICAL,
         'pr' => 99,
-        'es' => 99,
+        'es' => ESSAY,
         'ca' => 99,
         'ot' => 99,
-        'sa' => ESSAY
+        'sa' => SHORTANSWER
         );
 
     public $matching_questions = array();
@@ -113,7 +113,7 @@ class qformat_examview extends qformat_default {
             return;
         }
         foreach ($matching_groups as $match_group) {
-            $newgroup = null;
+            $newgroup = new stdClass();
             $groupname = trim($match_group['@']['name']);
             $questiontext = $this->unxmlise($match_group['#']['text'][0]['#']);
             $newgroup->questiontext = trim($questiontext);
@@ -136,7 +136,7 @@ class qformat_examview extends qformat_default {
         $phrase = trim($this->unxmlise($qrec['text']['0']['#']));
         $answer = trim($this->unxmlise($qrec['answer']['0']['#']));
         $answer = strip_tags( $answer );
-        $match_group->subquestions[] = $this->text_field($phrase);
+        $match_group->subquestions[] = $phrase;
         $match_group->subanswers[] = $match_group->subchoices[$answer];
         $this->matching_questions[$groupname] = $match_group;
         return null;
@@ -159,7 +159,7 @@ class qformat_examview extends qformat_default {
             $question->subanswers = array();
             foreach ($match_group->subquestions as $key => $value) {
                 $htmltext = s($value);
-                $question->subquestions[] = $htmltext;
+                $question->subquestions[] = $this->text_field($htmltext);
 
                 $htmltext = s($match_group->subanswers[$key]);
                 $question->subanswers[] = $htmltext;
@@ -231,7 +231,7 @@ class qformat_examview extends qformat_default {
                 $question = $this->parse_co($qrec['#'], $question);
                 break;
             case ESSAY:
-                $question = $this->parse_sa($qrec['#'], $question);
+                $question = $this->parse_es($qrec['#'], $question);
                 break;
             case NUMERICAL:
                 $question = $this->parse_nr($qrec['#'], $question);
@@ -298,9 +298,13 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    protected function parse_sa($qrec, $question) {
+    protected function parse_es($qrec, $question) {
         $feedback = trim($this->unxmlise($qrec['answer'][0]['#']));
+        $question->graderinfo =  $this->text_field($feedback);
         $question->feedback = $feedback;
+        $question->responseformat = 'editor';
+        $question->responsefieldlines = 15;
+        $question->attachments = 0;
         $question->fraction = 0;
         return $question;
     }
@@ -317,8 +321,7 @@ class qformat_examview extends qformat_default {
                 $question->answer[$key] = $value;
                 $question->fraction[$key] = 1;
                 $question->feedback[$key] = $this->text_field("Correct");
-                $question->min[$key] = $question->answer[$key] - $errormargin;
-                $question->max[$key] = $question->answer[$key] + $errormargin;
+                $question->tolerance[$key] = $errormargin;
             }
         }
         return $question;
-- 
1.7.9.5


From de53bada572d9a75d9a193889db956e975b90661 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 27 Jul 2012 16:38:14 +0100
Subject: [PATCH 278/903] MDL-32791 quiz db: clean up garbage data that was
 causing problems.

Melinda Kraft reported having rows in their quiz_question_instances
table which caused various problems. These rows are meaningless, so I
have done a DB upgrade step to clean them up, which should deal with the
bad side-effets they were causing.
---
 mod/quiz/db/upgrade.php |   10 ++++++++++
 mod/quiz/version.php    |    2 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/db/upgrade.php b/mod/quiz/db/upgrade.php
index b0a4a4f..3bbbb6d 100644
--- a/mod/quiz/db/upgrade.php
+++ b/mod/quiz/db/upgrade.php
@@ -330,6 +330,16 @@ function xmldb_quiz_upgrade($oldversion) {
     // Moodle v2.3.0 release upgrade line
     // Put any upgrade step following this
 
+    if ($oldversion < 2012061702) {
+
+        // MDL-32791 somebody reported having nonsense rows in their
+        // quiz_question_instances which caused various problems. These rows
+        // are meaningless, hence this upgrade step to clean them up.
+        $DB->delete_records('quiz_question_instances', array('question' => 0));
+
+        // Quiz savepoint reached.
+        upgrade_mod_savepoint(true, 2012061702, 'quiz');
+    }
 
     return true;
 }
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index 03f42f1..67ca371 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX).
+$module->version   = 2012061702;       // The current module version (Date: YYYYMMDDXX).
 $module->requires  = 2012061700;    // Requires this Moodle version.
 $module->component = 'mod_quiz';       // Full name of the plugin (used for diagnostics).
 $module->cron      = 60;
-- 
1.7.9.5


From f2fd3f3138a0633ae653e3ff24cfc12697469fa4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 27 Jul 2012 18:42:18 +0200
Subject: [PATCH 279/903] MDL-34538 add float validation tests

---
 lib/tests/moodlelib_test.php |   50 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 5ce3a2c..2d03ffc 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -912,6 +912,56 @@ class moodlelib_testcase extends advanced_testcase {
         } catch (invalid_parameter_exception $ex) {
             $this->assertTrue(true);
         }
+        try {
+            $param = validate_param('1.0', PARAM_FLOAT);
+            $this->assertSame(1.0, $param);
+
+            // Make sure valid floats do not cause exception.
+            validate_param(1.0, PARAM_FLOAT);
+            validate_param(10, PARAM_FLOAT);
+            validate_param('0', PARAM_FLOAT);
+            validate_param('119813454.545464564564546564545646556564465465456465465465645645465645645645', PARAM_FLOAT);
+            validate_param('011.1', PARAM_FLOAT);
+            validate_param('11', PARAM_FLOAT);
+            validate_param('+.1', PARAM_FLOAT);
+            validate_param('-.1', PARAM_FLOAT);
+            validate_param('1e10', PARAM_FLOAT);
+            validate_param('.1e+10', PARAM_FLOAT);
+            validate_param('1E-1', PARAM_FLOAT);
+            $this->assertTrue(true);
+        } catch (invalid_parameter_exception $ex) {
+            $this->fail('Valid float notation not accepted');
+        }
+        try {
+            $param = validate_param('1,2', PARAM_FLOAT);
+            $this->fail('invalid_parameter_exception expected');
+        } catch (invalid_parameter_exception $ex) {
+            $this->assertTrue(true);
+        }
+        try {
+            $param = validate_param('', PARAM_FLOAT);
+            $this->fail('invalid_parameter_exception expected');
+        } catch (invalid_parameter_exception $ex) {
+            $this->assertTrue(true);
+        }
+        try {
+            $param = validate_param('.', PARAM_FLOAT);
+            $this->fail('invalid_parameter_exception expected');
+        } catch (invalid_parameter_exception $ex) {
+            $this->assertTrue(true);
+        }
+        try {
+            $param = validate_param('e10', PARAM_FLOAT);
+            $this->fail('invalid_parameter_exception expected');
+        } catch (invalid_parameter_exception $ex) {
+            $this->assertTrue(true);
+        }
+        try {
+            $param = validate_param('abc', PARAM_FLOAT);
+            $this->fail('invalid_parameter_exception expected');
+        } catch (invalid_parameter_exception $ex) {
+            $this->assertTrue(true);
+        }
     }
 
     function test_shorten_text() {
-- 
1.7.9.5


From 009933e28c1a6cd82c3feca61d35e4f9a07f6111 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 27 Jul 2012 18:44:41 +0200
Subject: [PATCH 280/903] MDL-34538 fix PARAM_FLOAT validation

---
 lib/moodlelib.php |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index b5b82c8..6591795 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -661,7 +661,8 @@ function optional_param_array($parname, $default, $type) {
  * @param string $type PARAM_ constant
  * @param bool $allownull are nulls valid value?
  * @param string $debuginfo optional debug information
- * @return mixed the $param value converted to PHP type or invalid_parameter_exception
+ * @return mixed the $param value converted to PHP type
+ * @throws invalid_parameter_exception if $param is not of given type
  */
 function validate_param($param, $type, $allownull=NULL_NOT_ALLOWED, $debuginfo='') {
     if (is_null($param)) {
@@ -676,7 +677,15 @@ function validate_param($param, $type, $allownull=NULL_NOT_ALLOWED, $debuginfo='
     }
 
     $cleaned = clean_param($param, $type);
-    if ((string)$param !== (string)$cleaned) {
+
+    if ($type == PARAM_FLOAT) {
+        // Do not detect precision loss here.
+        if (is_float($param) or is_int($param)) {
+            // These always fit.
+        } else if (!is_numeric($param) or !preg_match('/^[\+-]?[0-9]*\.?[0-9]*(e[-+]?[0-9]+)?$/i', (string)$param)) {
+            throw new invalid_parameter_exception($debuginfo);
+        }
+    } else if ((string)$param !== (string)$cleaned) {
         // conversion to string is usually lossless
         throw new invalid_parameter_exception($debuginfo);
     }
-- 
1.7.9.5


From d1d989ce13fd261fbf356af28ede89808d16c7df Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 27 Jul 2012 18:06:24 +0100
Subject: [PATCH 281/903] MDL-31509 quiz outcomes: let people associate
 quizzes with outcomes.

The quiz does not really support outcomes, but even so in 1.9 you could
select outcomes on the quiz edit form, and apparently this was useful to
some people, therefore we should re-enable it.
---
 mod/quiz/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 6e28cbf..397869d 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1556,7 +1556,7 @@ function quiz_supports($feature) {
         case FEATURE_MOD_INTRO:                 return true;
         case FEATURE_COMPLETION_TRACKS_VIEWS:   return true;
         case FEATURE_GRADE_HAS_GRADE:           return true;
-        case FEATURE_GRADE_OUTCOMES:            return false;
+        case FEATURE_GRADE_OUTCOMES:            return true;
         case FEATURE_BACKUP_MOODLE2:            return true;
         case FEATURE_SHOW_DESCRIPTION:          return true;
         case FEATURE_CONTROLS_GRADE_VISIBILITY: return true;
-- 
1.7.9.5


From 0e3c86746f74bac47cbf74ea0072a085667dd549 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 29 Jul 2012 14:54:00 +0100
Subject: [PATCH 282/903] MDL-34624 theme_base: added background-color to
 style/admin.css for role edit default

---
 theme/base/style/admin.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/theme/base/style/admin.css b/theme/base/style/admin.css
index 049a2a8..8c0ce47 100644
--- a/theme/base/style/admin.css
+++ b/theme/base/style/admin.css
@@ -68,6 +68,7 @@
 .path-admin-roles .capabilitysearchui {text-align: left;margin-left: auto;margin-right: auto;}
 #page-admin-roles-define .topfields {margin: 1em 0 2em;}
 #page-admin-roles-define .mform {width: 100%;}
+#page-admin-roles-define .capdefault {background-color: #eee; border: 1px solid #cecece;}
 #page-filter-manage .backlink,
 .path-admin-roles .backlink {margin-top: 1em}
 #page-admin-roles-explain #chooseuser h3,
-- 
1.7.9.5


From 899fe648676dbe2fdd943bfd0eb47f5490e06b8b Mon Sep 17 00:00:00 2001
From: kordan <kordan@mclink.it>
Date: Sun, 29 Jul 2012 15:59:54 +0200
Subject: [PATCH 283/903] MDL-34405 theme_formal_white: added background for
 quiz overview

---
 theme/formal_white/style/pagelayout.css |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/formal_white/style/pagelayout.css b/theme/formal_white/style/pagelayout.css
index 1a19546..38cf98b 100644
--- a/theme/formal_white/style/pagelayout.css
+++ b/theme/formal_white/style/pagelayout.css
@@ -113,7 +113,7 @@
     .has_dock.side-post-only .page-middle #region-main {margin-left:[[setting:blockcolumnwidth]];}
 
 /** Report layout **/
-    .pagelayout-report #report-main-content .region-content {margin-left:[[setting:blockcolumnwidth]];}
+    .pagelayout-report #report-main-content .region-content {background-color:white;margin-left:[[setting:blockcolumnwidth]];}
     .pagelayout-report #report-region-pre {width:[[setting:blockcolumnwidth]];}
 
 /** Correct for right to left languages **/
-- 
1.7.9.5


From dacc63f1ae9c52084101d4d92fd8b71d8ce89065 Mon Sep 17 00:00:00 2001
From: kordan <kordan@mclink.it>
Date: Sun, 29 Jul 2012 16:40:29 +0200
Subject: [PATCH 284/903] MDL-34494 theme_formal_white: replaced old style
 core_renderer::MAIN_CONTENT_TOKEN with
 $OUTPUT->main_content()

---
 theme/formal_white/layout/report.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/formal_white/layout/report.php b/theme/formal_white/layout/report.php
index 9bb7ca1..1c49f65 100644
--- a/theme/formal_white/layout/report.php
+++ b/theme/formal_white/layout/report.php
@@ -102,7 +102,7 @@ echo $OUTPUT->doctype() ?>
                                 <!-- main mandatory content of the moodle page  -->
                                 <div id="report-main-content">
                                     <div class="region-content">
-                                        <?php echo core_renderer::MAIN_CONTENT_TOKEN ?>
+                                        <?php echo $OUTPUT->main_content() ?>
                                     </div>
                                 </div>
                                 <!-- end of main mandatory content of the moodle page -->
-- 
1.7.9.5


From f785edd9e257f122fdf8a215e86afc26061cb832 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 29 Jul 2012 21:42:04 +0100
Subject: [PATCH 285/903] MDL-34528 theme_canvas: Removed redundent exclude
 stylesheet configurations from CANVAS theme

---
 theme/canvas/config.php |   18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/theme/canvas/config.php b/theme/canvas/config.php
index 925a72b..2a043b2 100644
--- a/theme/canvas/config.php
+++ b/theme/canvas/config.php
@@ -40,9 +40,7 @@ $THEME->name = 'canvas';
 // the directory in which this file resides.
 ////////////////////////////////////////////////////
 
-$THEME->parents = array(
-    'base',
-);
+$THEME->parents = array('base');
 
 /////////////////////////////////////////////////////
 // Which existing theme(s) in the /theme/ directory
@@ -73,12 +71,7 @@ $THEME->sheets = array(
 // this theme's /styles/ directory.
 ////////////////////////////////////////////////////
 
-$THEME->parents_exclude_sheets = array(
-    'base'=>array(
-        'navigation',
-        'browser',
-    ),
-);
+$THEME->parents_exclude_sheets = array();
 
 ////////////////////////////////////////////////////
 // An array of stylesheets not to inherit from the
@@ -194,16 +187,13 @@ $THEME->hidefromselector = true;
 // switched on.
 /////////////////////////////////////////////////////
 
-
-
 // $THEME->enable_dock = false;
 
 ////////////////////////////////////////////////////
 // Do you want to use the new navigation dock?
 ////////////////////////////////////////////////////
 
-
-// $THEME->editor_sheets
+$THEME->editor_sheets = array('editor');
 
 ////////////////////////////////////////////////////
 // An array of stylesheets to include within the
@@ -265,5 +255,3 @@ $THEME->hidefromselector = true;
 // Sets a custom render factory to use with the
 // theme, used when working with custom renderers.
 ////////////////////////////////////////////////////
-
-$THEME->editor_sheets = array('editor');
\ No newline at end of file
-- 
1.7.9.5


From ca4548c1c2c178935fe5e9c7e737b8473319889d Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Mon, 23 Jul 2012 15:28:26 +0100
Subject: [PATCH 286/903] MDL-34433 Check for existence of e and e.target in
 set_form_changed

This is required for cases when code directly calls set_form_changed as
happens with the filepicker.
---
 lib/yui/formchangechecker/formchangechecker.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/yui/formchangechecker/formchangechecker.js b/lib/yui/formchangechecker/formchangechecker.js
index 5c46983..ea5164d 100644
--- a/lib/yui/formchangechecker/formchangechecker.js
+++ b/lib/yui/formchangechecker/formchangechecker.js
@@ -93,7 +93,7 @@ YUI.add('moodle-core-formchangechecker',
          * Set the form changed state to true
          */
         M.core_formchangechecker.set_form_changed = function(e) {
-            if (e.target.hasClass('ignoredirty')) {
+            if (e && e.target && e.target.hasClass('ignoredirty')) {
                 // Don't warn on elements with the ignoredirty class
                 return;
             }
-- 
1.7.9.5


From db8e600a2304744541f03b09cb5125bce6cf4c78 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Tue, 24 Jul 2012 12:53:43 +0300
Subject: [PATCH 287/903] MDL-34513 - RTL Theme fixes for Moodle 2
 (theme/mymobile) + Right align frontpage course
 list + right align activity and resource titles +
 Two Columns on/off slider fix + Right align content
 in Blocks + Fix checkbox question types in quiz +
 Right align titles of fields in Forms + minor ui
 tweaks

---
 theme/mymobile/config.php              |    1 +
 theme/mymobile/style/jmobile11_rtl.css |   54 ++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 theme/mymobile/style/jmobile11_rtl.css

diff --git a/theme/mymobile/config.php b/theme/mymobile/config.php
index 2e05c99..544c792 100644
--- a/theme/mymobile/config.php
+++ b/theme/mymobile/config.php
@@ -35,6 +35,7 @@ $THEME->parents = array(
 // Set the stylesheets that we want to include for this theme
 $THEME->sheets = array(
     'jmobile11',
+    'jmobile11_rtl',
     'core',
     'media'
 );
diff --git a/theme/mymobile/style/jmobile11_rtl.css b/theme/mymobile/style/jmobile11_rtl.css
new file mode 100644
index 0000000..7d2ba26
--- /dev/null
+++ b/theme/mymobile/style/jmobile11_rtl.css
@@ -0,0 +1,54 @@
+.dir-rtl .ui-collapsible-heading a {text-align: right}
+
+.dir-rtl .ui-li, .ui-li.ui-field-contain {text-align: right;}
+
+.dir-rtl .ui-li-thumb, .dir-rtl .ui-listview .ui-li-icon, .dir-rtl .ui-li-content {
+    float: right;
+    margin-left: 27px;
+}
+.dir-rtl .ui-li, .dir-rtl .ui-li.ui-field-contain {
+    text-align: right;
+}
+.dir-rtl .ui-listview .ui-li-icon {right:27px; left:auto;}
+
+.dir-rtl .mod-indent-1 { margin-right: 0px;}
+
+.dir-rtl .ui-icon-arrow-r {
+    background-position: -108px 0%;
+}
+
+.dir-rtl .ui-field-contain div.ui-slider-switch {
+    width: 10.5em;
+}
+
+.dir-rtl .coursebox h3 a .ui-btn-inner, .dir-rtl .category a .ui-btn-inner {
+    padding-right: .8em;
+    padding-left: 8px;
+}
+
+.dir-rtl .mform .fitem .felement {
+    margin-right: auto;
+    margin-left: 16%;
+    text-align: right;
+}
+
+.dir-rtl .has-myblocks .content-secondary {
+    text-align: right;
+}
+
+.dir-rtl .forumheaderlist thead .ui-btn-inner, .dir-rtl .topic .ui-btn {
+    text-align: right !important;
+    padding-right: 7px;
+}
+
+.dir-rtl .ui-li-count { left:38px; right:auto;}
+
+.dir-rtl .ui-checkbox .ui-btn, .dir-rtl .ui-radio .ui-btn {
+    text-align: right;
+}
+
+.dir-rtl .mform .fitemtitle { text-align: right !important; }
+
+.path-mod-quiz.dir-rtl .que .control {
+    width: 75%;
+}
\ No newline at end of file
-- 
1.7.9.5


From 7ae8f60489502754dd59f25959e7a437d45507c4 Mon Sep 17 00:00:00 2001
From: Fred Woolard <woolardfa@appstate.edu>
Date: Mon, 30 Jul 2012 20:04:55 +1200
Subject: [PATCH 288/903] MDL-34440 Site registration failing with mysqli

---
 course/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index 36ef842..09559fd 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -4039,7 +4039,7 @@ function average_number_of_participants() {
         WHERE ue.enrolid = e.id
             AND e.courseid <> :siteid
             AND c.id = e.courseid
-            AND c.visible = 1)';
+            AND c.visible = 1) total';
     $params = array('siteid' => $SITE->id);
     $enrolmenttotal = $DB->count_records_sql($sql, $params);
 
@@ -4072,7 +4072,7 @@ function average_number_of_courses_modules() {
         WHERE c.id = cm.course
             AND c.id <> :siteid
             AND cm.visible = 1
-            AND c.visible = 1)';
+            AND c.visible = 1) total';
     $params = array('siteid' => $SITE->id);
     $moduletotal = $DB->count_records_sql($sql, $params);
 
-- 
1.7.9.5


From 0b7dfe12ed0820e79456be0d174bac78c7757ef7 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 27 Jul 2012 12:18:10 +0100
Subject: [PATCH 289/903] MDL-34483 qformat_examview: Commit example file.

Supplied by Rick Jerz.
---
 .../examview/tests/fixtures/questions.examview.xml |  164 ++++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100644 question/format/examview/tests/fixtures/questions.examview.xml

diff --git a/question/format/examview/tests/fixtures/questions.examview.xml b/question/format/examview/tests/fixtures/questions.examview.xml
new file mode 100644
index 0000000..5abeccd
--- /dev/null
+++ b/question/format/examview/tests/fixtures/questions.examview.xml
@@ -0,0 +1,164 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<examview type='test' platform='Windows' app-version='4.0.2'>
+    <header>
+        <title>Moodle Example</title>
+        <version>A</version>
+    </header>
+    <font-table>
+        <font-entry number='1'>
+            <charset>ansi</charset>
+            <name>Times New Roman</name>
+            <pitch>variable</pitch>
+            <family>roman</family>
+        </font-entry>
+    </font-table>
+    <preferences>
+        <show>
+            <show-answer value='yes'/>
+            <show-difficulty value='yes'/>
+            <show-reference value='yes'/>
+            <show-text-objective value='yes'/>
+            <show-state-objective value='yes'/>
+            <show-topic value='yes'/>
+            <show-keywords value='yes'/>
+            <show-misc value='yes'/>
+            <show-notes value='yes'/>
+            <show-rationale value='yes'/>
+        </show>
+        <leave-answer-space>
+            <tf value='yes'/>
+            <mtf value='yes'/>
+            <mc value='yes'/>
+            <yn value='yes'/>
+            <nr value='no'/>
+            <co value='no'/>
+            <ma value='yes'/>
+            <sa value='no'/>
+            <pr value='no'/>
+            <es value='no'/>
+            <ca value='no'/>
+            <ot value='no'/>
+        </leave-answer-space>
+        <question-type-order value='tf,mtf,mc,yn,nr,co,ma,sa,pr,es,ca,ot'/>
+        <section-page-break value='no'/>
+        <bi-display-mode value='mc'/>
+        <tf-show-choices value='no'/>
+        <mc-conserve-paper value='no'/>
+        <mc-choice-sequence value='abcde'/>
+        <show-answer-lines value='no'/>
+        <question-numbering value='continuous'/>
+        <answer-style template='a.' style='none'/>
+        <number-style template='1.' style='none'/>
+        <max-question-id value='9'/>
+        <max-narrative-id value='0'/>
+        <max-group-id value='1'/>
+        <default-font target='title'>
+            <number>1</number>
+            <size>13</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='sectiontitle'>
+            <number>1</number>
+            <size>11</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='questionnumber'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='answerchoice'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='newquestiondefault'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+    </preferences>
+    <test-header page='first'><para tabs='R10440'><b>Name: ________________________  Class: ___________________  Date: __________    ID: <field field-type='version'/></b></para></test-header>
+    <test-header page='subsequent'><para tabs='R10440'><b>Name: ________________________    ID: <field field-type='version'/></b></para></test-header>
+    <test-footer page='first'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <test-footer page='subsequent'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <instruction type='tf'><b>True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.</i></instruction>
+    <instruction type='mtf'><b>Modified True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.  If false, change the identified word or phrase to make the sentence or statement true.</i></instruction>
+    <instruction type='mc'><b>Multiple Choice</b><font size='10'>
+</font><i>Identify the letter of the choice that best completes the statement or answers the question.</i></instruction>
+    <instruction type='yn'><b>Yes/No</b><font size='10'>
+</font><i>Indicate whether you agree with the sentence or statement.</i></instruction>
+    <instruction type='nr'><b>Numeric Response</b></instruction>
+    <instruction type='co'><b>Completion</b><font size='10'>
+</font><i>Complete each sentence or statement.</i></instruction>
+    <instruction type='ma'><b>Matching</b></instruction>
+    <instruction type='sa'><b>Short Answer</b></instruction>
+    <instruction type='pr'><b>Problem</b></instruction>
+    <instruction type='es'><b>Essay</b></instruction>
+    <instruction type='ca'><b>Case</b></instruction>
+    <instruction type='ot'><b>Other</b></instruction>
+    <question type='tf' question-id='1' bank-id='0'>
+        <text>This is a T/F question.  Tim and Jean-Michael are great people.</text>
+        <rationale>Examview allows for this &#x201c;Rationale&#x201d; field</rationale>
+        <answer>T</answer>
+    </question>
+    <question type='mc' question-id='2' bank-id='0'>
+        <text>This is an example of a multiple choice question.  This is only an ________</text>
+        <choices columns='2'>
+            <choice-a>example</choice-a>
+            <choice-b>the real thing</choice-b>
+            <choice-c>a true false question</choice-c>
+            <choice-d>none of these</choice-d>
+        </choices>
+        <answer>A</answer>
+    </question>
+    <question type='nr' question-id='3' bank-id='0'>
+        <text>This is a numeric response question.  How much is 12 * 2?</text>
+        <answer>24</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <matching-group group-id='1' bank-id='0' name='Matching 1'>
+        <text>This is a matching question type.
+</text>
+        <choices columns='2'>
+            <choice-a>Question 1</choice-a>
+            <choice-b>Question 2</choice-b>
+            <choice-c>Question 3</choice-c>
+            <choice-d>Question 4</choice-d>
+        </choices>
+    </matching-group>
+    <question type='ma' question-id='6' bank-id='0' group='Matching 1'>
+        <text>This is question 1.</text>
+        <answer>A</answer>
+    </question>
+    <question type='ma' question-id='7' bank-id='0' group='Matching 1'>
+        <text>This is question 2.</text>
+        <answer>B</answer>
+    </question>
+    <question type='ma' question-id='8' bank-id='0' group='Matching 1'>
+        <text>This is question 3.</text>
+        <answer>C</answer>
+    </question>
+    <question type='sa' question-id='5' bank-id='0'>
+        <text>This is a short answer question.  This is a ___________ answer question.</text>
+        <answer>short</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <question type='es' question-id='4' bank-id='0'>
+        <text>This is an essay question.  I am not sure if an answer is needed.</text>
+        <answer>This is the answer in Examview.  I am curious to see how this shows in Moodle.</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+</examview>
-- 
1.7.9.5


From 10813a0c78cdd9f7f5ac3188101763e5c21d512f Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Tue, 31 Jul 2012 10:44:48 +0930
Subject: [PATCH 290/903] MDL-34645: enrol_manual: enrolment init to pass
 default duration setting

---
 enrol/manual/lib.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/enrol/manual/lib.php b/enrol/manual/lib.php
index 9c3a5d6..e9eac64 100644
--- a/enrol/manual/lib.php
+++ b/enrol/manual/lib.php
@@ -215,6 +215,7 @@ class enrol_manual_plugin extends enrol_plugin {
         $today = time();
         $today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
         $startdateoptions[3] = get_string('today') . ' (' . userdate($today, $timeformat) . ')' ;
+        $defaultduration = $instance->enrolperiod > 0 ? $instance->enrolperiod / 86400 : '';
 
         $modules = array('moodle-enrol_manual-quickenrolment', 'moodle-enrol_manual-quickenrolment-skin');
         $arguments = array(
@@ -224,6 +225,7 @@ class enrol_manual_plugin extends enrol_plugin {
             'url'                 => $manager->get_moodlepage()->url->out(false),
             'optionsStartDate'    => $startdateoptions,
             'defaultRole'         => $instance->roleid,
+            'defaultDuration'     => $defaultduration,
             'disableGradeHistory' => $CFG->disablegradehistory,
             'recoverGradesDefault'=> ''
         );
-- 
1.7.9.5


From 5aba3d6df98e4274e7a424e2186d4116d13ff52c Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Sat, 28 Jul 2012 14:10:54 +0930
Subject: [PATCH 291/903] MDL-34647: admintool: uploaduser enrolments now obey
 enrolperiod directive

---
 admin/tool/uploaduser/index.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/admin/tool/uploaduser/index.php b/admin/tool/uploaduser/index.php
index ec692e2..380db45 100644
--- a/admin/tool/uploaduser/index.php
+++ b/admin/tool/uploaduser/index.php
@@ -857,6 +857,8 @@ if ($formdata = $mform2->is_cancelled()) {
                         if ($duration > 0) { // sanity check
                             $timeend = $today + $duration;
                         }
+                    } else if ($manualcache[$courseid]->enrolperiod > 0) {
+                        $timeend = $today + $manualcache[$courseid]->enrolperiod;
                     }
 
                     $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend);
-- 
1.7.9.5


From 2a3a22a46d6c728f1b76d03ec06d45e75cfe462a Mon Sep 17 00:00:00 2001
From: Crafton Williams <craftonjr@gmail.com>
Date: Thu, 21 Jun 2012 12:59:21 -0500
Subject: [PATCH 292/903] MDL-33869 user_get_user_details: allow return of
 idnumber

---
 enrol/externallib.php |    1 +
 user/externallib.php  |    1 +
 user/lib.php          |    5 ++++-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/enrol/externallib.php b/enrol/externallib.php
index 147383c..7d2fb5a 100644
--- a/enrol/externallib.php
+++ b/enrol/externallib.php
@@ -273,6 +273,7 @@ class core_enrol_external extends external_api {
                     'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
                     'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
                     'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
+                    'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
                     'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
diff --git a/user/externallib.php b/user/externallib.php
index c1d57bc..9586369 100644
--- a/user/externallib.php
+++ b/user/externallib.php
@@ -614,6 +614,7 @@ class core_user_external extends external_api {
                     'msn'         => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
                     'department'  => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
                     'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
+                    'idnumber'    => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
                     'interests'   => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
diff --git a/user/lib.php b/user/lib.php
index bfa5476..a8086ed 100644
--- a/user/lib.php
+++ b/user/lib.php
@@ -395,8 +395,11 @@ function user_get_user_details($user, $course = null, array $userfields = array(
         }
     }
 
-    //Departement/Institution are not displayed on any profile, however you can get them from editing profile.
+    //Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
     if ($isadmin or $currentuser) {
+    if (in_array('idnumber', $userfields) && $user->idnumber) {
+            $userdetails['idnumber'] = $user->idnumber;
+        }
         if (in_array('institution', $userfields) && $user->institution) {
             $userdetails['institution'] = $user->institution;
         }
-- 
1.7.9.5


From 1b158ee8c9185890c744f94cd230f2d37f891435 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Fri, 22 Jun 2012 16:48:51 +0800
Subject: [PATCH 293/903] MDL-33869 user_get_user_details: add support for
 'Show user identity' fields set by administrator

---
 user/lib.php |   26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/user/lib.php b/user/lib.php
index a8086ed..0da89c7 100644
--- a/user/lib.php
+++ b/user/lib.php
@@ -227,6 +227,8 @@ function user_get_user_details($user, $course = null, array $userfields = array(
     $currentuser = ($user->id == $USER->id);
     $isadmin = is_siteadmin($USER);
 
+    $showuseridentityfields = get_extra_user_fields($context);
+
     if (!empty($course)) {
         $canviewhiddenuserfields = has_capability('moodle/course:viewhiddenuserfields', $context);
     } else {
@@ -309,16 +311,19 @@ function user_get_user_details($user, $course = null, array $userfields = array(
         if ($user->address && in_array('address', $userfields)) {
             $userdetails['address'] = $user->address;
         }
-        if ($user->phone1 && in_array('phone1', $userfields)) {
-            $userdetails['phone1'] = $user->phone1;
-        }
-        if ($user->phone2 && in_array('phone2', $userfields)) {
-            $userdetails['phone2'] = $user->phone2;
-        }
     } else {
         $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
     }
 
+    if ($user->phone1 && in_array('phone1', $userfields) &&
+            (isset($showuseridentityfields['phone1']) or $canviewhiddenuserfields)) {
+        $userdetails['phone1'] = $user->phone1;
+    }
+    if ($user->phone2 && in_array('phone2', $userfields) &&
+            (isset($showuseridentityfields['phone2']) or $canviewhiddenuserfields)) {
+        $userdetails['phone2'] = $user->phone2;
+    }
+
     if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
         if (!$cannotviewdescription) {
 
@@ -383,6 +388,7 @@ function user_get_user_details($user, $course = null, array $userfields = array(
     if (in_array('email', $userfields) && ($isadmin // The admin is allowed the users email
       or $currentuser // Of course the current user is as well
       or $canviewuseremail  // this is a capability in course context, it will be false in usercontext
+      or isset($showuseridentityfields['email'])
       or $user->maildisplay == 1
       or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
         $userdetails['email'] = $user->email;
@@ -396,13 +402,17 @@ function user_get_user_details($user, $course = null, array $userfields = array(
     }
 
     //Departement/Institution/Idnumber are not displayed on any profile, however you can get them from editing profile.
-    if ($isadmin or $currentuser) {
-    if (in_array('idnumber', $userfields) && $user->idnumber) {
+    if ($isadmin or $currentuser or isset($showuseridentityfields['idnumber'])) {
+        if (in_array('idnumber', $userfields) && $user->idnumber) {
             $userdetails['idnumber'] = $user->idnumber;
         }
+    }
+    if ($isadmin or $currentuser or isset($showuseridentityfields['institution'])) {
         if (in_array('institution', $userfields) && $user->institution) {
             $userdetails['institution'] = $user->institution;
         }
+    }
+    if ($isadmin or $currentuser or isset($showuseridentityfields['department'])) {
         if (in_array('department', $userfields) && isset($user->department)) { //isset because it's ok to have department 0
             $userdetails['department'] = $user->department;
         }
-- 
1.7.9.5


From 669f274735da5530131bca36fda5e6b071cdc3ef Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 31 Jul 2012 11:24:15 +0800
Subject: [PATCH 294/903]  MDL-32827 calendar: update eventtype of broken
 event in bulk instead of doing it one by one

---
 lib/db/upgrade.php |   25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index a777170..c948d5f 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -924,22 +924,15 @@ function xmldb_main_upgrade($oldversion) {
     }
 
     if ($oldversion < 2012062501.06) {
-        $rs = $DB->get_recordset('event', array( 'eventtype' => ''), '', 'id, courseid, groupid, userid, modulename');
-        foreach ($rs as $event) {
-            if ($event->courseid == $SITE->id) {                                // Site event
-                $DB->set_field('event', 'eventtype', 'site', array('id' => $event->id));
-            } else if ($event->courseid != 0 && $event->groupid == 0 && ($event->modulename == 'assignment' || $event->modulename == 'assign')) {
-                // Course assingment event
-                $DB->set_field('event', 'eventtype', 'due', array('id' => $event->id));
-            } else if ($event->courseid != 0 && $event->groupid == 0) {      // Course event
-                $DB->set_field('event', 'eventtype', 'course', array('id' => $event->id));
-            } else if ($event->groupid) {                                      // Group event
-                $DB->set_field('event', 'eventtype', 'group', array('id' => $event->id));
-            } else if ($event->userid) {                                       // User event
-                $DB->set_field('event', 'eventtype', 'user', array('id' => $event->id));
-            }
-        }
-        $rs->close();
+
+        // Handle events with empty eventtype MDL-32827
+
+        $DB->set_field('event', 'eventtype', 'site', array('eventtype' => '', 'courseid' => $SITE->id));
+        $DB->set_field_select('event', 'eventtype', 'due', "eventtype = '' AND courseid != 0 AND groupid = 0 AND (modulename = 'assignment' OR modulename = 'assign')");
+        $DB->set_field_select('event', 'eventtype', 'course', "eventtype = '' AND courseid != 0 AND groupid = 0");
+        $DB->set_field_select('event', 'eventtype', 'group', "eventtype = '' AND groupid != 0");
+        $DB->set_field_select('event', 'eventtype', 'user', "eventtype = '' AND userid != 0");
+
         // Main savepoint reached
         upgrade_main_savepoint(true, 2012062501.06);
     }
-- 
1.7.9.5


From 2a336b5ef142af1b800b16ffb84c351e961655fa Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 31 Jul 2012 12:09:18 +0800
Subject: [PATCH 295/903] MDL-34650 - accessibility compliance: Add <label>
 for form input text and select tag

---
 lang/en/moodle.php       |   11 +++++++++++
 lang/en/table.php        |    1 +
 lib/form/editor.php      |    5 +++--
 lib/outputcomponents.php |   19 +++++++++++++++++--
 lib/outputrenderers.php  |    6 +++---
 lib/portfoliolib.php     |    3 ++-
 lib/questionlib.php      |    2 +-
 lib/tablelib.php         |    1 +
 8 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 1aae903..6cd608c 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -938,6 +938,7 @@ $string['liketologin'] = 'Would you like to log in now with a full user account?
 $string['list'] = 'List';
 $string['listfiles'] = 'List of files in {$a}';
 $string['listofallpeople'] = 'List of all people';
+$string['listofcourses'] = 'List of courses';
 $string['local'] = 'Local';
 $string['localplugindeleteconfirm'] = 'You are about to completely delete the local plugin \'{$a}\'. This will completely delete everything in the database associated with this plugin. Are you SURE you want to continue?';
 $string['localplugins'] = 'Local plugins';
@@ -1033,6 +1034,7 @@ $string['messageselectadd'] = 'Send a message';
 $string['migratinggrades'] = 'Migrating grades';
 $string['min'] = 'min';
 $string['mins'] = 'mins';
+$string['minute'] = 'minute';
 $string['minutes'] = 'minutes';
 $string['miscellaneous'] = 'Miscellaneous';
 $string['missingcategory'] = 'You need to choose a category';
@@ -1060,6 +1062,8 @@ $string['missingteacher'] = 'Must choose something';
 $string['missingurl'] = 'Missing URL';
 $string['missingusername'] = 'Missing username';
 $string['moddoesnotsupporttype'] = 'Module {$a->modname} does not support uploads of type {$a->type}';
+$string['month'] = 'Month';
+$string['months'] = 'Months';
 $string['modified'] = 'Modified';
 $string['modchooserenable'] = 'Activity chooser on';
 $string['modchooserdisable'] = 'Activity chooser off';
@@ -1248,6 +1252,7 @@ $string['oldpassword'] = 'Current password';
 $string['olduserdirectory'] = 'This is the OLD users directory, and is no longer needed. You may safely delete it. The files it contains have been copied to the NEW user directory.';
 $string['opentoguests'] = 'Guest access';
 $string['optional'] = 'optional';
+$string['options'] = 'options';
 $string['order'] = 'Order';
 $string['originalpath'] = 'Original path';
 $string['orphanedactivities'] = 'Orphaned activities';
@@ -1494,9 +1499,15 @@ $string['sectionusedefaultname'] = 'Use default section name';
 $string['seealsostats'] = 'See also: stats';
 $string['select'] = 'Select';
 $string['selectacountry'] = 'Select a country';
+$string['selectacourse'] = 'Select a course';
+$string['selectacoursesite'] = 'Select a course or site';
+$string['selectanaction'] = 'Select an action';
+$string['selectagroup'] = 'Select a group';
 $string['selectaregion'] = 'Select a region';
+$string['selctauser'] = 'Select a user';
 $string['selectall'] = 'Select all';
 $string['selectamodule'] = 'Please select an activity module';
+$string['selectanoptions'] = 'Select an options';
 $string['selectdefault'] = 'Select default';
 $string['selectedfile'] = 'Selected file';
 $string['selectednowmove'] = '{$a} files selected for moving. Now go into the destination folder and press \'Move files to here\'';
diff --git a/lang/en/table.php b/lang/en/table.php
index a4e9abd..c2bf463 100644
--- a/lang/en/table.php
+++ b/lang/en/table.php
@@ -27,5 +27,6 @@ $string['downloadas'] = 'Download table data as';
 $string['downloadcsv'] = 'a comma separated values text file';
 $string['downloadexcel'] = 'a Microsoft Excel spreadsheet';
 $string['downloadods'] = 'an OpenDocument Spreadsheet (ODS)';
+$string['downloadoptions'] = 'Select download options';
 $string['downloadtsv'] = 'a tab separated values text file';
 $string['downloadxhtml'] = 'an unpaged XHTML document';
diff --git a/lib/form/editor.php b/lib/form/editor.php
index 0f054a5..50d32ef 100644
--- a/lib/form/editor.php
+++ b/lib/form/editor.php
@@ -360,10 +360,11 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
 
         $str .= '<div>';
         if (count($formats)>1) {
-            $str.= html_writer::select($formats, $elname.'[format]', $format, false);
+            $str .= html_writer::label(get_string('format'), 'menu'. $elname. 'format', false, array('class' => 'accesshide'));
+            $str .= html_writer::select($formats, $elname.'[format]', $format, false, array('id' => 'menu'. $elname. 'format'));
         } else {
             $keys = array_keys($formats);
-            $str.= html_writer::empty_tag('input',
+            $str .= html_writer::empty_tag('input',
                     array('name'=>$elname.'[format]', 'type'=> 'hidden', 'value' => array_pop($keys)));
         }
         $str .= '</div>';
diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index 35edf3b..4370279 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -715,6 +715,11 @@ class single_select implements renderable {
     var $label = '';
 
     /**
+     * @var array Button label's
+     */
+    var $labelattributes = array();
+
+    /**
      * @var string Form submit method post or get
      */
     var $method = 'get';
@@ -806,9 +811,12 @@ class single_select implements renderable {
      * Sets select's label
      *
      * @param string $label
+     * @param array $attributes (optional)
      */
-    public function set_label($label) {
+    public function set_label($label, $attributes = array()) {
         $this->label = $label;
+        $this->labelattributes = $attributes;
+
     }
 }
 
@@ -851,6 +859,11 @@ class url_select implements renderable {
     var $label = '';
 
     /**
+     * @var array Button label's attributes
+     */
+    var $labelattributes = array();
+
+    /**
      * @var string Wrapping div class
      */
     var $class = 'urlselect';
@@ -922,9 +935,11 @@ class url_select implements renderable {
      * Sets select's label
      *
      * @param string $label
+     * @param array $attributes (optional)
      */
-    public function set_label($label) {
+    public function set_label($label, $attributes = array()) {
         $this->label = $label;
+        $this->labelattributes = $attributes;
     }
 }
 
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index e800b8f..717ad00 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1334,7 +1334,7 @@ class core_renderer extends renderer_base {
         }
 
         if ($select->label) {
-            $output .= html_writer::label($select->label, $select->attributes['id']);
+            $output .= html_writer::label($select->label, $select->attributes['id'], false, $select->labelattributes);
         }
 
         if ($select->helpicon instanceof help_icon) {
@@ -1342,7 +1342,6 @@ class core_renderer extends renderer_base {
         } else if ($select->helpicon instanceof old_help_icon) {
             $output .= $this->render($select->helpicon);
         }
-
         $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes);
 
         $go = html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('go')));
@@ -1412,7 +1411,7 @@ class core_renderer extends renderer_base {
         $output = '';
 
         if ($select->label) {
-            $output .= html_writer::label($select->label, $select->attributes['id']);
+            $output .= html_writer::label($select->label, $select->attributes['id'], false, $select->labelattributes);
         }
 
         if ($select->helpicon instanceof help_icon) {
@@ -1629,6 +1628,7 @@ class core_renderer extends renderer_base {
 
             $scalearray = array(RATING_UNSET_RATING => $strrate.'...') + $rating->settings->scale->scaleitems;
             $scaleattrs = array('class'=>'postratingmenu ratinginput','id'=>'menurating'.$rating->itemid);
+            $ratinghtml .= html_writer::label($rating->rating, 'menurating'.$rating->itemid, false, array('class' => 'accesshide'));
             $ratinghtml .= html_writer::select($scalearray, 'rating', $rating->rating, false, $scaleattrs);
 
             //output submit button
diff --git a/lib/portfoliolib.php b/lib/portfoliolib.php
index dc7473a..8405102 100644
--- a/lib/portfoliolib.php
+++ b/lib/portfoliolib.php
@@ -462,7 +462,8 @@ function portfolio_instance_select($instances, $callerformats, $callbackclass, $
     $pinsane = portfolio_plugin_sanity_check();
 
     $count = 0;
-    $selectoutput = "\n" . '<select name="' . $selectname . '">' . "\n";
+    $selectoutput = "\n" . '<label class="accesshide" for="instanceid">' . get_string('plugin', 'portfolio') . '</label>';
+    $selectoutput .= "\n" . '<select id="instanceid" name="' . $selectname . '">' . "\n";
     $existingexports = portfolio_existing_exports_by_plugin($USER->id);
     foreach ($instances as $instance) {
         $formats = portfolio_supported_formats_intersect($callerformats, $instance->supported_formats());
diff --git a/lib/questionlib.php b/lib/questionlib.php
index 1a24e8c..db7be64 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -992,7 +992,7 @@ function question_category_select_menu($contexts, $top = false, $currentcat = 0,
     foreach ($categoriesarray as $group => $opts) {
         $options[] = array($group => $opts);
     }
-
+    echo html_writer::label($selected, 'menucategory', false, array('class' => 'accesshide'));
     echo html_writer::select($options, 'category', $selected, $choose);
 }
 
diff --git a/lib/tablelib.php b/lib/tablelib.php
index b810564..04daa06 100644
--- a/lib/tablelib.php
+++ b/lib/tablelib.php
@@ -918,6 +918,7 @@ class flexible_table {
             $html = '<form action="'. $this->baseurl .'" method="post">';
             $html .= '<div class="mdl-align">';
             $html .= '<input type="submit" value="'.get_string('downloadas', 'table').'"/>';
+            $html .= html_writer::label(get_string('downloadoptions', 'table'), 'menudownload', false, array('class' => 'accesshide'));
             $html .= html_writer::select($downloadoptions, 'download', $this->defaultdownloadformat, false);
             $html .= '</div></form>';
 
-- 
1.7.9.5


From 28557dc456f25d2a9b8838e3aae1706a71aa533a Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Tue, 31 Jul 2012 13:23:42 +0800
Subject: [PATCH 296/903] MDL-34650 typo correction

---
 lib/outputcomponents.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index 4370279..6b760c2 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -715,7 +715,7 @@ class single_select implements renderable {
     var $label = '';
 
     /**
-     * @var array Button label's
+     * @var array Button label's attributes
      */
     var $labelattributes = array();
 
@@ -2805,4 +2805,4 @@ class custom_menu extends custom_menu_item {
         }
         return ($itema > $itemb) ? +1 : -1;
     }
-}
\ No newline at end of file
+}
-- 
1.7.9.5


From 971937e7d04794de58185ffe0f52c2cd0731dddb Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Tue, 31 Jul 2012 15:30:38 +0800
Subject: [PATCH 297/903] MDL-34650 added MDLs to todo comment and deprecation
 comment. (also triggering an amos script here for
 the other MDL-34650 commit)

AMOS BEGIN
  CPY [minute,form],[minute,core]
  CPY [month,form],[month,core]
  CPY [options,editor],[options,core]
  CPY [selectacourse,backup],[selectacourse,core]
AMOS END
---
 lang/en/moodle.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 6cd608c..ec475fa 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1470,7 +1470,7 @@ $string['screenreaderuse'] = 'Screen reader';
 $string['screenreaderyes'] = 'Yes';
 $string['screenreaderuse_help'] = 'If set to yes, a more accessible interface is provided in various places such as chat.';
 $string['screenshot'] = 'Screenshot';
-$string['search'] = 'Search'; // TODO rename to searchforums and move to mod_forum
+$string['search'] = 'Search'; // TODO MDL-34652 rename to searchforums and move to mod_forum
 $string['search_help'] = 'For basic searching of one or more words anywhere in the text, just type them separated by spaces. All words longer than two characters are used.
 
 For advanced searching, press the search button without typing anything in the search box to access the advanced search form.';
@@ -1523,7 +1523,7 @@ $string['servererror'] = 'An error occurred whilst communicating with the server
 $string['serverlocaltime'] = 'Server\'s local time';
 $string['setcategorytheme'] = 'Set category theme';
 $string['settings'] = 'Settings';
-$string['shortname'] = 'Short name'; // @deprecated - use shortnamecourse or shortnameuser or some own context specific string
+$string['shortname'] = 'Short name'; // @deprecated MDL-34652 - use shortnamecourse or shortnameuser or some own context specific string
 $string['shortnamecollisionwarning'] = '[*] = This shortname is already in use by a course and will need to be changed upon approval';
 $string['shortnamecourse'] = 'Course short name';
 $string['shortnamecourse_help'] = 'The short name of the course is displayed in the navigation and is used in the subject line of course email messages.';
-- 
1.7.9.5


From 548b7112a2c4e7da914e60cd2dd1cb4bb1d8db64 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Mon, 23 Jul 2012 12:32:46 +0100
Subject: [PATCH 298/903] MDL-28486 Force use of SSL for all youtube and vimeo
 embeds

If a page is served over SSL (https), then any content loaded from non-SSL
sources (e.g. http://youtube.com/) will cause errors to show in the
browser. To prevent this, it's best to use the SSL equivelants where they
exist (e.g. https://youtube.com/).

Unfortunately, it isn't possible to accurately determine whether the
current page is loaded over an SSL connection or not in Moodle.

Since including content from an external SSL site on a non-SSL moodle page
does not lead to browser warnings, but non-SSL external content on an SSL
moodle page does, we always use SSL where available.

Note: This does not lead to any additional processing requirements for the
moodle site.
---
 lib/medialib.php |   29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/lib/medialib.php b/lib/medialib.php
index 57a9e90..2290060 100644
--- a/lib/medialib.php
+++ b/lib/medialib.php
@@ -493,7 +493,7 @@ class core_media_player_vimeo extends core_media_player_external {
 
         $output = <<<OET
 <span class="mediaplugin mediaplugin_vimeo">
-<iframe title="$info" src="http://player.vimeo.com/video/$videoid"
+<iframe title="$info" src="https://player.vimeo.com/video/$videoid"
   width="$width" height="$height" frameborder="0"></iframe>
 </span>
 OET;
@@ -503,7 +503,7 @@ OET;
 
     protected function get_regex() {
         // Initial part of link.
-        $start = '~^http://vimeo\.com/';
+        $start = '~^https?://vimeo\.com/';
         // Middle bit: either watch?v= or v/.
         $middle = '([0-9]+)';
         return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
@@ -541,8 +541,9 @@ class core_media_player_youtube extends core_media_player_external {
 
         if (empty($CFG->xmlstrictheaders)) {
             return <<<OET
-<iframe title="$info" width="$width" height="$height"
-  src="$site/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen></iframe>
+<span class="mediaplugin mediaplugin_youtube">
+<iframe title="$info" width="$width" height="$height" src="https://$site/embed/$videoid?rel=0&wmode=transparent" frameborder="0" allowfullscreen="1"></iframe>
+</span>
 OET;
         }
 
@@ -551,7 +552,7 @@ OET;
         $output = <<<OET
 <span class="mediaplugin mediaplugin_youtube">
 <object title="$info" type="application/x-shockwave-flash"
-  data="$site/v/$videoid&amp;fs=1&amp;rel=0" width="$width" height="$height">
+  data="https://$site/v/$videoid&amp;fs=1&amp;rel=0" width="$width" height="$height">
  <param name="movie" value="$site/v/$videoid&amp;fs=1&amp;rel=0" />
  <param name="FlashVars" value="playerMode=embedded" />
  <param name="allowFullScreen" value="true" />
@@ -564,7 +565,7 @@ OET;
 
     protected function get_regex() {
         // Initial part of link.
-        $start = '~^(https?://www\.youtube(-nocookie)?\.com)/';
+        $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
         // Middle bit: either watch?v= or v/.
         $middle = '(?:watch\?v=|v/)([a-z0-9\-_]+)';
         return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
@@ -607,26 +608,16 @@ class core_media_player_youtube_playlist extends core_media_player_external {
 
         self::pick_video_size($width, $height);
 
-        // TODO: iframe HTML 5 video not implemented and object does not work
-        // on iOS devices.
-        $fallback = core_media_player::PLACEHOLDER;
-        $output = <<<OET
+        return <<<OET
 <span class="mediaplugin mediaplugin_youtube">
-<object title="$info" type="application/x-shockwave-flash"
-  data="$site/p/$playlist&amp;fs=1&amp;rel=0" width="$width" height="$height">
- <param name="movie" value="$site/v/$playlist&amp;fs=1&amp;rel=0" />
- <param name="FlashVars" value="playerMode=embedded" />
- <param name="allowFullScreen" value="true" />
-$fallback</object>
+<iframe width="$width" height="$height" src="https://$site/embed/videoseries?list=$playlist" frameborder="0" allowfullscreen="1"></iframe>
 </span>
 OET;
-
-        return $output;
     }
 
     protected function get_regex() {
         // Initial part of link.
-        $start = '~^(https?://www\.youtube(-nocookie)?\.com)/';
+        $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
         // Middle bit: either view_play_list?p= or p/ (doesn't work on youtube) or playlist?list=.
         $middle = '(?:view_play_list\?p=|p/|playlist\?list=)([a-z0-9\-_]+)';
         return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
-- 
1.7.9.5


From 4233aac1e36595798a8fe76e5f9e88641c8f2a35 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:26:09 +0800
Subject: [PATCH 299/903] MDL-34552 accessibility compliance for admin: Add
 forform input text and select tag

---
 admin/filters.php                                  |    2 ++
 admin/mnet/access_control.php                      |    7 ++++---
 admin/portfolio.php                                |    2 ++
 admin/repository.php                               |    3 ++-
 admin/timezone.php                                 |    2 +-
 admin/tool/langimport/index.php                    |    4 ++--
 admin/tool/spamcleaner/index.php                   |    1 +
 .../tool/spamcleaner/lang/en/tool_spamcleaner.php  |    1 +
 .../new_table_from_mysql.class.php                 |    2 +-
 .../view_structure_php.class.php                   |    2 +-
 .../view_table_php/view_table_php.class.php        |    2 +-
 11 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/admin/filters.php b/admin/filters.php
index 0d7faa3..39a15a8 100644
--- a/admin/filters.php
+++ b/admin/filters.php
@@ -242,6 +242,7 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
 
     // Disable/off/on
     $select = new single_select(filters_action_url($filter, 'setstate'), 'newstate', $activechoices, $filterinfo->active, null, 'active' . basename($filter));
+    $select->set_label(get_string('isactive', 'filters'), array('class' => 'accesshide'));
     $row[] = $OUTPUT->render($select);
 
     // Re-order
@@ -263,6 +264,7 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
 
     // Apply to strings.
     $select = new single_select(filters_action_url($filter, 'setapplyto'), 'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . basename($filter));
+    $select->set_label(get_string('applyto', 'filters'), array('class' => 'accesshide'));
     $select->disabled = $filterinfo->active == TEXTFILTER_DISABLED;
     $row[] = $OUTPUT->render($select);
 
diff --git a/admin/mnet/access_control.php b/admin/mnet/access_control.php
index b9e436f..e820489 100644
--- a/admin/mnet/access_control.php
+++ b/admin/mnet/access_control.php
@@ -203,17 +203,18 @@ echo get_string('username') . ":\n";
 if (!empty($formerror['username'])) {
     echo '<span class="error"> * </span>';
 }
-echo '<input type="text" name="username" size="20" maxlength="100" />';
+echo html_writer::label(get_string('username'), 'menuusername', false, array('class' => 'accesshide'));
+echo '<input id="menuusername" type="text" name="username" size="20" maxlength="100" />';
 
 // choose a remote host
-echo " " . get_string('remotehost', 'mnet') . ":\n";
+echo " " . html_writer::label(get_string('remotehost', 'mnet'), 'menumnet_host_id') . ":\n";
 if (!empty($formerror['mnet_host_id'])) {
     echo '<span class="error"> * </span>';
 }
 echo html_writer::select($mnethosts, 'mnet_host_id');
 
 // choose an access level
-echo " " . get_string('accesslevel', 'mnet') . ":\n";
+echo " " . html_writer::label(get_string('accesslevel', 'mnet'), 'menuaccessctrl') . ":\n";
 if (!empty($formerror['accessctrl'])) {
     echo '<span class="error"> * </span>';
 }
diff --git a/admin/portfolio.php b/admin/portfolio.php
index 791c79f..9536942 100644
--- a/admin/portfolio.php
+++ b/admin/portfolio.php
@@ -197,6 +197,7 @@ if (($action == 'edit') || ($action == 'new')) {
                 $currentaction = 'hide';
             }
             $select = new single_select(portfolio_action_url($pluginid, 'pf'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . $pluginid);
+            $select->set_label(get_string('action'), array('class' => 'accesshide'));
             $table->data[] = array($pluginname, $OUTPUT->render($select), $settings);
         }
         if (!in_array($plugin, $usedplugins)) {
@@ -218,6 +219,7 @@ if (($action == 'edit') || ($action == 'new')) {
                 $insaneplugins[] = $p;
             } else {
                 $select = new single_select(portfolio_action_url($p, 'pf'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . $p);
+                $select->set_label(get_string('action'), array('class' => 'accesshide'));
                 $table->data[] = array(portfolio_static_function($p, 'get_name'), $OUTPUT->render($select), '');
             }
         }
diff --git a/admin/repository.php b/admin/repository.php
index b3494ca..04ce40e 100644
--- a/admin/repository.php
+++ b/admin/repository.php
@@ -352,7 +352,7 @@ if (($action == 'edit') || ($action == 'new')) {
             }
 
             $select = new single_select(repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
-
+            $select->set_label(get_string('action'), array('class' => 'accesshide'));
             // Display up/down link
             $updown = '';
             $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
@@ -389,6 +389,7 @@ if (($action == 'edit') || ($action == 'new')) {
             // Check that it has not already been listed
             if (!in_array($plugin, $alreadyplugins)) {
                 $select = new single_select(repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
+                $select->set_label(get_string('action'), array('class' => 'accesshide'));
                 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
             }
         }
diff --git a/admin/timezone.php b/admin/timezone.php
index e031be4..3bbe8d1 100644
--- a/admin/timezone.php
+++ b/admin/timezone.php
@@ -44,7 +44,7 @@
     $timezones = get_list_of_timezones();
 
     echo '<center><form action="timezone.php" method="post">';
-    echo "$strusers ($strall): ";
+    echo html_writer::label($strusers . ' (' . $strall . '): ', 'menuzone');
     echo html_writer::select($timezones, "zone", $current, array('99'=>get_string("serverlocaltime")));
     echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />";
     echo '<input type="submit" value="'.s($strsavechanges).'" />';
diff --git a/admin/tool/langimport/index.php b/admin/tool/langimport/index.php
index 80d8829..82b5cc2 100644
--- a/admin/tool/langimport/index.php
+++ b/admin/tool/langimport/index.php
@@ -287,7 +287,7 @@ $url = new moodle_url('/admin/tool/langimport/index.php', array('mode' => DELETI
 echo html_writer::start_tag('td', array('valign' => 'top'));
 echo html_writer::start_tag('form', array('id' => 'uninstallform', 'action' => $url->out(), 'method' => 'post'));
 echo html_writer::start_tag('fieldset');
-echo html_writer::label(get_string('installedlangs', 'tool_langimport'), 'uninstalllang');
+echo html_writer::label(get_string('installedlangs', 'tool_langimport'), 'menuuninstalllang');
 echo html_writer::empty_tag('br');
 echo html_writer::select($installedlangs, 'uninstalllang', '', false, array('size' => 15));
 echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
@@ -315,7 +315,7 @@ if (!empty($options)) {
     $url = new moodle_url('/admin/tool/langimport/index.php', array('mode' => INSTALLATION_OF_SELECTED_LANG));
     echo html_writer::start_tag('form', array('id' => 'installform', 'action' => $url->out(), 'method' => 'post'));
     echo html_writer::start_tag('fieldset');
-    echo html_writer::label(get_string('availablelangs','install'), 'pack');
+    echo html_writer::label(get_string('availablelangs','install'), 'menupack');
     echo html_writer::empty_tag('br');
     echo html_writer::select($options, 'pack[]', '', false, array('size' => 15, 'multiple' => 'multiple'));
     echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
diff --git a/admin/tool/spamcleaner/index.php b/admin/tool/spamcleaner/index.php
index 443f5cd..0835270 100644
--- a/admin/tool/spamcleaner/index.php
+++ b/admin/tool/spamcleaner/index.php
@@ -96,6 +96,7 @@ echo $OUTPUT->box_start();     // The forms section at the top
 
 <form method="post" action="index.php">
   <div>
+    <label class="accesshide" for="keyword_el"><?php print_string('spamkeyword', 'tool_spamcleaner') ?></label>
     <input type="text" name="keyword" id="keyword_el" value="<?php p($keyword) ?>" />
     <input type="hidden" name="sesskey" value="<?php echo sesskey();?>" />
     <input type="submit" value="<?php echo get_string('spamsearch', 'tool_spamcleaner')?>" />
diff --git a/admin/tool/spamcleaner/lang/en/tool_spamcleaner.php b/admin/tool/spamcleaner/lang/en/tool_spamcleaner.php
index 5a86357..df6b4a3 100644
--- a/admin/tool/spamcleaner/lang/en/tool_spamcleaner.php
+++ b/admin/tool/spamcleaner/lang/en/tool_spamcleaner.php
@@ -38,6 +38,7 @@ $string['spamfromcomments'] = 'From comments:';
 $string['spamfrommessages'] = 'From messages:';
 $string['spamfromforumpost'] = 'From forum post:';
 $string['spaminvalidresult'] = 'Unknown but invalid result';
+$string['spamkeyword'] = 'Keyword';
 $string['spamoperation'] = 'Operation';
 $string['spamresult'] = 'Results of searching user profiles containing:';
 $string['spamsearch'] = 'Search for these keywords';
diff --git a/admin/tool/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php b/admin/tool/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
index 4dca286..8332d21 100644
--- a/admin/tool/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
+++ b/admin/tool/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
@@ -113,7 +113,7 @@ class new_table_from_mysql extends XMLDBAction {
             $o.= '    <input type="hidden" name ="postaction" value="edit_table" />';
             $o.= '    <input type="hidden" name ="sesskey" value="' . sesskey() . '" />';
             $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-            $o.= '      <tr><td><label for="table" accesskey="t">' . $this->str['createtable'] .' </label>' . html_writer::select($selecttables, 'table') . '<label for="after" accesskey="a">' . $this->str['aftertable'] . ' </label>' .html_writer::select($aftertables, 'after') . '</td></tr>';
+            $o.= '      <tr><td><label for="menutable" accesskey="t">' . $this->str['createtable'] .' </label>' . html_writer::select($selecttables, 'table') . '<label for="menuafter" accesskey="a">' . $this->str['aftertable'] . ' </label>' .html_writer::select($aftertables, 'after') . '</td></tr>';
             $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['create'] . '" /></td></tr>';
             $o.= '      <tr><td colspan="2" align="center"><a href="index.php?action=edit_xml_file&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a></td></tr>';
             $o.= '    </table>';
diff --git a/admin/tool/xmldb/actions/view_structure_php/view_structure_php.class.php b/admin/tool/xmldb/actions/view_structure_php/view_structure_php.class.php
index 11d779c..0ddf559 100644
--- a/admin/tool/xmldb/actions/view_structure_php/view_structure_php.class.php
+++ b/admin/tool/xmldb/actions/view_structure_php/view_structure_php.class.php
@@ -114,7 +114,7 @@ class view_structure_php extends XMLDBAction {
         $o.= '    <input type="hidden" name ="dir" value="' . str_replace($CFG->dirroot, '', $dirpath) . '" />';
         $o.= '    <input type="hidden" name ="action" value="view_structure_php" />';
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td><label for="action" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="table" accesskey="t">' . $this->str['selecttable'] . ' </label>' .html_writer::select($poptables, 'table', $tableparam, false) . '</td></tr>';
+        $o.= '      <tr><td><label for="menucommand" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="menutable" accesskey="t">' . $this->str['selecttable'] . ' </label>' .html_writer::select($poptables, 'table', $tableparam, false) . '</td></tr>';
         $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['view'] . '" /></td></tr>';
         $o.= '    </table>';
         $o.= '</div></form>';
diff --git a/admin/tool/xmldb/actions/view_table_php/view_table_php.class.php b/admin/tool/xmldb/actions/view_table_php/view_table_php.class.php
index 132c881..235056f 100644
--- a/admin/tool/xmldb/actions/view_table_php/view_table_php.class.php
+++ b/admin/tool/xmldb/actions/view_table_php/view_table_php.class.php
@@ -163,7 +163,7 @@ class view_table_php extends XMLDBAction {
         $o.= '    <input type="hidden" name ="table" value="' . s($tableparam) . '" />';
         $o.= '    <input type="hidden" name ="action" value="view_table_php" />';
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td><label for="action" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="fieldkeyindex" accesskey="f">' . $this->str['selectfieldkeyindex'] . ' </label>' .html_writer::select($popfields, 'fieldkeyindex', $origfieldkeyindexparam, false) . '</td></tr>';
+        $o.= '      <tr><td><label for="menucommand" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="menufieldkeyindex" accesskey="f">' . $this->str['selectfieldkeyindex'] . ' </label>' .html_writer::select($popfields, 'fieldkeyindex', $origfieldkeyindexparam, false) . '</td></tr>';
         $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['view'] . '" /></td></tr>';
         $o.= '    </table>';
         $o.= '</div></form>';
-- 
1.7.9.5


From 61e3665a15bc33860d013e5278d8b880ee241d2e Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:46:40 +0800
Subject: [PATCH 300/903] MDL-34553 accessibility compliance for
 authentication: Add forform input text and select
 tag

---
 auth/cas/config.html            |   28 ++++++++++++++--------------
 auth/fc/config.html             |   24 ++++++++++++------------
 auth/imap/config.html           |   14 +++++++-------
 auth/ldap/config.html           |    2 +-
 auth/mnet/config.html           |    6 +++---
 auth/nntp/config.html           |   12 ++++++------
 auth/pop3/config.html           |   18 +++++++++---------
 auth/radius/config.html         |   18 +++++++++---------
 auth/shibboleth/config.html     |   24 ++++++++++++------------
 auth/shibboleth/index_form.html |    4 ++--
 10 files changed, 75 insertions(+), 75 deletions(-)

diff --git a/auth/cas/config.html b/auth/cas/config.html
index 4781cb9..28557dd 100644
--- a/auth/cas/config.html
+++ b/auth/cas/config.html
@@ -94,9 +94,9 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_hostname_key', 'auth_cas') ?>:</td>
+    <td align="right"><label for="hostname"><?php print_string('auth_cas_hostname_key', 'auth_cas') ?>: </label></td>
     <td>
-        <input name="hostname" type="text" size="30" value="<?php echo $config->hostname ?>" />
+        <input name="hostname" id="hostname" type="text" size="30" value="<?php echo $config->hostname ?>" />
         <?php if (isset($err['hostname'])) { echo $OUTPUT->error_text($err['hostname']); } ?>
     </td>
     <td>
@@ -105,10 +105,10 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_baseuri_key', 'auth_cas') ?>:
+        <label for="baseuri"><?php print_string('auth_cas_baseuri_key', 'auth_cas') ?>: </label>
     </td>
     <td>
-        <input name="baseuri" type="text" size="30" value="<?php echo $config->baseuri ?>" />
+        <input name="baseuri" id="baseuri" type="text" size="30" value="<?php echo $config->baseuri ?>" />
         <?php if (isset($err['baseuri'])) { echo $OUTPUT->error_text($err['baseuri']); } ?>
     </td>
     <td>
@@ -117,10 +117,10 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_port_key', 'auth_cas') ?>:
+        <label for="port"><?php print_string('auth_cas_port_key', 'auth_cas') ?>: </label>
     </td>
     <td>
-        <input name="port" type="text" size="30" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="30" value="<?php echo $config->port ?>" />
         <?php if (isset($err['port'])) { echo $OUTPUT->error_text($err['port']); } ?>
     </td>
     <td>
@@ -129,7 +129,7 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_casversion', 'auth_cas') ?>:
+        <?php echo html_writer::label(get_string('auth_cas_casversion', 'auth_cas'), 'menucasversion'); ?>:
     </td>
     <td>
         <?php
@@ -145,7 +145,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_language_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_language_key', 'auth_cas'), 'menulanguage'); ?>:</td>
     <td>
         <?php echo html_writer::select($CASLANGUAGES, 'language', $config->language, false); ?>
     </td>
@@ -155,7 +155,7 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_proxycas_key', 'auth_cas') ?>:
+        <?php echo html_writer::label(get_string('auth_cas_proxycas_key', 'auth_cas'), 'menuproxycas'); ?>:
     </td>
     <td>
         <?php echo html_writer::select($yesno, 'proxycas', $config->proxycas, false); ?>
@@ -165,7 +165,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_logoutcas_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_logoutcas_key', 'auth_cas'), 'menulogoutcas'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'logoutcas', $config->logoutcas, false); ?>
     </td>
@@ -174,7 +174,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_multiauth_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_multiauth_key', 'auth_cas'), 'menumultiauth'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'multiauth', $config->multiauth, false); ?>
     </td>
@@ -183,7 +183,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top"  class="required">
-    <td align="right"><?php print_string('auth_cas_certificate_check_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_certificate_check_key', 'auth_cas'), 'menucertificate_check'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'certificate_check', $config->certificate_check, false); ?>
     </td>
@@ -192,7 +192,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_certificate_path_key', 'auth_cas') ?>:</td>
+    <td align="right"><label for="certificate_path"><?php print_string('auth_cas_certificate_path_key', 'auth_cas') ?>: </label></td>
     <td>
         <input name="certificate_path" id="certificate_path" type="text" size="30" value="<?php echo $config->certificate_path ?>" />
         <?php if (isset($err['certificate_path'])) echo $OUTPUT->error_text($err['certificate_path']); ?>
@@ -219,7 +219,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><label for="menuversion"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label></td>
+    <td align="right"><label for="menuldap_version"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label></td>
     <td>
         <?php
              $versions = array();
diff --git a/auth/fc/config.html b/auth/fc/config.html
index 91dd8c8..0d0da60 100644
--- a/auth/fc/config.html
+++ b/auth/fc/config.html
@@ -27,9 +27,9 @@
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fchost_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="host"><?php print_string("auth_fchost_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host?>" />
     <?php  if (isset($err["host"])) echo $OUTPUT->error_text($err["host"]); ?>
     </td>
     <td>
@@ -38,9 +38,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcfppport_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="fppport"><?php  print_string("auth_fcfppport_key", "auth_fc") ?>: </label></td>
     <td>
-        <input name="fppport" type="text" size="30" value="<?php echo $config->fppport?>" />
+        <input name="fppport" id="fppport" type="text" size="30" value="<?php echo $config->fppport?>" />
     <?php  if (isset($err["fppport"])) echo $OUTPUT->error_text($err["host"]); ?>
     </td>
     <td>
@@ -49,9 +49,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcuserid_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="userid"><?php  print_string("auth_fcuserid_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="userid" type="text" size="30" maxlength="15" value="<?php echo $config->userid?>" />
+        <input name="userid" id="userid" type="text" size="30" maxlength="15" value="<?php echo $config->userid?>" />
     <?php  if (isset($err["userid"])) echo $OUTPUT->error_text($err["userid"]); ?>
     </td>
     <td>
@@ -59,9 +59,9 @@
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcpasswd_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="passwd"><?php print_string("auth_fcpasswd_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" />
+        <input name="passwd" id="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" />
     <?php  if (isset($err["passwd"])) echo $OUTPUT->error_text($err["passwd"]); ?>
     </td>
     <td>
@@ -70,9 +70,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fccreators_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="creators"><?php  print_string("auth_fccreators_key", "auth_fc") ?>: </label></td>
     <td>
-        <input name="creators" type="text" size="30" value="<?php echo $config->creators?>" />
+        <input name="creators" id="creators" type="text" size="30" value="<?php echo $config->creators?>" />
     <?php  if (isset($err["creators"])) echo $OUTPUT->error_text($err["creators"]); ?>
     </td>
     <td>
@@ -81,9 +81,9 @@
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_fcchangepasswordurl', 'auth_fc') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_fcchangepasswordurl', 'auth_fc') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/imap/config.html b/auth/imap/config.html
index d88ad3a..e36fdd0 100644
--- a/auth/imap/config.html
+++ b/auth/imap/config.html
@@ -18,9 +18,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imaphost_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_imaphost_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -40,7 +40,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imaptype_key', 'auth_imap') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_imaptype_key', 'auth_imap'), 'menutype'); ?>: </td>
     <td>
         <?php
 
@@ -56,9 +56,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imapport_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_imapport_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err['port'])) {
@@ -71,9 +71,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_imapchangepasswordurl_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_imapchangepasswordurl_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/ldap/config.html b/auth/ldap/config.html
index 72519c7..8ad27ef 100644
--- a/auth/ldap/config.html
+++ b/auth/ldap/config.html
@@ -118,7 +118,7 @@ $yesno = array(get_string('no'), get_string('yes'));
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <label for="menuversion"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label>
+        <label for="menuldap_version"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label>
     </td>
     <td>
         <?php
diff --git a/auth/mnet/config.html b/auth/mnet/config.html
index 2dbba3f..c25b314 100644
--- a/auth/mnet/config.html
+++ b/auth/mnet/config.html
@@ -22,9 +22,9 @@ if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict'
 <table cellspacing="0" cellpadding="5">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('rpc_negotiation_timeout', 'auth_mnet'); ?>: </td>
+    <td align="right"><label for="rpc_negotiation_timeout"><?php print_string('rpc_negotiation_timeout', 'auth_mnet'); ?>: </label></td>
     <td>
-        <input name="rpc_negotiation_timeout" type="text" size="5" value="<?php echo $config->rpc_negotiation_timeout ?>" />
+        <input name="rpc_negotiation_timeout" id="rpc_negotiation_timeout" type="text" size="5" value="<?php echo $config->rpc_negotiation_timeout ?>" />
         <?php
 
         if (isset($err['rpc_negotiation_timeout'])) {
@@ -45,7 +45,7 @@ if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict'
 <?php /*
  See MDL-21327   for why this is commented out
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auto_add_remote_users', 'auth_mnet'); ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auto_add_remote_users', 'auth_mnet'), 'menuauto_add_remote_users'); ?>: </td>
     <td>
         <?php
 
diff --git a/auth/nntp/config.html b/auth/nntp/config.html
index 179efdd..c9ed4c5 100644
--- a/auth/nntp/config.html
+++ b/auth/nntp/config.html
@@ -15,9 +15,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_nntphost_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_nntphost_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err["host"])) {
@@ -37,9 +37,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_nntpport_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_nntpport_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err["port"])) {
@@ -52,9 +52,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_nntpchangepasswordurl_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_nntpchangepasswordurl_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/pop3/config.html b/auth/pop3/config.html
index e2d7e7a..1f21e67 100644
--- a/auth/pop3/config.html
+++ b/auth/pop3/config.html
@@ -21,9 +21,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3host_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_pop3host_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -43,7 +43,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3type_key', 'auth_pop3') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_pop3type_key', 'auth_pop3'), 'menutype'); ?>: </td>
     <td>
         <?php
 
@@ -59,9 +59,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3port_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_pop3port_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err['port'])) {
@@ -74,9 +74,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3mailbox_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="mailbox"><?php print_string('auth_pop3mailbox_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="mailbox" type="text" size="6" value="<?php echo $config->mailbox ?>" />
+        <input name="mailbox" id="mailbox" type="text" size="6" value="<?php echo $config->mailbox ?>" />
         <?php
 
         if (isset($err['mailbox'])) {
@@ -89,9 +89,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_pop3changepasswordurl_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_pop3changepasswordurl_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/radius/config.html b/auth/radius/config.html
index 5973c34..103bb20 100644
--- a/auth/radius/config.html
+++ b/auth/radius/config.html
@@ -30,9 +30,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiushost_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_radiushost_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -45,9 +45,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiusnasport_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="nasport"><?php print_string('auth_radiusnasport_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="nasport" type="text" size="6" value="<?php echo $config->nasport ?>" />
+        <input name="nasport" id="nasport" type="text" size="6" value="<?php echo $config->nasport ?>" />
         <?php
 
         if (isset($err['nasport'])) {
@@ -60,7 +60,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" >
-    <td align="right"><?php print_string('auth_radiustype_key', 'auth_radius') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_radiustype_key', 'auth_radius'), 'menuradiustype'); ?>: </td>
     <td>
 <?php
 
@@ -82,9 +82,9 @@ if (!isset($config->changepasswordurl)) {
 
 
 <tr valign="top" >
-    <td align="right"><?php print_string('auth_radiussecret_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="secret"><?php print_string('auth_radiussecret_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="secret" type="text" size="6" value="<?php echo $config->secret ?>" />
+        <input name="secret" id="secret" type="text" size="6" value="<?php echo $config->secret ?>" />
         <?php
 
         if (isset($err['secret'])) {
@@ -97,9 +97,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiuschangepasswordurl_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_radiuschangepasswordurl_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/shibboleth/config.html b/auth/shibboleth/config.html
index 18dfdea..9a1854f 100644
--- a/auth/shibboleth/config.html
+++ b/auth/shibboleth/config.html
@@ -20,17 +20,17 @@
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string("username") ?>:</td>
+    <td align="right"><label for="user_attribute"><?php print_string("username") ?>: </label></td>
     <td>
-        <input name="user_attribute" type="text" size="30" value="<?php echo $config->user_attribute ?>" />
+        <input id="user_attribute" name="user_attribute" type="text" size="30" value="<?php echo $config->user_attribute ?>" />
     </td>
     <td><?php print_string("auth_shib_username_description", "auth_shibboleth") ?></td>
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_convert_data", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="convert_data"><?php print_string("auth_shib_convert_data", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
+        <input name="convert_data" id="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
         <?php
 
         if ($config->convert_data and $config->convert_data != '' and !is_readable($config->convert_data)) {
@@ -82,9 +82,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_logout_url", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="logout_handler"><?php print_string("auth_shib_logout_url", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="logout_handler" type="text" size="30" value="<?php
+        <input name="logout_handler" id="logout_handler" type="text" size="30" value="<?php
         if ( isset($config->logout_handler) and !empty($config->logout_handler)){
             echo $config->logout_handler;
         }
@@ -94,9 +94,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_logout_return_url", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="logout_return_url"><?php print_string("auth_shib_logout_return_url", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="logout_return_url" type="text" size="30" value="<?php
+        <input name="logout_return_url" id="logout_return_url" type="text" size="30" value="<?php
         if ( isset($config->logout_return_url) and !empty($config->logout_return_url)){
             echo $config->logout_return_url;
         }
@@ -106,9 +106,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_auth_method", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="login_name"><?php print_string("auth_shib_auth_method", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="login_name" type="text" size="30" value="<?php
+        <input name="login_name" id="login_name" type="text" size="30" value="<?php
         if ( isset($config->login_name) and !empty($config->login_name)){
             echo htmlentities($config->login_name);
         } else {
@@ -120,9 +120,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_shib_changepasswordurl', 'auth_shibboleth') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_shib_changepasswordurl', 'auth_shibboleth') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
diff --git a/auth/shibboleth/index_form.html b/auth/shibboleth/index_form.html
index 423faa0..1e93cf2 100644
--- a/auth/shibboleth/index_form.html
+++ b/auth/shibboleth/index_form.html
@@ -29,9 +29,9 @@ if ($show_instructions) {
 
         ?>
           <div class="guestsub">
-          <p><?php print_string("auth_shibboleth_select_organization", "auth_shibboleth"); ?></p>
+          <p><label for="idp"><?php print_string("auth_shibboleth_select_organization", "auth_shibboleth"); ?></label></p>
             <form action="login.php" method="post" id="guestlogin">
-            <select name="idp">
+            <select id="idp" name="idp">
                 <option value="-" ><?php print_string("auth_shibboleth_select_member", "auth_shibboleth"); ?></option>
                 <?php
                     print_idp_list();
-- 
1.7.9.5


From 8291579200c717c7f4759273c510fa0d3d1e1325 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:46:48 +0800
Subject: [PATCH 301/903] MDL-34554 accessibility compliance for blocks: Add
 forform input text and select tag

---
 blocks/section_links/config_instance.html |    4 ++--
 blocks/tags/block_tags.php                |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/blocks/section_links/config_instance.html b/blocks/section_links/config_instance.html
index efc2fbc..a2765da 100644
--- a/blocks/section_links/config_instance.html
+++ b/blocks/section_links/config_instance.html
@@ -66,7 +66,7 @@ for($i = 1; $i < 3; $i++){
 ?>
     <tr valign="top">
         <td align="right">
-            <?php print_string('numsections'.$i, 'block_section_links'); ?>:
+            <label for="menunumsections<?php echo $i; ?>"><?php print_string('numsections'.$i, 'block_section_links'); ?>:</label>
         </td>
         <td>
             <?php choose_from_menu($numberofsections, 'numsections'.$i, $selected[$i][0]); ?>
@@ -77,7 +77,7 @@ for($i = 1; $i < 3; $i++){
     </tr>
     <tr valign="top">
         <td align="right">
-            <?php print_string('incby'.$i, 'block_section_links'); ?>:
+            <label for="menuincby<?php echo $i;?>"><?php print_string('incby'.$i, 'block_section_links'); ?>:</label>
         </td>
         <td>
             <?php choose_from_menu($increments, 'incby'.$i, $selected[$i][1]); ?>
diff --git a/blocks/tags/block_tags.php b/blocks/tags/block_tags.php
index b7a35fd..7ce4a4a 100644
--- a/blocks/tags/block_tags.php
+++ b/blocks/tags/block_tags.php
@@ -225,7 +225,6 @@ class block_tags extends block_base {
             if ($officialtags) { $this->content->text .= $officialtagscontent; }
             if ($coursetags) { $this->content->text .= $coursetagscontent; }
             if ($commtags) { $this->content->text .= $commtagscontent; }
-
             // add the input form section (allowing a user to tag the current course) and navigation, or loggin message
             if ($loggedin) {
                 // only show the input form on course pages for those allowed (or not barred)
@@ -250,7 +249,8 @@ class block_tags extends block_base {
                             <div class="coursetag_form_wrapper">
                             <div class="coursetag_form_positioner">
                                 <div class="coursetag_form_input1">
-                                    <input type="text" name="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
+                                    <label class="accesshide" for="coursetag_sug_keyword">$tagthisunit</label>
+                                    <input type="text" name="coursetag_sug_keyword" id="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
                                 </div>
                                 <div class="coursetag_form_input2">
                                     <input type="text" name="coursetag_new_tag" id="coursetag_new_tag" class="coursetag_form_input2a"
-- 
1.7.9.5


From 81ff28e7e669222e100b2c8db304f31ba0bd9ce1 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:46:55 +0800
Subject: [PATCH 302/903] MDL-34555 accessibility compliance for calendar: Add
 forform input text and select tag

---
 calendar/lib.php      |    1 +
 calendar/renderer.php |    4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/calendar/lib.php b/calendar/lib.php
index 8152990..8f562a9 100644
--- a/calendar/lib.php
+++ b/calendar/lib.php
@@ -1627,6 +1627,7 @@ function calendar_print_month_selector($name, $selected) {
     for ($i=1; $i<=12; $i++) {
         $months[$i] = userdate(gmmktime(12, 0, 0, $i, 15, 2000), '%B');
     }
+    echo html_writer::label(get_string('months'), 'menu'. $name, false, array('class' => 'accesshide'));
     echo html_writer::select($months, $name, $selected, false);
 }
 
diff --git a/calendar/renderer.php b/calendar/renderer.php
index a2f8a7b..396e91d 100644
--- a/calendar/renderer.php
+++ b/calendar/renderer.php
@@ -710,7 +710,9 @@ class core_calendar_renderer extends plugin_renderer_base {
         $select = new single_select(new moodle_url(CALENDAR_URL.'set.php', array('return' => base64_encode($returnurl->out(false)), 'var' => 'setcourse', 'sesskey'=>sesskey())), 'id', $courseoptions, $selected, null);
         $select->class = 'cal_courses_flt';
         if ($label !== null) {
-            $select->label = $label;
+            $select->set_label($label);
+        } else {
+            $select->set_label(get_string('listofcourses'), array('class' => 'accesshide'));
         }
         return $this->output->render($select);
     }
-- 
1.7.9.5


From 0fa95a3c976d752ddc952a80e189fbbe0eb97ab0 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:47:05 +0800
Subject: [PATCH 303/903] MDL-34556 accessibility compliance for course: Add
 forform input text and select tag

---
 course/category.php |    1 +
 course/index.php    |    1 +
 course/scales.php   |    9 ++++++---
 course/search.php   |    1 +
 4 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/course/category.php b/course/category.php
index 935b83a..5989cf8 100644
--- a/course/category.php
+++ b/course/category.php
@@ -422,6 +422,7 @@ if (!$courses) {
         make_categories_list($movetocategories, $notused, 'moodle/category:manage');
         $movetocategories[$category->id] = get_string('moveselectedcoursesto');
         echo '<tr><td colspan="3" align="right">';
+        echo html_writer::label(get_string('moveselectedcoursesto'), 'movetoid', false, array('class' => 'accesshide'));
         echo html_writer::select($movetocategories, 'moveto', $category->id, null, array('id'=>'movetoid'));
         $PAGE->requires->js_init_call('M.util.init_select_autosubmit', array('movecourses', 'movetoid', false));
         echo '<input type="hidden" name="id" value="'.$category->id.'" />';
diff --git a/course/index.php b/course/index.php
index ce1466a..e086dcf 100644
--- a/course/index.php
+++ b/course/index.php
@@ -369,6 +369,7 @@ function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $
             }
             $popupurl = new moodle_url("index.php?move=$category->id&sesskey=".sesskey());
             $select = new single_select($popupurl, 'moveto', $tempdisplaylist, $category->parent, null, "moveform$category->id");
+            $select->set_label(get_string('frontpagecategorynames'), array('class' => 'accesshide'));
             echo $OUTPUT->render($select);
         }
         echo '</td>';
diff --git a/course/scales.php b/course/scales.php
index 07bf4fa..67793a4 100644
--- a/course/scales.php
+++ b/course/scales.php
@@ -70,7 +70,8 @@ if ($scaleid) {
             echo $OUTPUT->box_start();
             echo $OUTPUT->heading($scale->name);
             echo "<center>";
-            echo html_writer::select($scalemenu, 'unused');
+            echo html_writer::label(get_string('scales'), 'scaleunused'. $scaleid, false, array('class' => 'accesshide'));
+            echo html_writer::select($scalemenu, 'unused', '', array('' => 'choosedots'), array('id' => 'scaleunused'.$scaleid));
             echo "</center>";
             echo text_to_html($scale->description);
             echo $OUTPUT->box_end();
@@ -101,7 +102,8 @@ if ($scales = $DB->get_records("scale", array("courseid"=>$course->id), "name AS
         echo $OUTPUT->box_start();
         echo $OUTPUT->heading($scale->name);
         echo "<center>";
-        echo html_writer::select($scalemenu, 'unused');
+        echo html_writer::label(get_string('scales'), 'courseunused' . $scale->id, false, array('class' => 'accesshide'));
+        echo html_writer::select($scalemenu, 'unused', '', array('' => 'choosedots'), array('id' => 'courseunused' . $scale->id));
         echo "</center>";
         echo text_to_html($scale->description);
         echo $OUTPUT->box_end();
@@ -127,7 +129,8 @@ if ($scales = $DB->get_records("scale", array("courseid"=>0), "name ASC")) {
         echo $OUTPUT->box_start();
         echo $OUTPUT->heading($scale->name);
         echo "<center>";
-        echo html_writer::select($scalemenu, 'unused');
+        echo html_writer::label(get_string('scales'), 'sitescale' . $scale->id, false, array('class' => 'accesshide'));
+        echo html_writer::select($scalemenu, 'unused', '', array('' => 'choosedots'), array('id' => 'sitescale' . $scale->id));
         echo "</center>";
         echo text_to_html($scale->description);
         echo $OUTPUT->box_end();
diff --git a/course/search.php b/course/search.php
index 246577c..8c9f85c 100644
--- a/course/search.php
+++ b/course/search.php
@@ -377,6 +377,7 @@ if ($courses) {
         echo "<input type=\"button\" onclick=\"checkall()\" value=\"$strselectall\" />\n";
         echo "<input type=\"button\" onclick=\"checknone()\" value=\"$strdeselectall\" />\n";
         // Select box should only show categories in which user has min capability to move course.
+        echo html_writer::label(get_string('moveselectedcoursesto'), 'movetoid', false, array('class' => 'accesshide'));
         echo html_writer::select($usercatlist, 'moveto', '', array(''=>get_string('moveselectedcoursesto')), array('id'=>'movetoid'));
         $PAGE->requires->js_init_call('M.util.init_select_autosubmit', array('movecourses', 'movetoid', false));
         echo "</td>\n</tr>\n";
-- 
1.7.9.5


From b44ae5fb0a9b82729524736b79df2abbcaec36e2 Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Sun, 4 Mar 2012 09:32:22 -0800
Subject: [PATCH 304/903] MDL-29909 wiki: do not show groups when no groups
 present

---
 mod/wiki/renderer.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/mod/wiki/renderer.php b/mod/wiki/renderer.php
index b89cdff..c06d2fa 100644
--- a/mod/wiki/renderer.php
+++ b/mod/wiki/renderer.php
@@ -390,6 +390,9 @@ class mod_wiki_renderer extends plugin_renderer_base {
                     }
                 } else {
                     $group = groups_get_group($subwiki->groupid);
+                    if (!$group) {
+                        return;
+                    }
                     $users = groups_get_members($subwiki->groupid);
                     foreach ($users as $user) {
                         $options[$group->id][$group->name][$group->id . '-' . $user->id] = fullname($user);
-- 
1.7.9.5


From 06d38548b1e0c68d82f1486ea8c5349cfa851255 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 1 Aug 2012 09:05:32 +0800
Subject: [PATCH 305/903] MDL-34599 mod_quiz: optional $thispage & $nextpage

The previous change making the params required was a regression.
---
 mod/quiz/processattempt.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/quiz/processattempt.php b/mod/quiz/processattempt.php
index 9f391f0..aa4a171 100644
--- a/mod/quiz/processattempt.php
+++ b/mod/quiz/processattempt.php
@@ -38,8 +38,8 @@ $timenow = time();
 
 // Get submitted parameters.
 $attemptid     = required_param('attempt',  PARAM_INT);
-$thispage      = required_param('thispage', PARAM_INT);
-$nextpage      = required_param('nextpage', PARAM_INT);
+$thispage      = optional_param('thispage', 0, PARAM_INT);
+$nextpage      = optional_param('nextpage', 0, PARAM_INT);
 $next          = optional_param('next',          false, PARAM_BOOL);
 $finishattempt = optional_param('finishattempt', false, PARAM_BOOL);
 $timeup        = optional_param('timeup',        0,      PARAM_BOOL); // True if form was submitted by timer.
-- 
1.7.9.5


From 87a31bb5d8fedd4447cf99cef13c5dd367c3ea3e Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 1 Aug 2012 10:28:36 +0800
Subject: [PATCH 306/903] MDL-34444 course: show section availability info

When available, rather than a capability error.
---
 course/view.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/view.php b/course/view.php
index ad495dd..028a3f4 100644
--- a/course/view.php
+++ b/course/view.php
@@ -105,7 +105,7 @@
         $coursesections = $modinfo->get_section_info($section, MUST_EXIST);
 
         // Check user is allowed to see it.
-        if (!$coursesections->uservisible) {
+        if (!$coursesections->uservisible && !empty($section->availableinfo)) {
             // Note: We actually already know they don't have this capability
             // or uservisible would have been true; this is just to get the
             // correct error message shown.
-- 
1.7.9.5


From 4486aa99be864407bf75a0ceac87ebb36fc07638 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 1 Aug 2012 10:29:44 +0800
Subject: [PATCH 307/903] MDL-34444 course: Dont display links to hidden
 sections

This is what happens when you dont use the navigation api
---
 course/format/renderer.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index 1309025..165aea6 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -448,7 +448,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $links = array('previous' => '', 'next' => '');
         $back = $sectionno - 1;
         while ($back > 0 and empty($links['previous'])) {
-            if ($canviewhidden || $sections[$back]->visible) {
+            if ($canviewhidden || $sections[$back]->uservisible) {
                 $params = array();
                 if (!$sections[$back]->visible) {
                     $params = array('class' => 'dimmed_text');
@@ -462,7 +462,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         $forward = $sectionno + 1;
         while ($forward <= $course->numsections and empty($links['next'])) {
-            if ($canviewhidden || $sections[$forward]->visible) {
+            if ($canviewhidden || $sections[$forward]->uservisible) {
                 $params = array();
                 if (!$sections[$forward]->visible) {
                     $params = array('class' => 'dimmed_text');
-- 
1.7.9.5


From b093fd5e5a691b2b6f074bab39b91489a7a88cc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 1 Aug 2012 08:30:28 +0200
Subject: [PATCH 308/903] MDL-34368 fix another validuntil condition

---
 webservice/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/webservice/lib.php b/webservice/lib.php
index afba3a4..5a14d57 100644
--- a/webservice/lib.php
+++ b/webservice/lib.php
@@ -1612,7 +1612,7 @@ abstract class webservice_base_server extends webservice_server {
                   FROM {external_services} s
                   JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1 AND sf.functionname = :name2)
                   JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)
-                 WHERE s.enabled = 1 AND su.validuntil IS NULL OR su.validuntil < :now $wscond2";
+                 WHERE s.enabled = 1 AND (su.validuntil IS NULL OR su.validuntil < :now) $wscond2";
         $params = array_merge($params, array('userid'=>$USER->id, 'name1'=>$function->name, 'name2'=>$function->name, 'now'=>time()));
 
         $rs = $DB->get_recordset_sql($sql, $params);
-- 
1.7.9.5


From 8b9416de539eefdfdda8dc752ec18c0a6b6f66e1 Mon Sep 17 00:00:00 2001
From: Matt Switlik <switlik@oakland.edu>
Date: Wed, 1 Aug 2012 16:40:34 -0400
Subject: [PATCH 309/903] MDL-34691 assign: Time remaining "Assignment is
 overdue" was incorrectly being displayed when a
 student viewed a submitted assignment after the due
 date.

---
 mod/assign/renderer.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php
index 8ffe18f..3ca0232 100644
--- a/mod/assign/renderer.php
+++ b/mod/assign/renderer.php
@@ -420,7 +420,7 @@ class mod_assign_renderer extends plugin_renderer_base {
             $row = new html_table_row();
             $cell1 = new html_table_cell(get_string('timeremaining', 'assign'));
             if ($duedate - $time <= 0) {
-                if (!$status->submission || $status->submission != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
+                if (!$status->submission || $status->submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
                     if ($status->submissionsenabled) {
                         $cell2 = new html_table_cell(get_string('overdue', 'assign', format_time($time - $duedate)));
                         $cell2->attributes = array('class'=>'overdue');
-- 
1.7.9.5


From c91dc553e5f58660a5e758a9e21213b4b146e1ba Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 16 May 2012 12:04:55 +1200
Subject: [PATCH 310/903] MDL-33022 mod_form: set correct groupid when editing
 an existing post

---
 mod/forum/post.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/mod/forum/post.php b/mod/forum/post.php
index 20528d0..a71d7d1 100644
--- a/mod/forum/post.php
+++ b/mod/forum/post.php
@@ -627,6 +627,9 @@ if ($fromform = $mform_post->get_data()) {
 
         // If the user has access to all groups and they are changing the group, then update the post.
         if ($contextcheck) {
+            if (empty($fromform->groupinfo)) {
+                $fromform->groupinfo = -1;
+            }
             $DB->set_field('forum_discussions' ,'groupid' , $fromform->groupinfo, array('firstpost' => $fromform->id));
         }
 
-- 
1.7.9.5


From 709efab5273050b71ddff031977991bd44f9517f Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 2 Aug 2012 11:08:28 +0800
Subject: [PATCH 311/903] MDL-31599 block_news - incorrect RSS feed for guest
 user

Was previously using the userid 0, rather than guest to use
authenticated RSS feed.

Thanks to Paul Verrall at LUNS for helping me debug this.
---
 blocks/news_items/block_news_items.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/news_items/block_news_items.php b/blocks/news_items/block_news_items.php
index 6fcd152..24e9ca0 100644
--- a/blocks/news_items/block_news_items.php
+++ b/blocks/news_items/block_news_items.php
@@ -106,7 +106,7 @@ class block_news_items extends block_base {
                     $tooltiptext = get_string('rsssubscriberssposts','forum');
                 }
                 if (!isloggedin()) {
-                    $userid = 0;
+                    $userid = $CFG->siteguest;
                 } else {
                     $userid = $USER->id;
                 }
-- 
1.7.9.5


From 02814bfc185651fe683aecee972b93511b2c3fcc Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 2 Aug 2012 14:38:49 +0800
Subject: [PATCH 312/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index d073294..b4eb988 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.06;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.07;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120726)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120802)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 4a5e1f9d4bd79175cea7cf056c7db44609f763bf Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Thu, 19 Jul 2012 09:24:10 +0800
Subject: [PATCH 313/903] MDL-25983 enrol_imsenterprise Importing the course
 summary when adding new courses

---
 enrol/imsenterprise/lib.php |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/enrol/imsenterprise/lib.php b/enrol/imsenterprise/lib.php
index 284608a..073e76a 100644
--- a/enrol/imsenterprise/lib.php
+++ b/enrol/imsenterprise/lib.php
@@ -321,6 +321,9 @@ function process_group_tag($tagcontents) {
     if (preg_match('{<description>.*?<short>(.*?)</short>.*?</description>}is', $tagcontents, $matches)) {
         $group->shortName = trim($matches[1]);
     }
+    if (preg_match('{<description>.*?<full>(.*?)</full>.*?</description>}is', $tagcontents, $matches)) {
+        $group->fulldescription = trim($matches[1]);
+    }
     if (preg_match('{<org>.*?<orgunit>(.*?)</orgunit>.*?</org>}is', $tagcontents, $matches)) {
         $group->category = trim($matches[1]);
     }
@@ -376,7 +379,10 @@ function process_group_tag($tagcontents) {
                     $courseconfig = get_config('moodlecourse'); // Load Moodle Course shell defaults
                     $course = new stdClass();
                     $course->fullname = $group->description;
-                    $course->shortname = $group->shortName;;
+                    $course->shortname = $group->shortName;
+                    if (!empty($group->fulldescription)) {
+                        $course->summary = format_text($group->fulldescription, FORMAT_HTML);
+                    }
                     $course->idnumber = $coursecode;
                     $course->format = $courseconfig->format;
                     $course->visible = $courseconfig->visible;
-- 
1.7.9.5


From 56eda1f10a2c4ee481dd7a1717e8ec5307342e4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Mon, 30 Jul 2012 20:05:34 +0200
Subject: [PATCH 314/903] MDL-34635 support multilang in self enrol course
 welcome message

Includes also new help string for the custom multilang placeholders by Helen Foster.
---
 enrol/self/edit_form.php          |    3 ++-
 enrol/self/lang/en/enrol_self.php |    6 ++++++
 enrol/self/lib.php                |   28 +++++++++++++++++++---------
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/enrol/self/edit_form.php b/enrol/self/edit_form.php
index 5919d69..8b1461c 100644
--- a/enrol/self/edit_form.php
+++ b/enrol/self/edit_form.php
@@ -105,6 +105,7 @@ class enrol_self_edit_form extends moodleform {
         $mform->addHelpButton('customint4', 'sendcoursewelcomemessage', 'enrol_self');
 
         $mform->addElement('textarea', 'customtext1', get_string('customwelcomemessage', 'enrol_self'), array('cols'=>'60', 'rows'=>'8'));
+        $mform->addHelpButton('customtext1', 'customwelcomemessage', 'enrol_self');
 
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
@@ -176,4 +177,4 @@ class enrol_self_edit_form extends moodleform {
         }
         return $roles;
     }
-}
\ No newline at end of file
+}
diff --git a/enrol/self/lang/en/enrol_self.php b/enrol/self/lang/en/enrol_self.php
index af2c54c..5c96f78 100644
--- a/enrol/self/lang/en/enrol_self.php
+++ b/enrol/self/lang/en/enrol_self.php
@@ -25,6 +25,12 @@
  */
 
 $string['customwelcomemessage'] = 'Custom welcome message';
+$string['customwelcomemessage_help'] = 'A custom welcome message may be added as plain text or Moodle-auto format, including HTML tags and multi-lang tags.
+
+The following placeholders may be included in the message:
+
+* Course name {$a->coursename}
+* Link to user\'s profile page {$a->profileurl}';
 $string['defaultrole'] = 'Default role assignment';
 $string['defaultrole_desc'] = 'Select role which should be assigned to users during self enrolment';
 $string['editenrolment'] = 'Edit enrolment';
diff --git a/enrol/self/lib.php b/enrol/self/lib.php
index 32c9d48..771ec76 100644
--- a/enrol/self/lib.php
+++ b/enrol/self/lib.php
@@ -74,7 +74,7 @@ class enrol_self_plugin extends enrol_plugin {
 
         if (empty($instance->name)) {
             if (!empty($instance->roleid) and $role = $DB->get_record('role', array('id'=>$instance->roleid))) {
-                $role = ' (' . role_get_name($role, get_context_instance(CONTEXT_COURSE, $instance->courseid)) . ')';
+                $role = ' (' . role_get_name($role, context_course::instance($instance->courseid, IGNORE_MISSING)) . ')';
             } else {
                 $role = '';
             }
@@ -115,7 +115,7 @@ class enrol_self_plugin extends enrol_plugin {
              throw new coding_exception('Invalid enrol instance type!');
         }
 
-        $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+        $context = context_course::instance($instance->courseid);
         if (has_capability('enrol/self:config', $context)) {
             $managelink = new moodle_url('/enrol/self/edit.php', array('courseid'=>$instance->courseid, 'id'=>$instance->id));
             $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING);
@@ -133,7 +133,7 @@ class enrol_self_plugin extends enrol_plugin {
         if ($instance->enrol !== 'self') {
             throw new coding_exception('invalid enrol instance!');
         }
-        $context = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+        $context = context_course::instance($instance->courseid);
 
         $icons = array();
 
@@ -151,7 +151,7 @@ class enrol_self_plugin extends enrol_plugin {
      * @return moodle_url page url
      */
     public function get_newinstance_link($courseid) {
-        $context = get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST);
+        $context = context_course::instance($courseid, MUST_EXIST);
 
         if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/self:config', $context)) {
             return NULL;
@@ -267,22 +267,32 @@ class enrol_self_plugin extends enrol_plugin {
         global $CFG, $DB;
 
         $course = $DB->get_record('course', array('id'=>$instance->courseid), '*', MUST_EXIST);
+        $context = context_course::instance($course->id);
 
         $a = new stdClass();
-        $a->coursename = format_string($course->fullname);
+        $a->coursename = format_string($course->fullname, true, array('context'=>$context));
         $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id&course=$course->id";
 
         if (trim($instance->customtext1) !== '') {
             $message = $instance->customtext1;
             $message = str_replace('{$a->coursename}', $a->coursename, $message);
             $message = str_replace('{$a->profileurl}', $a->profileurl, $message);
+            if (strpos($message, '<') === false) {
+                // Plain text only.
+                $messagetext = $message;
+                $messagehtml = text_to_html($messagetext, null, false, true);
+            } else {
+                // This is most probably the tag/newline soup known as FORMAT_MOODLE.
+                $messagehtml = format_text($message, FORMAT_MOODLE, array('context'=>$context, 'para'=>false, 'newlines'=>true, 'filter'=>true));
+                $messagetext = html_to_text($messagehtml);
+            }
         } else {
-            $message = get_string('welcometocoursetext', 'enrol_self', $a);
+            $messagetext = get_string('welcometocoursetext', 'enrol_self', $a);
+            $messagehtml = text_to_html($messagetext, null, false, true);
         }
 
-        $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname));
+        $subject = get_string('welcometocourse', 'enrol_self', format_string($course->fullname, true, array('context'=>$context)));
 
-        $context = get_context_instance(CONTEXT_COURSE, $course->id);
         $rusers = array();
         if (!empty($CFG->coursecontact)) {
             $croles = explode(',', $CFG->coursecontact);
@@ -295,7 +305,7 @@ class enrol_self_plugin extends enrol_plugin {
         }
 
         //directly emailing welcome message rather than using messaging
-        email_to_user($user, $contact, $subject, $message);
+        email_to_user($user, $contact, $subject, $messagetext, $messagehtml);
     }
 
     /**
-- 
1.7.9.5


From 605d6ffcf4d04817078f781a98f99991e435040f Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Thu, 2 Aug 2012 19:49:28 +1200
Subject: [PATCH 315/903] MDL-33942 Grading method: Marking Guide - check for
 $cm before using - may not exist if the course is
 being deleted.

---
 grade/grading/form/guide/lib.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/grade/grading/form/guide/lib.php b/grade/grading/form/guide/lib.php
index 5672202..1990064 100644
--- a/grade/grading/form/guide/lib.php
+++ b/grade/grading/form/guide/lib.php
@@ -339,7 +339,9 @@ class gradingform_guide_controller extends gradingform_controller {
                 $modulename = substr($modulename, 4);
                 if ($dbman->table_exists($modulename)) {
                     $cm = get_coursemodule_from_id($modulename, $context->instanceid);
-                    $this->moduleinstance = $DB->get_record($modulename, array("id"=>$cm->instance));
+                    if (!empty($cm)) { // This should only occur when the course is being deleted.
+                        $this->moduleinstance = $DB->get_record($modulename, array("id"=>$cm->instance));
+                    }
                 }
             }
         }
-- 
1.7.9.5


From 137bd7a8b569f52ee20c2e5a34d7e9091b384822 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 27 Jul 2012 17:55:14 +0200
Subject: [PATCH 316/903] MDL-34601 drop legacy wiki upgrade tables

Next time please keep db in sync with install.xml at all times.
---
 mod/wiki/db/upgrade.php |   21 +++++++++++++++++++++
 mod/wiki/version.php    |    2 +-
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/mod/wiki/db/upgrade.php b/mod/wiki/db/upgrade.php
index 9925711..b528958 100644
--- a/mod/wiki/db/upgrade.php
+++ b/mod/wiki/db/upgrade.php
@@ -48,6 +48,27 @@ function xmldb_wiki_upgrade($oldversion) {
     // Moodle v2.3.0 release upgrade line
     // Put any upgrade step following this
 
+    if ($oldversion < 2012061701) {
+        // Drop all legacy upgrade tables, not used anymore.
+
+        $table = new xmldb_table('wiki_entries_old');
+        if ($dbman->table_exists('wiki_entries_old')) {
+            $dbman->drop_table($table);
+        }
+
+        $table = new xmldb_table('wiki_locks_old');
+        if ($dbman->table_exists('wiki_locks_old')) {
+            $dbman->drop_table($table);
+        }
+
+        $table = new xmldb_table('wiki_pages_old');
+        if ($dbman->table_exists('wiki_pages_old')) {
+            $dbman->drop_table($table);
+        }
+
+        upgrade_plugin_savepoint(true, 2012061701, 'mod', 'wiki');
+    }
+
 
     return true;
 }
diff --git a/mod/wiki/version.php b/mod/wiki/version.php
index db01d62..0c22ff3 100644
--- a/mod/wiki/version.php
+++ b/mod/wiki/version.php
@@ -33,7 +33,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700;    // Requires this Moodle version
 $module->component = 'mod_wiki';       // Full name of the plugin (used for diagnostics)
 $module->cron      = 0;
-- 
1.7.9.5


From 3a933cdf101226f5ea5bd90d1567535ee23828dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 31 Jul 2012 16:02:54 +0200
Subject: [PATCH 317/903] MDL-34585 fix broken blog file access control

---
 lib/filelib.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index 3b2d453..4f60f3c 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -3471,15 +3471,15 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
             }
         }
 
-        if ('publishstate' === 'public') {
+        if ($entry->publishstate === 'public') {
             if ($CFG->forcelogin) {
                 require_login();
             }
 
-        } else if ('publishstate' === 'site') {
+        } else if ($entry->publishstate === 'site') {
             require_login();
             //ok
-        } else if ('publishstate' === 'draft') {
+        } else if ($entry->publishstate === 'draft') {
             require_login();
             if ($USER->id != $entry->userid) {
                 send_file_not_found();
-- 
1.7.9.5


From 46c770079d272cc1837565ee8a53194f4f76eb90 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 2 Aug 2012 17:44:43 +0100
Subject: [PATCH 318/903] MDL-34705 role assignments list: should link to
 contexts.

This will make Admin's lives a bit easier.
---
 admin/roles/usersroles.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/admin/roles/usersroles.php b/admin/roles/usersroles.php
index 968f025..3ac05f9 100644
--- a/admin/roles/usersroles.php
+++ b/admin/roles/usersroles.php
@@ -166,7 +166,8 @@ function print_report_tree($contextid, $contexts, $systemcontext, $fullname) {
     $context = context::instance_by_id($contextid);
 
     // Print the context name.
-    echo $OUTPUT->heading($context->get_context_name(), 4, 'contextname');
+    echo $OUTPUT->heading(html_writer::link($context->get_url(), $context->get_context_name()),
+            4, 'contextname');
 
     // If there are any role assignments here, print them.
     foreach ($contexts[$contextid]->roleassignments as $ra) {
@@ -189,7 +190,7 @@ function print_report_tree($contextid, $contexts, $systemcontext, $fullname) {
             }
             $a = new stdClass;
             $a->fullname = $fullname;
-            $a->contextlevel = get_contextlevel_name($context->contextlevel);
+            $a->contextlevel = $context->get_level_name();
             if ($context->contextlevel == CONTEXT_SYSTEM) {
                 $strgoto = get_string('gotoassignsystemroles', 'role');
                 $strcheck = get_string('checksystempermissionsfor', 'role', $a);
-- 
1.7.9.5


From 7d45268bc600671b1d50396a79b98914b44c31ab Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 2 Aug 2012 18:40:49 +0100
Subject: [PATCH 319/903] MDL-34707 backup UI: only include the JS once.

---
 backup/util/ui/base_moodleform.class.php |   20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/backup/util/ui/base_moodleform.class.php b/backup/util/ui/base_moodleform.class.php
index e0ffc0f..3a72edc 100644
--- a/backup/util/ui/base_moodleform.class.php
+++ b/backup/util/ui/base_moodleform.class.php
@@ -96,7 +96,6 @@ abstract class base_moodleform extends moodleform {
      * @global moodle_page $PAGE
      */
     function definition_after_data() {
-        global $PAGE;
         $buttonarray=array();
         $buttonarray[] = $this->_form->createElement('submit', 'submitbutton', get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'), array('class'=>'proceedbutton'));
         if (!$this->uistage->is_first_stage()) {
@@ -106,13 +105,9 @@ abstract class base_moodleform extends moodleform {
         $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
         $this->_form->closeHeaderBefore('buttonar');
 
-        $config = new stdClass;
-        $config->title = get_string('confirmcancel', 'backup');
-        $config->question = get_string('confirmcancelquestion', 'backup');
-        $config->yesLabel = get_string('confirmcancelyes', 'backup');
-        $config->noLabel = get_string('confirmcancelno', 'backup');
-        $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+        $this->_definition_finalized = true;
     }
+
     /**
      * Closes any open divs
      */
@@ -318,7 +313,17 @@ abstract class base_moodleform extends moodleform {
      * Displays the form
      */
     public function display() {
+        global $PAGE;
+
         $this->require_definition_after_data();
+
+        $config = new stdClass;
+        $config->title = get_string('confirmcancel', 'backup');
+        $config->question = get_string('confirmcancelquestion', 'backup');
+        $config->yesLabel = get_string('confirmcancelyes', 'backup');
+        $config->noLabel = get_string('confirmcancelno', 'backup');
+        $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+
         parent::display();
     }
 
@@ -327,7 +332,6 @@ abstract class base_moodleform extends moodleform {
      */
     public function require_definition_after_data() {
         if (!$this->_definition_finalized) {
-            $this->_definition_finalized = true;
             $this->definition_after_data();
         }
     }
-- 
1.7.9.5


From 84af4013c136c8b4e306a87d2228c4cf6df5975c Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 18 Jul 2012 14:21:16 +0800
Subject: [PATCH 320/903] MDL-28207 Course: Showing/hiding/marking a section
 respect capabilities

---
 course/format/renderer.php        |   36 ++++++++++++++++++------------------
 course/format/topics/renderer.php |   30 +++++++++++++++---------------
 course/rest.php                   |    5 +++--
 course/view.php                   |    4 +++-
 4 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index 1309025..ea88504 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -205,9 +205,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
             return array();
         }
 
-        if (!has_capability('moodle/course:update', context_course::instance($course->id))) {
-            return array();
-        }
+        $coursecontext = context_course::instance($course->id);
 
         if ($onsectionpage) {
             $baseurl = course_get_url($course, $section->section);
@@ -219,23 +217,25 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $controls = array();
 
         $url = clone($baseurl);
-        if ($section->visible) { // Show the hide/show eye.
-            $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
-            $url->param('hide', $section->section);
-            $controls[] = html_writer::link($url,
-                html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/hide'),
-                'class' => 'icon hide', 'alt' => $strhidefromothers)),
-                array('title' => $strhidefromothers, 'class' => 'editing_showhide'));
-        } else {
-            $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
-            $url->param('show',  $section->section);
-            $controls[] = html_writer::link($url,
-                html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/show'),
-                'class' => 'icon hide', 'alt' => $strshowfromothers)),
-                array('title' => $strshowfromothers, 'class' => 'editing_showhide'));
+        if (has_capability('moodle/course:sectionvisibility', $coursecontext)) {
+            if ($section->visible) { // Show the hide/show eye.
+                $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
+                $url->param('hide', $section->section);
+                $controls[] = html_writer::link($url,
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/hide'),
+                    'class' => 'icon hide', 'alt' => $strhidefromothers)),
+                    array('title' => $strhidefromothers, 'class' => 'editing_showhide'));
+            } else {
+                $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
+                $url->param('show',  $section->section);
+                $controls[] = html_writer::link($url,
+                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/show'),
+                    'class' => 'icon hide', 'alt' => $strshowfromothers)),
+                    array('title' => $strshowfromothers, 'class' => 'editing_showhide'));
+            }
         }
 
-        if (!$onsectionpage) {
+        if (!$onsectionpage && has_capability('moodle/course:update', $coursecontext)) {
             $url = clone($baseurl);
             if ($section->section > 1) { // Add a arrow to move section up.
                 $url->param('section', $section->section);
diff --git a/course/format/topics/renderer.php b/course/format/topics/renderer.php
index 5ef126f..e293a9d 100644
--- a/course/format/topics/renderer.php
+++ b/course/format/topics/renderer.php
@@ -74,9 +74,7 @@ class format_topics_renderer extends format_section_renderer_base {
             return array();
         }
 
-        if (!has_capability('moodle/course:update', context_course::instance($course->id))) {
-            return array();
-        }
+        $coursecontext = context_course::instance($course->id);
 
         if ($onsectionpage) {
             $url = course_get_url($course, $section->section);
@@ -86,18 +84,20 @@ class format_topics_renderer extends format_section_renderer_base {
         $url->param('sesskey', sesskey());
 
         $controls = array();
-        if ($course->marker == $section->section) {  // Show the "light globe" on/off.
-            $url->param('marker', 0);
-            $controls[] = html_writer::link($url,
-                                html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marked'),
-                                    'class' => 'icon ', 'alt' => get_string('markedthistopic'))),
-                                array('title' => get_string('markedthistopic'), 'class' => 'editing_highlight'));
-        } else {
-            $url->param('marker', $section->section);
-            $controls[] = html_writer::link($url,
-                            html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marker'),
-                                'class' => 'icon', 'alt' => get_string('markthistopic'))),
-                            array('title' => get_string('markthistopic'), 'class' => 'editing_highlight'));
+        if (has_capability('moodle/course:setcurrentsection', $coursecontext)) {
+            if ($course->marker == $section->section) {  // Show the "light globe" on/off.
+                $url->param('marker', 0);
+                $controls[] = html_writer::link($url,
+                                    html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marked'),
+                                        'class' => 'icon ', 'alt' => get_string('markedthistopic'))),
+                                    array('title' => get_string('markedthistopic'), 'class' => 'editing_highlight'));
+            } else {
+                $url->param('marker', $section->section);
+                $controls[] = html_writer::link($url,
+                                html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/marker'),
+                                    'class' => 'icon', 'alt' => get_string('markthistopic'))),
+                                array('title' => get_string('markthistopic'), 'class' => 'editing_highlight'));
+            }
         }
 
         return array_merge($controls, parent::section_edit_controls($course, $section, $onsectionpage));
diff --git a/course/rest.php b/course/rest.php
index 6efd228..61392ea 100644
--- a/course/rest.php
+++ b/course/rest.php
@@ -75,7 +75,6 @@ switch($requestmethod) {
 
         switch ($class) {
             case 'section':
-                require_capability('moodle/course:update', $coursecontext);
 
                 if (!$DB->record_exists('course_sections', array('course'=>$course->id, 'section'=>$id))) {
                     throw new moodle_exception('AJAX commands.php: Bad Section ID '.$id);
@@ -83,11 +82,13 @@ switch($requestmethod) {
 
                 switch ($field) {
                     case 'visible':
+                        require_capability('moodle/course:sectionvisibility', $coursecontext);
                         $resourcestotoggle = set_section_visible($course->id, $id, $value);
                         echo json_encode(array('resourcestotoggle' => $resourcestotoggle));
                         break;
 
                     case 'move':
+                        require_capability('moodle/course:update', $coursecontext);
                         move_section_to($course, $id, $value);
                         // See if format wants to do something about it
                         $libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php';
@@ -178,7 +179,7 @@ switch($requestmethod) {
             case 'course':
                 switch($field) {
                     case 'marker':
-                        require_capability('moodle/course:update', $coursecontext);
+                        require_capability('moodle/course:setcurrentsection', $coursecontext);
                         course_set_marker($course->id, $value);
                         break;
                 }
diff --git a/course/view.php b/course/view.php
index ad495dd..c750205 100644
--- a/course/view.php
+++ b/course/view.php
@@ -162,7 +162,7 @@
             set_user_preference('usemodchooser', $modchooser);
         }
 
-        if (has_capability('moodle/course:update', $context)) {
+        if (has_capability('moodle/course:sectionvisibility', $context)) {
             if ($hide && confirm_sesskey()) {
                 set_section_visible($course->id, $hide, '0');
                 redirect($PAGE->url);
@@ -172,7 +172,9 @@
                 set_section_visible($course->id, $show, '1');
                 redirect($PAGE->url);
             }
+        }
 
+        if (has_capability('moodle/course:update', $context)) {
             if (!empty($section)) {
                 if (!empty($move) and confirm_sesskey()) {
                     $destsection = $section + $move;
-- 
1.7.9.5


From 6ce946c561670d33bae68829fdf3f5c54be95f68 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 26 Jul 2012 16:36:20 +0800
Subject: [PATCH 321/903] MDL-34259 Lesson: True/false questions don't break
 on missing answer

---
 mod/lesson/pagetypes/truefalse.php |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/mod/lesson/pagetypes/truefalse.php b/mod/lesson/pagetypes/truefalse.php
index 8566244..61306ab 100644
--- a/mod/lesson/pagetypes/truefalse.php
+++ b/mod/lesson/pagetypes/truefalse.php
@@ -76,12 +76,11 @@ class lesson_page_type_truefalse extends lesson_page {
 
         $result = parent::check_answer();
 
-        $answerid = $data->answerid;
-        if ($answerid === false) {
+        if (empty($data->answerid)) {
             $result->noanswer = true;
             return $result;
         }
-        $result->answerid = $answerid;
+        $result->answerid = $data->answerid;
         $answer = $DB->get_record("lesson_answers", array("id" => $result->answerid), '*', MUST_EXIST);
         if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) {
             $result->correctanswer = true;
-- 
1.7.9.5


From e9ec895d926b55cc4fb7b141a780026f1364ee73 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 12 Jul 2012 09:39:52 +0800
Subject: [PATCH 322/903] MDL-28531 Backup: Automated backups run when they
 are scheduled

---
 backup/util/helper/backup_cron_helper.class.php |   70 +++--
 lib/moodlelib.php                               |    4 +-
 lib/tests/backup_test.php                       |  336 ++++++++++++++++++++---
 3 files changed, 344 insertions(+), 66 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 00db13d..353d451 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -110,7 +110,7 @@ abstract class backup_cron_automated_helper {
             $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
             $showtime = "undefined";
             if ($nextstarttime > 0) {
-                $showtime = userdate($nextstarttime,"",$admin->timezone);
+                $showtime = date('r', $nextstarttime);
             }
 
             $rs = $DB->get_recordset('course');
@@ -124,7 +124,14 @@ abstract class backup_cron_automated_helper {
                 }
 
                 // Skip courses that do not yet need backup
-                $skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                $skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                if ($skipped && $backupcourse->nextstarttime != $nextstarttime) {
+                    $backupcourse->nextstarttime = $nextstarttime;
+                    $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+                    $DB->update_record('backup_courses', $backupcourse);
+                    mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
+                }
+
                 // Skip backup of unavailable courses that have remained unmodified in a month
                 if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + settings were unmodified last month
                     //Check log if there were any modifications to the course content
@@ -139,9 +146,10 @@ abstract class backup_cron_automated_helper {
                         $skipped = true;
                     }
                 }
+
                 //Now we backup every non-skipped course
                 if (!$skipped) {
-                    mtrace('Backing up '.$course->fullname, '...');
+                    mtrace('Backing up '.$course->fullname.'...');
 
                     //We have to send a email because we have included at least one backup
                     $emailpending = true;
@@ -270,38 +278,47 @@ abstract class backup_cron_automated_helper {
     /**
      * Works out the next time the automated backup should be run.
      *
-     * @param mixed $timezone
-     * @param int $now
-     * @return int
+     * @param mixed $timezone user timezone
+     * @param int $now timestamp, should not be in the past, most likely time()
+     * @return int timestamp of the next execution at server time
      */
     public static function calculate_next_automated_backup($timezone, $now) {
 
-        $result = -1;
+        $result = 0;
         $config = get_config('backup');
-        $midnight = usergetmidnight($now, $timezone);
+        $autohour = $config->backup_auto_hour;
+        $automin = $config->backup_auto_minute;
+
+        // Gets the user time relatively to the server time.
         $date = usergetdate($now, $timezone);
+        $usertime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
+        $diff = $now - $usertime;
 
-        // Get number of days (from today) to execute backups
+        // Get number of days (from user's today) to execute backups.
         $automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
-        $daysfromtoday = strpos($automateddays, "1", 1);
+        $daysfromnow = strpos($automateddays, "1");
 
-        // If we can't find the next day, we set it to tomorrow
-        if (empty($daysfromtoday)) {
-            $daysfromtoday = 1;
+        // Error, there are no days to schedule the backup for.
+        if ($daysfromnow === false) {
+            return 0;
         }
 
-        // If some day has been found
-        if ($daysfromtoday !== false) {
-            // Calculate distance
-            $dist = ($daysfromtoday * 86400) +                // Days distance
-                    ($config->backup_auto_hour * 3600) +      // Hours distance
-                    ($config->backup_auto_minute * 60);       // Minutes distance
-            $result = $midnight + $dist;
+        // Checks if the date would happen in the future (of the user).
+        $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
+        if ($userresult <= $usertime) {
+            // If not, we skip the first scheduled day, that should fix it.
+            $daysfromnow = strpos($automateddays, "1", 1);
+            $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
         }
 
-        // If that time is past, call the function recursively to obtain the next valid day
-        if ($result > 0 && $result < time()) {
-            $result = self::calculate_next_automated_backup($timezone, $result);
+        // Now we generate the time relative to the server.
+        $result = $userresult + $diff;
+
+        // If that time is past, call the function recursively to obtain the next valid day.
+        if ($result <= $now) {
+            // Checking time() in here works, but makes PHPUnit Tests extremely hard to predict.
+            // $now should never be earlier than time() anyway...
+            $result = self::calculate_next_automated_backup($timezone, $now + DAYSECS);
         }
 
         return $result;
@@ -411,7 +428,12 @@ abstract class backup_cron_automated_helper {
 
         $config = get_config('backup');
         $active = (int)$config->backup_auto_active;
-        if ($active === self::AUTO_BACKUP_DISABLED || ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL)) {
+        $weekdays = (string)$config->backup_auto_weekdays;
+
+        // In case of automated backup also check that it is scheduled for at least one weekday.
+        if ($active === self::AUTO_BACKUP_DISABLED ||
+                ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL) ||
+                ($rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false)) {
             return self::STATE_DISABLED;
         } else if (!empty($config->backup_auto_running)) {
             // Detect if the backup_auto_running semaphore is a valid one
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 6591795..5cf0b7e 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -2324,10 +2324,10 @@ function get_user_timezone($tz = 99) {
 
     $tz = 99;
 
-    while(($tz == '' || $tz == 99 || $tz == NULL) && $next = each($timezones)) {
+    // Loop while $tz is, empty but not zero, or 99, and there is another timezone is the array
+    while(((empty($tz) && !is_numeric($tz)) || $tz == 99) && $next = each($timezones)) {
         $tz = $next['value'];
     }
-
     return is_numeric($tz) ? (float) $tz : $tz;
 }
 
diff --git a/lib/tests/backup_test.php b/lib/tests/backup_test.php
index 1830f56..5b44435 100644
--- a/lib/tests/backup_test.php
+++ b/lib/tests/backup_test.php
@@ -36,149 +36,405 @@ class backup_testcase extends advanced_testcase {
     public function test_next_automated_backup() {
 
         $this->resetAfterTest();
-        $admin = get_admin();
-        $timezone = $admin->timezone;
+        set_config('backup_auto_active', '1', 'backup');
 
         // Notes
-        // - The next automated backup will never be on the same date than $now
         // - backup_auto_weekdays starts on Sunday
-        // - Tests cannot be done in the past.
+        // - Tests cannot be done in the past
+        // - Only the DST on the server side is handled.
 
-        // Every Wed and Sat at 11pm.
-        set_config('backup_auto_active', '1', 'backup');
+        // Every Tue and Fri at 11pm.
         set_config('backup_auto_weekdays', '0010010', 'backup');
         set_config('backup_auto_hour', '23', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 18:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
         // Every Sun and Sat at 12pm.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000001', 'backup');
         set_config('backup_auto_hour', '0', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
         // Every Sun at 4am.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000000', 'backup');
         set_config('backup_auto_hour', '4', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
         // Every day but Wed at 8:30pm.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1110111', 'backup');
         set_config('backup_auto_hour', '20', 'backup');
         set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        // Sun, Tue, Thu, Sat at 12pm.
+        set_config('backup_auto_weekdays', '1010101', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 13:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('1-20:30', date('w-H:i', $next));
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        // None.
+        set_config('backup_auto_weekdays', '0000000', 'backup');
+        set_config('backup_auto_hour', '15', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0', $next);
+
+        // Playing with timezones.
+        set_config('backup_auto_weekdays', '1111111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        $timezone = 99;
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        // Viva Australia! (UTC+8).
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+
+        $timezone = -10.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = -5.0; // 5am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 0.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 3.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 8.0; // 6pm for the user (same than the server).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 9.0; // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
+
+        $timezone = 13.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-21:00') : date('w-22:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 1am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // The big apple! (UTC-5 / UTC-4 DST).
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 6pm for the user (server time).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-20:00') : date('w-21:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 11pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('next Monday 18:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-09:00' : '2-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-01:00' : '2-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-21:00' : '1-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-19:00' : '1-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 9pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-17:00' : '6-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-09:00' : '6-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '02', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('next Monday 04:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-09:00' : '1-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 4am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-01:00' : '6-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-21:00' : '5-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-19:00' : '5-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-17:00' : '5-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-09:00' : '5-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
 
     }
 }
-- 
1.7.9.5


From d3e1371030b2959187e972502a8249c889f841de Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Wed, 18 Jul 2012 16:33:18 +0800
Subject: [PATCH 323/903] MDL-30792 Files API: maxbytes will be set by
 get_max_upload_file_size if less then 0 or greater
 then max moodle limit

---
 repository/filepicker.php      |    4 ++--
 repository/repository_ajax.php |    9 ++++++---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/repository/filepicker.php b/repository/filepicker.php
index 73970d6..568cd6d 100644
--- a/repository/filepicker.php
+++ b/repository/filepicker.php
@@ -89,9 +89,9 @@ if ($repo_id) {
 }
 
 $context = context::instance_by_id($contextid);
-$moodle_maxbytes = get_user_max_upload_file_size($context);
+$moodle_maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $course->maxbytes);
 // to prevent maxbytes greater than moodle maxbytes setting
-if ($maxbytes == 0 || $maxbytes>=$moodle_maxbytes) {
+if (($maxbytes <= 0) || ($maxbytes >= $moodle_maxbytes)) {
     $maxbytes = $moodle_maxbytes;
 }
 
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index 2452158..ed159e5 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -78,10 +78,13 @@ $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
 
 // Check permissions
 $repo->check_capability();
-
-$moodle_maxbytes = get_user_max_upload_file_size($context);
+$coursemaxbytes = 0;
+if (!empty($course)) {
+    $coursemaxbytes = $course->maxbytes;
+}
+$moodle_maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $coursemaxbytes);
 // to prevent maxbytes greater than moodle maxbytes setting
-if ($maxbytes == 0 || $maxbytes>=$moodle_maxbytes) {
+if (($maxbytes <= 0) || ($maxbytes >= $moodle_maxbytes)) {
     $maxbytes = $moodle_maxbytes;
 }
 
-- 
1.7.9.5


From 6ecbacac00fdaccb5757feb0a7a96d4928370c7e Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 3 Aug 2012 11:20:55 +0800
Subject: [PATCH 324/903] MDL-30792 Files API: Cleaner approach to get
 maxbytes size in filepicker

---
 lib/moodlelib.php              |    6 +++---
 repository/filepicker.php      |    8 +++-----
 repository/repository_ajax.php |    8 +++-----
 3 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 6591795..910f899 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -5842,15 +5842,15 @@ function get_max_upload_file_size($sitebytes=0, $coursebytes=0, $modulebytes=0)
         }
     }
 
-    if ($sitebytes and $sitebytes < $minimumsize) {
+    if (($sitebytes > 0) and ($sitebytes < $minimumsize)) {
         $minimumsize = $sitebytes;
     }
 
-    if ($coursebytes and $coursebytes < $minimumsize) {
+    if (($coursebytes > 0) and ($coursebytes < $minimumsize)) {
         $minimumsize = $coursebytes;
     }
 
-    if ($modulebytes and $modulebytes < $minimumsize) {
+    if (($modulebytes > 0) and ($modulebytes < $minimumsize)) {
         $minimumsize = $modulebytes;
     }
 
diff --git a/repository/filepicker.php b/repository/filepicker.php
index 568cd6d..fd16e66 100644
--- a/repository/filepicker.php
+++ b/repository/filepicker.php
@@ -89,11 +89,9 @@ if ($repo_id) {
 }
 
 $context = context::instance_by_id($contextid);
-$moodle_maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $course->maxbytes);
-// to prevent maxbytes greater than moodle maxbytes setting
-if (($maxbytes <= 0) || ($maxbytes >= $moodle_maxbytes)) {
-    $maxbytes = $moodle_maxbytes;
-}
+
+// Make sure maxbytes passed is within site filesize limits.
+$maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $course->maxbytes, $maxbytes);
 
 $params = array('ctx_id' => $contextid, 'itemid' => $itemid, 'env' => $env, 'course'=>$courseid, 'maxbytes'=>$maxbytes, 'maxfiles'=>$maxfiles, 'subdirs'=>$subdirs, 'sesskey'=>sesskey());
 $params['action'] = 'browse';
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index ed159e5..98701a5 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -78,15 +78,13 @@ $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
 
 // Check permissions
 $repo->check_capability();
+
 $coursemaxbytes = 0;
 if (!empty($course)) {
     $coursemaxbytes = $course->maxbytes;
 }
-$moodle_maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $coursemaxbytes);
-// to prevent maxbytes greater than moodle maxbytes setting
-if (($maxbytes <= 0) || ($maxbytes >= $moodle_maxbytes)) {
-    $maxbytes = $moodle_maxbytes;
-}
+// Make sure maxbytes passed is within site filesize limits.
+$maxbytes = get_user_max_upload_file_size($context, $CFG->maxbytes, $coursemaxbytes, $maxbytes);
 
 // Wait as long as it takes for this script to finish
 set_time_limit(0);
-- 
1.7.9.5


From daeee0afae63e267975b69b8a041d1416d55fac6 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:47:17 +0800
Subject: [PATCH 325/903] MDL-34557 accessibility compliance for enrol: Add
 forform input text and select tag

---
 enrol/authorize/locallib.php |    4 +++-
 enrol/manual/manage.php      |    6 +++---
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/enrol/authorize/locallib.php b/enrol/authorize/locallib.php
index 058b1b0..9708408 100644
--- a/enrol/authorize/locallib.php
+++ b/enrol/authorize/locallib.php
@@ -58,8 +58,10 @@ function authorize_print_orders($courseid, $userid) {
 
     $searchmenu = array('orderid' => $authstrs->orderid, 'transid' => $authstrs->transid, 'cclastfour' => $authstrs->cclastfour);
     $buttons = "<form method='post' action='index.php' autocomplete='off'><div>";
+    $buttons .= html_writer::label(get_string('orderdetails', 'enrol_authorize'), 'menusearchtype', false, array('class' => 'accesshide'));
     $buttons .= html_writer::select($searchmenu, 'searchtype', $searchtype, false);
-    $buttons .= "<input type='text' size='16' name='searchquery' value='' />";
+    $buttons .= html_writer::label(get_string('search'), 'searchquery', false, array('class' => 'accesshide'));
+    $buttons .= "<input id='searchquery' type='text' size='16' name='searchquery' value='' />";
     $buttons .= "<input type='submit' value='$strs->search' />";
     $buttons .= "</div></form>";
 
diff --git a/enrol/manual/manage.php b/enrol/manual/manage.php
index 94fdc63..f7ea7e2 100644
--- a/enrol/manual/manage.php
+++ b/enrol/manual/manage.php
@@ -162,13 +162,13 @@ echo $OUTPUT->heading($instancename);
 
               <div class="enroloptions">
 
-              <p><label for="roleid"><?php print_string('assignrole', 'enrol_manual') ?></label><br />
+              <p><label for="menuroleid"><?php print_string('assignrole', 'enrol_manual') ?></label><br />
               <?php echo html_writer::select($roles, 'roleid', $roleid, false); ?></p>
 
-              <p><label for="extendperiod"><?php print_string('enrolperiod', 'enrol') ?></label><br />
+              <p><label for="menuextendperiod"><?php print_string('enrolperiod', 'enrol') ?></label><br />
               <?php echo html_writer::select($periodmenu, 'extendperiod', $defaultperiod, $unlimitedperiod); ?></p>
 
-              <p><label for="extendbase"><?php print_string('startingfrom') ?></label><br />
+              <p><label for="menuextendbase"><?php print_string('startingfrom') ?></label><br />
               <?php echo html_writer::select($basemenu, 'extendbase', $extendbase, false); ?></p>
 
               </div>
-- 
1.7.9.5


From f81c3a32f0e60acf73534854318e467963814799 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:47:27 +0800
Subject: [PATCH 326/903] MDL-34558 accessibility compliance for filter: Add
 forform input text and select tag

---
 filter/algebra/algebradebug.php           |    3 ++-
 filter/algebra/lang/en/filter_algebra.php |    1 +
 filter/manage.php                         |    5 ++++-
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/filter/algebra/algebradebug.php b/filter/algebra/algebradebug.php
index 67b715c..bdf6ac4 100644
--- a/filter/algebra/algebradebug.php
+++ b/filter/algebra/algebradebug.php
@@ -280,7 +280,8 @@ function slasharguments($texexp, $md5) {
           <form action="algebradebug.php" method="get"
            target="inlineframe">
             <center>
-             <input type="text" name="algebra" size="50"
+             <label for="algebra" class="accesshide"><?php print_string('algebraicexpression', 'filter_algebra'); ?></label>
+             <input type="text" id="algebra" name="algebra" size="50"
                     value="sin(z)/(x^2+y^2)" />
             </center>
            <ol>
diff --git a/filter/algebra/lang/en/filter_algebra.php b/filter/algebra/lang/en/filter_algebra.php
index 5435f7f..6db42a1 100644
--- a/filter/algebra/lang/en/filter_algebra.php
+++ b/filter/algebra/lang/en/filter_algebra.php
@@ -24,3 +24,4 @@
  */
 
 $string['filtername'] = 'Algebra notation';
+$string['algebraicexpression'] = 'Algebraic expression';
diff --git a/filter/manage.php b/filter/manage.php
index 943c7fc..04893f1 100644
--- a/filter/manage.php
+++ b/filter/manage.php
@@ -181,7 +181,10 @@ if (empty($availablefilters)) {
         } else {
             $activechoices[TEXTFILTER_INHERIT] = $strdefaultoff;
         }
-        $row[] = html_writer::select($activechoices, str_replace('/', '_', $filter), $filterinfo->localstate, false);
+        $filtername = str_replace('/', '_', $filter);
+        $select = html_writer::label($filterinfo->localstate, 'menu'. $filtername, false, array('class' => 'accesshide'));
+        $select .= html_writer::select($activechoices, $filtername, $filterinfo->localstate, false);
+        $row[] = $select;
 
         // Settings link, if required
         if ($settingscol) {
-- 
1.7.9.5


From aa15bd56d6398ebd7e5eb51e6958931534663248 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:47:36 +0800
Subject: [PATCH 327/903] MDL-34559 accessibility compliance for grade: Add
 forform input text and select tag

---
 grade/edit/tree/calculation.php        |    1 +
 grade/edit/tree/index.php              |    2 +-
 grade/edit/tree/lib.php                |    3 ++-
 grade/grading/form/rubric/renderer.php |    7 ++++---
 grade/lib.php                          |    2 +-
 grade/report/grader/lib.php            |    3 ++-
 6 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/grade/edit/tree/calculation.php b/grade/edit/tree/calculation.php
index 89d5cd2..a18d0c1 100644
--- a/grade/edit/tree/calculation.php
+++ b/grade/edit/tree/calculation.php
@@ -184,6 +184,7 @@ function get_grade_tree(&$gtree, $element, $current_itemid=null, $errors=null) {
                     $name .= '<div class="error"><span class="error">' . $errors[$grade_item->id].'</span><br />'."\n";
                     $closingdiv = "</div>\n";
                 }
+                $name .= '<label class="accesshide" for="id_idnumber_' . $grade_item->id . '">' . get_string('gradeitems', 'grades')  .'</label>';
                 $name .= '<input class="idnumber" id="id_idnumber_'.$grade_item->id.'" type="text" name="idnumbers['.$grade_item->id.']" />' . "\n";
                 $name .= $closingdiv;
             }
diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index 801c9ef..b044fe0 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -342,8 +342,8 @@ if (!$moving) {
 if (!$moving && count($grade_edit_tree->categories) > 1) {
     echo '<br /><br />';
     echo '<input type="hidden" name="bulkmove" value="0" id="bulkmoveinput" />';
-    echo get_string('moveselectedto', 'grades') . ' ';
     $attributes = array('id'=>'menumoveafter');
+    echo html_writer::label(get_string('moveselectedto', 'grades'), 'menumoveafter', false, array('class' => 'accesshide'));
     echo html_writer::select($grade_edit_tree->categories, 'moveafter', '', array(''=>'choosedots'), $attributes);
     $OUTPUT->add_action_handler(new component_action('change', 'submit_bulk_move'), 'menumoveafter');
     echo '<div id="noscriptgradetreeform" class="hiddenifjs">
diff --git a/grade/edit/tree/lib.php b/grade/edit/tree/lib.php
index eee8664..2bc2dc7 100644
--- a/grade/edit/tree/lib.php
+++ b/grade/edit/tree/lib.php
@@ -673,7 +673,8 @@ class grade_edit_tree_column_aggregation extends grade_edit_tree_column_category
         } else {
             $attributes = array();
             $attributes['id'] = 'aggregation_'.$category->id;
-            $aggregation = html_writer::select($options, 'aggregation_'.$category->id, $category->aggregation, null, $attributes);
+            $aggregation = html_writer::label(get_string('aggregation', 'grades'), 'aggregation_'.$category->id, false, array('class' => 'accesshide'));
+            $aggregation .= html_writer::select($options, 'aggregation_'.$category->id, $category->aggregation, null, $attributes);
             $action = new component_action('change', 'update_category_aggregation', array('courseid' => $params['id'], 'category' => $category->id, 'sesskey' => sesskey()));
             $OUTPUT->add_action_handler($action, 'aggregation_'.$category->id);
         }
diff --git a/grade/grading/form/rubric/renderer.php b/grade/grading/form/rubric/renderer.php
index 9469e94..c269c0a 100644
--- a/grade/grading/form/rubric/renderer.php
+++ b/grade/grading/form/rubric/renderer.php
@@ -164,7 +164,8 @@ class gradingform_rubric_renderer extends plugin_renderer_base {
         $leveltemplate .= html_writer::start_tag('div', array('class' => 'level-wrapper'));
         if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
             $definition = html_writer::tag('textarea', htmlspecialchars($level['definition']), array('name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'cols' => '10', 'rows' => '4'));
-            $score = html_writer::empty_tag('input', array('type' => 'text', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
+            $score = html_writer::label(get_string('criterionempty', 'gradingform_rubric'), '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', false, array('class' => 'accesshide'));
+            $score .= html_writer::empty_tag('input', array('type' => 'text','id' => '{NAME}criteria{CRITERION-id}levels{LEVEL-id}', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][score]', 'size' => '3', 'value' => $level['score']));
         } else {
             if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FROZEN) {
                 $leveltemplate .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => '{NAME}[criteria][{CRITERION-id}][levels][{LEVEL-id}][definition]', 'value' => $level['definition']));
@@ -290,7 +291,7 @@ class gradingform_rubric_renderer extends plugin_renderer_base {
             switch ($option) {
                 case 'sortlevelsasc':
                     // Display option as dropdown
-                    $html .= html_writer::tag('span', get_string($option, 'gradingform_rubric'), array('class' => 'label'));
+                    $html .= html_writer::label(get_string($option, 'gradingform_rubric'), $attrs['id'], false, array('class' => 'label'));
                     $value = (int)(!!$value); // make sure $value is either 0 or 1
                     if ($mode == gradingform_rubric_controller::DISPLAY_EDIT_FULL) {
                         $selectoptions = array(0 => get_string($option.'0', 'gradingform_rubric'), 1 => get_string($option.'1', 'gradingform_rubric'));
@@ -448,7 +449,7 @@ class gradingform_rubric_renderer extends plugin_renderer_base {
     public function display_regrade_confirmation($elementname, $changelevel, $value) {
         $html = html_writer::start_tag('div', array('class' => 'gradingform_rubric-regrade'));
         if ($changelevel<=2) {
-            $html .= get_string('regrademessage1', 'gradingform_rubric');
+            $html .= html_writer::label(get_string('regrademessage1', 'gradingform_rubric'), 'menu' . $elementname . 'regrade');
             $selectoptions = array(
                 0 => get_string('regradeoption0', 'gradingform_rubric'),
                 1 => get_string('regradeoption1', 'gradingform_rubric')
diff --git a/grade/lib.php b/grade/lib.php
index 9d1bda9..b166e54 100644
--- a/grade/lib.php
+++ b/grade/lib.php
@@ -437,7 +437,7 @@ function print_grade_plugin_selector($plugin_info, $active_type, $active_plugin,
     // finally print/return the popup form
     if ($count > 1) {
         $select = new url_select($menu, $active, null, 'choosepluginreport');
-
+        $select->set_label(get_string('gradereport', 'grades'), array('class' => 'accesshide'));
         if ($return) {
             return $OUTPUT->render($select);
         } else {
diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index d5dafa4..ea8f076 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -1016,7 +1016,8 @@ class grade_report_grader extends grade_report {
                                 $nogradestr = $this->get_lang_string('nooutcome', 'grades');
                             }
                             $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
-                            $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);;
+                            $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);
                         } elseif(!empty($scale)) {
                             $scales = explode(",", $scale->scale);
 
-- 
1.7.9.5


From 519adbc6844bdae5dce13fc1215e280d46760cb0 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:47:56 +0800
Subject: [PATCH 328/903] MDL-34561 accessibility compliance for assignment
 module: Add forform input text and select tag

---
 mod/assignment/lib.php |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index 99d29c8..3266274 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1475,7 +1475,8 @@ class assignment_base {
                                 } else if ($quickgrade) {
                                     $attributes = array();
                                     $attributes['tabindex'] = $tabindex++;
-                                    $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
+                                    $menu = html_writer::label(get_string('assignment:grade', 'assignment'), 'menumenu'. $auser->id, false, array('class' => ''));
+                                    $menu .= html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
                                     $grade = '<div id="g'.$auser->id.'">'. $menu .'</div>';
                                 } else {
                                     $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
@@ -1488,7 +1489,8 @@ class assignment_base {
                                 } else if ($quickgrade) {
                                     $attributes = array();
                                     $attributes['tabindex'] = $tabindex++;
-                                    $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
+                                    $menu = html_writer::label(get_string('assignment:grade', 'assignment'), 'menumenu'. $auser->id, false, array('class' => 'accesshide'));
+                                    $menu .= html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
                                     $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>';
                                 } else {
                                     $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>';
@@ -1516,7 +1518,8 @@ class assignment_base {
                             } else if ($quickgrade) {   // allow editing
                                 $attributes = array();
                                 $attributes['tabindex'] = $tabindex++;
-                                $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
+                                $menu = html_writer::label(get_string('assignment:grade', 'assignment'), 'menumenu'. $auser->id, false, array('class' => 'accesshide'));
+                                $menu .= html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
                                 $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>';
                                 $hassubmission = true;
                             } else {
@@ -1560,7 +1563,7 @@ class assignment_base {
                         if ($uses_outcomes) {
 
                             foreach($grading_info->outcomes as $n=>$outcome) {
-                                $outcomes .= '<div class="outcome"><label>'.$outcome->name.'</label>';
+                                $outcomes .= '<div class="outcome"><label for="'. 'outcome_'.$n.'_'.$auser->id .'">'.$outcome->name.'</label>';
                                 $options = make_grades_menu(-$outcome->scaleid);
 
                                 if ($outcome->grades[$auser->id]->locked or !$quickgrade) {
-- 
1.7.9.5


From d0d9c135e1e35b4a7379e79d6d4c92a1c33d5b88 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:48:30 +0800
Subject: [PATCH 329/903] MDL-34564 accessibility compliance for feedback
 module: Add forform input text and select tag

---
 mod/feedback/analysis_course.php           |    7 +++----
 mod/feedback/item/multichoice/lib.php      |    3 ++-
 mod/feedback/item/multichoicerated/lib.php |    3 ++-
 mod/feedback/mapcourse.php                 |    2 +-
 mod/feedback/show_nonrespondents.php       |    1 +
 5 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/mod/feedback/analysis_course.php b/mod/feedback/analysis_course.php
index b0ab0dc..faf95ff 100644
--- a/mod/feedback/analysis_course.php
+++ b/mod/feedback/analysis_course.php
@@ -165,8 +165,8 @@ if ($courseitemfilter > 0) {
     }
 } else {
 
-    echo get_string('search_course', 'feedback') . ': ';
-    echo '<input type="text" name="searchcourse" value="'.s($searchcourse).'"/> ';
+    echo html_writer::label(get_string('search_course', 'feedback') . ': ', 'searchcourse');
+    echo '<input id="searchcourse" type="text" name="searchcourse" value="'.s($searchcourse).'"/> ';
     echo '<input type="submit" value="'.get_string('search').'"/>';
     echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
     echo '<input type="hidden" name="id" value="'.$id.'" />';
@@ -185,8 +185,7 @@ if ($courseitemfilter > 0) {
 
     if ($courses = $DB->get_records_sql_menu($sql, $params)) {
 
-         echo ' ' . get_string('filter_by_course', 'feedback') . ': ';
-
+         echo ' '. html_writer::label(get_string('filter_by_course', 'feedback'), 'coursefilterid'). ': ';
          echo html_writer::select($courses, 'coursefilter', $coursefilter,
                                   null, array('id'=>'coursefilterid'));
 
diff --git a/mod/feedback/item/multichoice/lib.php b/mod/feedback/item/multichoice/lib.php
index 33955c1..4b7a841 100644
--- a/mod/feedback/item/multichoice/lib.php
+++ b/mod/feedback/item/multichoice/lib.php
@@ -763,7 +763,8 @@ class feedback_item_multichoice extends feedback_item_base {
 
         ?>
         <li class="feedback_item_select_<?php echo $hv.'_'.$align;?>">
-            <select name="<?php echo $item->typ .'_' . $item->id;?>[]" size="1">
+            <label class="accesshide" for="<?php echo $item->typ .'_' . $item->id;?>"><?php echo $item->name; ?></label>
+            <select  id="<?php echo $item->typ .'_' . $item->id;?>" name="<?php echo $item->typ .'_' . $item->id;?>[]" size="1">
                 <option value="0">&nbsp;</option>
                 <?php
                 $index = 1;
diff --git a/mod/feedback/item/multichoicerated/lib.php b/mod/feedback/item/multichoicerated/lib.php
index ca43a44..00ee832 100644
--- a/mod/feedback/item/multichoicerated/lib.php
+++ b/mod/feedback/item/multichoicerated/lib.php
@@ -575,7 +575,8 @@ class feedback_item_multichoicerated extends feedback_item_base {
         echo '<ul>';
         ?>
         <li class="feedback_item_select_<?php echo $hv.'_'.$align;?>">
-            <select name="<?php echo $item->typ.'_'.$item->id;?>">
+            <label class="accesshide" for="<?php echo $item->typ.'_'.$item->id;?>"><?php echo $item->name; ?></label>
+            <select id="<?php echo $item->typ.'_'.$item->id;?>" name="<?php echo $item->typ.'_'.$item->id;?>">
                 <option value="0">&nbsp;</option>
                 <?php
                 $index = 1;
diff --git a/mod/feedback/mapcourse.php b/mod/feedback/mapcourse.php
index 8014ca7..be060c0 100644
--- a/mod/feedback/mapcourse.php
+++ b/mod/feedback/mapcourse.php
@@ -104,7 +104,7 @@ $sql = "select c.id, c.shortname
 $params = array("%{$searchcourse}%", "%{$searchcourse}%");
 
 if (($courses = $DB->get_records_sql_menu($sql, $params)) && !empty($searchcourse)) {
-    echo ' ' . get_string('courses') . ': ';
+    echo ' '. html_writer::label(get_string('courses'), 'menucoursefilter', false). ': ';
     echo html_writer::select($courses, 'coursefilter', $coursefilter);
     echo '<input type="submit" value="'.get_string('mapcourse', 'feedback').'"/>';
     echo $OUTPUT->help_icon('mapcourses', 'feedback');
diff --git a/mod/feedback/show_nonrespondents.php b/mod/feedback/show_nonrespondents.php
index de5d0c7..d03ac14 100644
--- a/mod/feedback/show_nonrespondents.php
+++ b/mod/feedback/show_nonrespondents.php
@@ -288,6 +288,7 @@ if (!$students) {
             print_string('formathtml');
             echo '<input type="hidden" name="format" value="'.FORMAT_HTML.'" />';
         } else {
+            echo '<label for="menuformat" class="accesshide">'. get_string('format') .'</label>';
             choose_from_menu(format_text_menu(), "format", $format, "");
         }
         echo '<br /><div class="buttons">';
-- 
1.7.9.5


From 077e06f6217ef371a4361ffb66eac171725f6aa4 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:49:02 +0800
Subject: [PATCH 330/903] MDL-34567 accessibility compliance for lesson
 module: Add forform input text and select tag

---
 mod/lesson/pagetypes/matching.php |    9 ++++++---
 mod/lesson/report.php             |    1 +
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/mod/lesson/pagetypes/matching.php b/mod/lesson/pagetypes/matching.php
index 0572978..be4be19 100644
--- a/mod/lesson/pagetypes/matching.php
+++ b/mod/lesson/pagetypes/matching.php
@@ -400,16 +400,19 @@ class lesson_page_type_matching extends lesson_page {
                     $answerdata->score = get_string("didnotreceivecredit", "lesson");
                 }
             } elseif ($n > 1) {
-                $data = "<select disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->answer))."</option></select>";
+                $data = '<label class="accesshide" for="answer_' . $n . '">' . get_string('answer', 'lesson') . '</label>';
+                $data .= "<select id=\"answer_". $n ."\" disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->answer))."</option></select>";
                 if ($useranswer != NULL) {
                     $userresponse = explode(",", $useranswer->useranswer);
-                    $data .= "<select disabled=\"disabled\"><option selected=\"selected\">";
+                    $data .= '<label class="accesshide" for="stu_answer_response_' . $n . '">' . get_string('matchesanswer', 'lesson') . '</label>';
+                    $data .= "<select id=\"stu_answer_response_" . $n . "\" disabled=\"disabled\"><option selected=\"selected\">";
                     if (array_key_exists($i, $userresponse)) {
                         $data .= strip_tags(format_string($answers[$userresponse[$i]]->response));
                     }
                     $data .= "</option></select>";
                 } else {
-                    $data .= "<select disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->response))."</option></select>";
+                    $data .= '<label class="accesshide" for="answer_response_' . $n . '">' . get_string('matchesanswer', 'lesson') . '</label>';
+                    $data .= "<select id=\"answer_response_" . $n . "\" disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->response))."</option></select>";
                 }
 
                 if ($n == 2) {
diff --git a/mod/lesson/report.php b/mod/lesson/report.php
index f2d1e05..37d6cba 100644
--- a/mod/lesson/report.php
+++ b/mod/lesson/report.php
@@ -314,6 +314,7 @@ if ($action === 'delete') {
     if (has_capability('mod/lesson:edit', $context)) {
         $checklinks  = '<a href="javascript: checkall();">'.get_string('selectall').'</a> / ';
         $checklinks .= '<a href="javascript: checknone();">'.get_string('deselectall').'</a>';
+        $checklinks .= html_writer::label('action', 'menuaction', false, array('class' => 'accesshide'));
         $checklinks .= html_writer::select(array('delete' => get_string('deleteselected')), 'action', 0, array(''=>'choosedots'), array('id'=>'actionid'));
         $PAGE->requires->js_init_call('M.util.init_select_autosubmit', array('theform', 'actionid', ''));
         echo $OUTPUT->box($checklinks, 'center');
-- 
1.7.9.5


From 08e03a695ac0a0ce4b4c07991a9d6e749080da41 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:48:52 +0800
Subject: [PATCH 331/903] MDL-34566 accessibility compliance for glossary
 module: Add forform input text and select tag

---
 mod/glossary/editcategories.html |    8 ++++----
 mod/glossary/formats.php         |   22 +++++++++++-----------
 mod/glossary/lib.php             |    6 ++++--
 3 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/mod/glossary/editcategories.html b/mod/glossary/editcategories.html
index b6c252e..3b64818 100644
--- a/mod/glossary/editcategories.html
+++ b/mod/glossary/editcategories.html
@@ -7,15 +7,15 @@
 <div>
 <table  class="generalbox" cellpadding="5">
 <tr valign="top">
-    <td align="right"><?php echo get_string("name") ?>:</td>
+    <td align="right"><label for="name"><?php echo get_string("name") ?>:</label></td>
     <td>
-        <input type="text" name="name" size="30" value="<?php p($name) ?>" />
+        <input type="text" name="name" id="name" size="30" value="<?php p($name) ?>" />
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><?php echo get_string("linkcategory","glossary") ?>:</td>
+    <td align="right"><label for="usedynalink"><?php echo get_string("linkcategory","glossary") ?>:</label></td>
     <td>
-      <select size="1" name="usedynalink">
+      <select size="1" id="usedynalink" name="usedynalink">
       <option value="1" <?php
        if ( $usedynalink ) {
           echo "selected=\"selected\"";
diff --git a/mod/glossary/formats.php b/mod/glossary/formats.php
index 5d65009..9210f5b 100644
--- a/mod/glossary/formats.php
+++ b/mod/glossary/formats.php
@@ -69,7 +69,7 @@ echo '<table width="90%" align="center" class="generalbox">';
     </strong></td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string('popupformat','glossary'); ?></td>
+    <td align="right" width="20%"><?php echo html_writer::label(get_string('popupformat','glossary'), 'menupopupformatname'); ?></td>
     <td>
  <?php
     //get and update available formats
@@ -92,9 +92,9 @@ echo '<table width="90%" align="center" class="generalbox">';
     </td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string('defaultmode','glossary'); ?></td>
+    <td align="right" width="20%"><label for="defaultmode"><?php print_string('defaultmode','glossary'); ?></label></td>
     <td>
-    <select size="1" name="defaultmode">
+    <select size="1" id="defaultmode" name="defaultmode">
 <?php
     $sletter = '';
     $scat = '';
@@ -129,9 +129,9 @@ echo '<table width="90%" align="center" class="generalbox">';
     </td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string('defaulthook','glossary'); ?></td>
+    <td align="right" width="20%"><label for="defaulthook"><?php print_string('defaulthook','glossary'); ?></label></td>
     <td>
-    <select size="1" name="defaulthook">
+    <select size="1" id="defaulthook" name="defaulthook">
 <?php
     $sall = '';
     $sspecial = '';
@@ -166,9 +166,9 @@ echo '<table width="90%" align="center" class="generalbox">';
     </td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string('defaultsortkey','glossary'); ?></td>
+    <td align="right" width="20%"><label for="sortkey"><?php print_string('defaultsortkey','glossary'); ?></label></td>
     <td>
-    <select size="1" name="sortkey">
+    <select size="1" id="sortkey" name="sortkey">
 <?php
     $sfname = '';
     $slname = '';
@@ -203,9 +203,9 @@ echo '<table width="90%" align="center" class="generalbox">';
     </td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string('defaultsortorder','glossary'); ?></td>
+    <td align="right" width="20%"><label for="sortorder"><?php print_string('defaultsortorder','glossary'); ?></label></td>
     <td>
-    <select size="1" name="sortorder">
+    <select size="1" id="sortorder" name="sortorder">
 <?php
     $sasc = '';
     $sdesc = '';
@@ -228,9 +228,9 @@ echo '<table width="90%" align="center" class="generalbox">';
     </td>
 </tr>
 <tr valign="top">
-    <td align="right" width="20%"><?php print_string("includegroupbreaks", "glossary"); ?>:</td>
+    <td align="right" width="20%"><label for="showgroup"><?php print_string("includegroupbreaks", "glossary"); ?>:</label></td>
     <td>
-    <select size="1" name="showgroup">
+    <select size="1" id="showgroup" name="showgroup">
 <?php
     $yselected = "";
     $nselected = "";
diff --git a/mod/glossary/lib.php b/mod/glossary/lib.php
index 85c9673..2a307bd 100644
--- a/mod/glossary/lib.php
+++ b/mod/glossary/lib.php
@@ -1188,7 +1188,7 @@ function  glossary_print_entry_aliases($course, $cm, $glossary, $entry,$mode='',
         foreach ($aliases as $alias) {
             if (trim($alias->alias)) {
                 if ($return == '') {
-                    $return = '<select style="font-size:8pt">';
+                    $return = '<select id="keyword" style="font-size:8pt">';
                 }
                 $return .= "<option>$alias->alias</option>";
             }
@@ -1344,7 +1344,8 @@ function  glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $m
         echo '<table>';
         if ( $aliases ) {
             echo '<tr valign="top"><td class="aliases">' .
-                  get_string('aliases','glossary').': '.$aliases . '</td></tr>';
+                 '<label for="keyword">' . get_string('aliases','glossary').': </label>' .
+                 $aliases . '</td></tr>';
         }
         if ($icons) {
             echo '<tr valign="top"><td class="icons">'.$icons.'</td></tr>';
@@ -1926,6 +1927,7 @@ function glossary_print_categories_menu($cm, $glossary, $hook, $category) {
      echo '<td align="center" style="width:20%">';
 
      $select = new single_select(new moodle_url("/mod/glossary/view.php", array('id'=>$cm->id, 'mode'=>'cat')), 'hook', $menu, $selected, null, "catmenu");
+     $select->set_label(get_string('categories', 'glossary'), array('class' => 'accesshide'));
      echo $OUTPUT->render($select);
 
      echo '</td>';
-- 
1.7.9.5


From 0f9992ca6678aff6856766dca1fbd11aa3d5940c Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:50:17 +0800
Subject: [PATCH 332/903] MDL-34574 accessibility compliance for mymobile
 theme: Add forform input text and select tag

---
 theme/mymobile/layout/general.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/mymobile/layout/general.php b/theme/mymobile/layout/general.php
index ba98834..c862738 100644
--- a/theme/mymobile/layout/general.php
+++ b/theme/mymobile/layout/general.php
@@ -210,7 +210,7 @@ echo $OUTPUT->doctype() ?>
 
                 <div data-role="fieldcontain" id="sliderdiv">
                     <label for="slider"><?php p(get_string('mtoggle','theme_mymobile')); ?>:</label>
-                    <select name="slider" class="slider" data-role="slider">
+                    <select name="slider" class="slider" data-role="slider" id="slider">
                         <option value="on">On</option>
                         <option value="off">Off</option>
                     </select>
-- 
1.7.9.5


From 1445fd133737e39bbc7b61692babdacef9004c71 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 3 Aug 2012 13:36:27 +0800
Subject: [PATCH 333/903] MDL-34575 accessibility compliance for notes: Add
 form input text and select tag

---
 lang/en/notes.php     |    1 +
 user/addnote.php      |    5 ++---
 user/groupaddnote.php |    2 +-
 user/index.php        |    3 ++-
 user/message.html     |    2 +-
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/lang/en/notes.php b/lang/en/notes.php
index 49dbf0e..e176ce8 100644
--- a/lang/en/notes.php
+++ b/lang/en/notes.php
@@ -60,4 +60,5 @@ $string['publishstate_help'] = 'A note\'s context determines who can see the not
 * Site - The note will be visible to teachers in all courses';
 $string['site'] = 'site';
 $string['sitenotes'] = 'Site notes';
+$string['selectnotestate'] = "Select note state";
 $string['unknown'] = 'unknown';
diff --git a/user/addnote.php b/user/addnote.php
index 1b89982..79a8263 100644
--- a/user/addnote.php
+++ b/user/addnote.php
@@ -79,7 +79,6 @@ $PAGE->set_title("$course->shortname: ".get_string('extendenrol'));
 $PAGE->set_heading($course->fullname);
 
 echo $OUTPUT->header();
-
 // this will contain all available the based On select options, but we'll disable some on them on a per user basis
 
 echo $OUTPUT->heading($straddnote);
@@ -104,12 +103,12 @@ if (empty($users) and $post = data_submitted()) {
         }
     }
 }
-
 foreach ($users as $k => $v) {
     if(!$user = $DB->get_record('user', array('id'=>$v))) {
         continue;
     }
-    $checkbox = html_writer::select($state_names, 'states[' . $k . ']', empty($states[$k]) ? NOTES_STATE_PUBLIC : $states[$k], false);
+    $checkbox = html_writer::label(get_string('selectnotestate', 'note'), 'menustates', false, array('class' => 'accesshide'));
+    $checkbox .= html_writer::select($state_names, 'states[' . $k . ']', empty($states[$k]) ? NOTES_STATE_PUBLIC : $states[$k], false, array('id' => 'menustates'));
     $table->data[] = array(
         '<input type="hidden" name="userid['.$k.']" value="'.$v.'" />'. fullname($user, true),
         '<textarea name="contents['. $k . ']" rows="2" cols="40">' . strip_tags(@$contents[$k]) . '</textarea>',
diff --git a/user/groupaddnote.php b/user/groupaddnote.php
index 26649da..066f6a7 100644
--- a/user/groupaddnote.php
+++ b/user/groupaddnote.php
@@ -117,7 +117,7 @@ echo '<p>' . get_string('content', 'notes');
 echo '<br /><textarea name="content" rows="5" cols="50">' . strip_tags(@$content) . '</textarea></p>';
 
 echo '<p>';
-echo get_string('publishstate', 'notes');
+echo html_writer::label(get_string('publishstate', 'notes'), 'menustate');
 echo $OUTPUT->help_icon('publishstate', 'notes');
 echo html_writer::select($state_names, 'state', empty($state) ? NOTES_STATE_PUBLIC : $state, false);
 echo '</p>';
diff --git a/user/index.php b/user/index.php
index 8ea84f9..0f4a64a 100644
--- a/user/index.php
+++ b/user/index.php
@@ -813,7 +813,8 @@
 
     if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
         echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
-        echo '<input type="text" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
+        echo '<label class="accesshide" for="search">' . get_string('search', 'search') . '</label>';
+        echo '<input type="text" id="search" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
     }
 
     $perpageurl = clone($baseurl);
diff --git a/user/message.html b/user/message.html
index e077cf1..6426111 100644
--- a/user/message.html
+++ b/user/message.html
@@ -14,7 +14,7 @@
 </tr>
 
 <tr valign="top">
-    <td align="right"><b><?php print_string("formattexttype"); ?>:</b></td>
+    <td align="right"><label for="menuformat"><b><?php print_string("formattexttype"); ?>:</b></label></td>
     <td>
     <?php
         if ($usehtmleditor) {   /// Trying this out for a while
-- 
1.7.9.5


From 3f995bef7ae44e66f89b7b3f3e9077dbace85ea6 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 1 Aug 2012 17:37:56 +0800
Subject: [PATCH 334/903] MDL-22663 Repository: Fixed strict standards notices
 in WebDAV lib

---
 lib/webdavlib.php |   63 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 27 deletions(-)

diff --git a/lib/webdavlib.php b/lib/webdavlib.php
index 1280a3d..58d3d8e 100644
--- a/lib/webdavlib.php
+++ b/lib/webdavlib.php
@@ -57,6 +57,7 @@ class webdav_client {
     private $_req;
     private $_resp_status;
     private $_parser;
+    private $_parserid;
     private $_xmltree;
     private $_tree;
     private $_ls = array();
@@ -612,9 +613,10 @@ class webdav_client {
                     if (strcmp($response['header']['Content-Type'], 'text/xml; charset="utf-8"') == 0) {
                         // ok let's get the content of the xml stuff
                         $this->_parser = xml_parser_create_ns();
+                        $this->_parserid = (int) $this->_parser;
                         // forget old data...
-                        unset($this->_lock[$this->_parser]);
-                        unset($this->_xmltree[$this->_parser]);
+                        unset($this->_lock[$this->_parserid]);
+                        unset($this->_xmltree[$this->_parserid]);
                         xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
                         xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
                         xml_set_object($this->_parser, $this);
@@ -630,8 +632,8 @@ class webdav_client {
                         // Free resources
                         xml_parser_free($this->_parser);
                         // add status code to array
-                        $this->_lock[$this->_parser]['status'] = 200;
-                        return $this->_lock[$this->_parser];
+                        $this->_lock[$this->_parserid]['status'] = 200;
+                        return $this->_lock[$this->_parserid];
 
                     } else {
                         print 'Missing Content-Type: text/xml header in response.<br>';
@@ -709,9 +711,10 @@ class webdav_client {
                     if (strcmp($response['header']['Content-Type'], 'text/xml; charset="utf-8"') == 0) {
                         // ok let's get the content of the xml stuff
                         $this->_parser = xml_parser_create_ns();
+                        $this->_parserid = (int) $this->_parser;
                         // forget old data...
-                        unset($this->_delete[$this->_parser]);
-                        unset($this->_xmltree[$this->_parser]);
+                        unset($this->_delete[$this->_parserid]);
+                        unset($this->_xmltree[$this->_parserid]);
                         xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
                         xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
                         xml_set_object($this->_parser, $this);
@@ -728,8 +731,8 @@ class webdav_client {
 
                         // Free resources
                         xml_parser_free($this->_parser);
-                        $this->_delete[$this->_parser]['status'] = $response['status']['status-code'];
-                        return $this->_delete[$this->_parser];
+                        $this->_delete[$this->_parserid]['status'] = $response['status']['status-code'];
+                        return $this->_delete[$this->_parserid];
 
                     } else {
                         print 'Missing Content-Type: text/xml header in response.<br>';
@@ -800,9 +803,10 @@ EOD;
                     if (preg_match('#(application|text)/xml;\s?charset=[\'\"]?utf-8[\'\"]?#i', $response['header']['Content-Type'])) {
                         // ok let's get the content of the xml stuff
                         $this->_parser = xml_parser_create_ns('UTF-8');
+                        $this->_parserid = (int) $this->_parser;
                         // forget old data...
-                        unset($this->_ls[$this->_parser]);
-                        unset($this->_xmltree[$this->_parser]);
+                        unset($this->_ls[$this->_parserid]);
+                        unset($this->_xmltree[$this->_parserid]);
                         xml_parser_set_option($this->_parser,XML_OPTION_SKIP_WHITE,0);
                         xml_parser_set_option($this->_parser,XML_OPTION_CASE_FOLDING,0);
                         // xml_parser_set_option($this->_parser,XML_OPTION_TARGET_ENCODING,'UTF-8');
@@ -819,7 +823,7 @@ EOD;
 
                         // Free resources
                         xml_parser_free($this->_parser);
-                        $arr = $this->_ls[$this->_parser];
+                        $arr = $this->_ls[$this->_parserid];
                         return $arr;
                     } else {
                         $this->_error_log('Missing Content-Type: text/xml header in response!!');
@@ -1038,7 +1042,8 @@ EOD;
 
     private function _endElement($parser, $name) {
         // end tag was found...
-        $this->_xmltree[$parser] = substr($this->_xmltree[$parser],0, strlen($this->_xmltree[$parser]) - (strlen($name) + 1));
+        $parserid = (int) $parser;
+        $this->_xmltree[$parserid] = substr($this->_xmltree[$parserid],0, strlen($this->_xmltree[$parserid]) - (strlen($name) + 1));
     }
 
     /**
@@ -1053,19 +1058,20 @@ EOD;
      */
     private function _propfind_startElement($parser, $name, $attrs) {
         // lower XML Names... maybe break a RFC, don't know ...
+        $parserid = (int) $parser;
 
         $propname = strtolower($name);
-        if (!empty($this->_xmltree[$parser])) {
-            $this->_xmltree[$parser] .= $propname . '_';
+        if (!empty($this->_xmltree[$parserid])) {
+            $this->_xmltree[$parserid] .= $propname . '_';
         } else {
-            $this->_xmltree[$parser] = $propname . '_';
+            $this->_xmltree[$parserid] = $propname . '_';
         }
 
         // translate xml tree to a flat array ...
-        switch($this->_xmltree[$parser]) {
+        switch($this->_xmltree[$parserid]) {
         case 'dav::multistatus_dav::response_':
             // new element in mu
-            $this->_ls_ref =& $this->_ls[$parser][];
+            $this->_ls_ref =& $this->_ls[$parserid][];
             break;
         case 'dav::multistatus_dav::response_dav::href_':
             $this->_ls_ref_cdata = &$this->_ls_ref['href'];
@@ -1113,7 +1119,7 @@ EOD;
 
         default:
             // handle unknown xml elements...
-            $this->_ls_ref_cdata = &$this->_ls_ref[$this->_xmltree[$parser]];
+            $this->_ls_ref_cdata = &$this->_ls_ref[$this->_xmltree[$parserid]];
         }
     }
 
@@ -1148,14 +1154,15 @@ EOD;
      */
     private function _delete_startElement($parser, $name, $attrs) {
         // lower XML Names... maybe break a RFC, don't know ...
+        $parserid = (int) $parser;
         $propname = strtolower($name);
-        $this->_xmltree[$parser] .= $propname . '_';
+        $this->_xmltree[$parserid] .= $propname . '_';
 
         // translate xml tree to a flat array ...
-        switch($this->_xmltree[$parser]) {
+        switch($this->_xmltree[$parserid]) {
         case 'dav::multistatus_dav::response_':
             // new element in mu
-            $this->_delete_ref =& $this->_delete[$parser][];
+            $this->_delete_ref =& $this->_delete[$parserid][];
             break;
         case 'dav::multistatus_dav::response_dav::href_':
             $this->_delete_ref_cdata = &$this->_ls_ref['href'];
@@ -1163,7 +1170,7 @@ EOD;
 
         default:
             // handle unknown xml elements...
-            $this->_delete_cdata = &$this->_delete_ref[$this->_xmltree[$parser]];
+            $this->_delete_cdata = &$this->_delete_ref[$this->_xmltree[$parserid]];
         }
     }
 
@@ -1199,8 +1206,9 @@ EOD;
      */
     private function _lock_startElement($parser, $name, $attrs) {
         // lower XML Names... maybe break a RFC, don't know ...
+        $parserid = (int) $parser;
         $propname = strtolower($name);
-        $this->_xmltree[$parser] .= $propname . '_';
+        $this->_xmltree[$parserid] .= $propname . '_';
 
         // translate xml tree to a flat array ...
         /*
@@ -1209,10 +1217,10 @@ EOD;
         dav::prop_dav::lockdiscovery_dav::activelock_dav::timeout_=
         dav::prop_dav::lockdiscovery_dav::activelock_dav::locktoken_dav::href_=
          */
-        switch($this->_xmltree[$parser]) {
+        switch($this->_xmltree[$parserid]) {
         case 'dav::prop_dav::lockdiscovery_dav::activelock_':
             // new element
-            $this->_lock_ref =& $this->_lock[$parser][];
+            $this->_lock_ref =& $this->_lock[$parserid][];
             break;
         case 'dav::prop_dav::lockdiscovery_dav::activelock_dav::locktype_dav::write_':
             $this->_lock_ref_cdata = &$this->_lock_ref['locktype'];
@@ -1238,7 +1246,7 @@ EOD;
             break;
         default:
             // handle unknown xml elements...
-            $this->_lock_cdata = &$this->_lock_ref[$this->_xmltree[$parser]];
+            $this->_lock_cdata = &$this->_lock_ref[$this->_xmltree[$parserid]];
 
         }
     }
@@ -1254,8 +1262,9 @@ EOD;
      * @access private
      */
     private function _lock_cData($parser, $cdata) {
+        $parserid = (int) $parser;
         if (trim($cdata) <> '') {
-            // $this->_error_log(($this->_xmltree[$parser]) . '='. htmlentities($cdata));
+            // $this->_error_log(($this->_xmltree[$parserid]) . '='. htmlentities($cdata));
             $this->_lock_ref_cdata .= $cdata;
         } else {
             // do nothing
-- 
1.7.9.5


From 85a9d23d916a540331a599acc64a05b28f7bae68 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 2 Aug 2012 12:04:32 +0800
Subject: [PATCH 335/903] MDL-22663 Repository: WebDAV supports SSL and
 chunked data

---
 lib/webdavlib.php         |   13 ++++++++++---
 repository/webdav/lib.php |   30 +++++++++++++++++++-----------
 2 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/lib/webdavlib.php b/lib/webdavlib.php
index 58d3d8e..9051a1e 100644
--- a/lib/webdavlib.php
+++ b/lib/webdavlib.php
@@ -44,6 +44,7 @@ class webdav_client {
     private $_server;
     private $_protocol = 'HTTP/1.1';
     private $_port = 80;
+    private $_socket = '';
     private $_path ='/';
     private $_auth = false;
     private $_user;
@@ -80,7 +81,7 @@ class webdav_client {
     /**
      * Constructor - Initialise class variables
      */
-    function __construct($server = '', $user = '', $pass = '', $auth = false) {
+    function __construct($server = '', $user = '', $pass = '', $auth = false, $socket = '') {
         if (!empty($server)) {
             $this->_server = $server;
         }
@@ -89,6 +90,7 @@ class webdav_client {
             $this->pass = $pass;
         }
         $this->_auth = $auth;
+        $this->_socket = $socket;
     }
     public function __set($key, $value) {
         $property = '_' . $key;
@@ -155,7 +157,7 @@ class webdav_client {
     function open() {
         // let's try to open a socket
         $this->_error_log('open a socket connection');
-        $this->sock = fsockopen($this->_server, $this->_port, $this->_errno, $this->_errstr, $this->_socket_timeout);
+        $this->sock = fsockopen($this->_socket . $this->_server, $this->_port, $this->_errno, $this->_errstr, $this->_socket_timeout);
         set_time_limit(30);
         if (is_resource($this->sock)) {
             socket_set_blocking($this->sock, true);
@@ -1404,7 +1406,12 @@ EOD;
                 fread($this->sock, 1);                           // also drop off the Line Feed
                 $chunk_size=hexdec($chunk_size);                // convert to a number in decimal system
                 if ($chunk_size > 0) {
-                    $buffer .= fread($this->sock,$chunk_size);
+                    $read = 0;
+                    // Reading the chunk in one bite is not secure, we read it byte by byte.
+                    while ($read < $chunk_size) {
+                        $buffer .= fread($this->sock, 1);
+                        $read++;
+                    }
                 }
                 fread($this->sock, 2);                            // ditch the CRLF that trails the chunk
             } while ($chunk_size);                            // till we reach the 0 length chunk (end marker)
diff --git a/repository/webdav/lib.php b/repository/webdav/lib.php
index 07c66b1..f0aa414 100644
--- a/repository/webdav/lib.php
+++ b/repository/webdav/lib.php
@@ -44,24 +44,27 @@ class repository_webdav extends repository {
         if ($this->options['webdav_auth'] == 'none') {
             $this->options['webdav_auth'] = false;
         }
-        $this->dav = new webdav_client($this->options['webdav_server'], $this->options['webdav_user'], $this->options['webdav_password'], $this->options['webdav_auth']);
         if (empty($this->options['webdav_type'])) {
             $this->webdav_type = '';
         } else {
             $this->webdav_type = 'ssl://';
         }
         if (empty($this->options['webdav_port'])) {
+            $port = '';
             if (empty($this->webdav_type)) {
-                $this->dav->port = 80;
+                $this->webdav_port = 80;
             } else {
-                $this->dav->port = 443;
+                $this->webdav_port = 443;
+                $port = ':443';
             }
-            $port = '';
         } else {
-            $this->dav->port = $this->options['webdav_port'];
-            $port = ':'.$this->options['webdav_port'];
+            $this->webdav_port = $this->options['webdav_port'];
+            $port = ':' . $this->webdav_port;
         }
         $this->webdav_host = $this->webdav_type.$this->options['webdav_server'].$port;
+        $this->dav = new webdav_client($this->options['webdav_server'], $this->options['webdav_user'],
+                $this->options['webdav_password'], $this->options['webdav_auth'], $this->webdav_type);
+        $this->dav->port = $this->webdav_port;
         $this->dav->debug = false;
     }
     public function check_login() {
@@ -120,13 +123,16 @@ class repository_webdav extends repository {
             } else {
                 $v['lastmodified'] = null;
             }
-            $v['href'] = substr($v['href'], strlen(urlencode($webdavpath)));
-            $title = urldecode(substr($v['href'], strlen($path)));
+
+            // Extracting object title from absolute path
+            $v['href'] = substr(urldecode($v['href']), strlen($webdavpath));
+            $title = substr($v['href'], strlen($path));
+
             if (!empty($v['resourcetype']) && $v['resourcetype'] == 'collection') {
                 // a folder
                 if ($path != $v['href']) {
-                    $folders[] = array(
-                        'title'=>$title,
+                    $folders[strtoupper($title)] = array(
+                        'title'=>rtrim($title, '/'),
                         'thumbnail'=>$OUTPUT->pix_url(file_folder_icon(90))->out(false),
                         'children'=>array(),
                         'datemodified'=>$v['lastmodified'],
@@ -136,7 +142,7 @@ class repository_webdav extends repository {
             }else{
                 // a file
                 $size = !empty($v['getcontentlength'])? $v['getcontentlength']:'';
-                $files[] = array(
+                $files[strtoupper($title)] = array(
                     'title'=>$title,
                     'thumbnail' => $OUTPUT->pix_url(file_extension_icon($title, 90))->out(false),
                     'size'=>$size,
@@ -145,6 +151,8 @@ class repository_webdav extends repository {
                 );
             }
         }
+        ksort($files);
+        ksort($folders);
         $ret['list'] = array_merge($folders, $files);
         return $ret;
     }
-- 
1.7.9.5


From a602649f8f06fa141e3d79bf2d4e6fe49446cd68 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 2 Aug 2012 16:29:00 +0800
Subject: [PATCH 336/903] MDL-22663 Repository: WebDAV supports Digest
 authentication

---
 lib/webdavlib.php         |  103 ++++++++++++++++++++++++++++++++++++++++++++-
 repository/webdav/lib.php |    2 +-
 2 files changed, 103 insertions(+), 2 deletions(-)

diff --git a/lib/webdavlib.php b/lib/webdavlib.php
index 1280a3d..027de73 100644
--- a/lib/webdavlib.php
+++ b/lib/webdavlib.php
@@ -73,6 +73,9 @@ class webdav_client {
     private $_body='';
     private $_connection_closed = false;
     private $_maxheaderlenth = 1000;
+    private $_digestchallenge = null;
+    private $_cnonce = '';
+    private $_nc = 0;
 
     /**#@-*/
 
@@ -1293,7 +1296,6 @@ EOD;
      * @access private
      */
     private function create_basic_request($method) {
-        $request = '';
         $this->header_add(sprintf('%s %s %s', $method, $this->_path, $this->_protocol));
         $this->header_add(sprintf('Host: %s:%s', $this->_server, $this->_port));
         //$request .= sprintf('Connection: Keep-Alive');
@@ -1302,10 +1304,105 @@ EOD;
         $this->header_add('TE: Trailers');
         if ($this->_auth == 'basic') {
             $this->header_add(sprintf('Authorization: Basic %s', base64_encode("$this->_user:$this->_pass")));
+        } else if ($this->_auth == 'digest') {
+            if ($signature = $this->digest_signature($method)){
+                $this->header_add($signature);
+            }
         }
     }
 
     /**
+     * Reads the header, stores the challenge information
+     *
+     * @return void
+     */
+    private function digest_auth() {
+
+        $headers = array();
+        $headers[] = sprintf('%s %s %s', 'HEAD', $this->_path, $this->_protocol);
+        $headers[] = sprintf('Host: %s:%s', $this->_server, $this->_port);
+        $headers[] = sprintf('User-Agent: %s', $this->_user_agent);
+        $headers = implode("\r\n", $headers);
+        $headers .= "\r\n\r\n";
+        fputs($this->sock, $headers);
+
+        // Reads the headers.
+        $i = 0;
+        $header = '';
+        do {
+            $header .= fread($this->sock, 1);
+            $i++;
+        } while (!preg_match('/\\r\\n\\r\\n$/', $header, $matches) && $i < $this->_maxheaderlenth);
+
+        // Analyse the headers.
+        $digest = array();
+        $splitheaders = explode("\r\n", $header);
+        foreach ($splitheaders as $line) {
+            if (!preg_match('/^WWW-Authenticate: Digest/', $line)) {
+                continue;
+            }
+            $line = substr($line, strlen('WWW-Authenticate: Digest '));
+            $params = explode(',', $line);
+            foreach ($params as $param) {
+                list($key, $value) = explode('=', trim($param), 2);
+                $digest[$key] = trim($value, '"');
+            }
+            break;
+        }
+
+        $this->_digestchallenge = $digest;
+    }
+
+    /**
+     * Generates the digest signature
+     *
+     * @return string signature to add to the headers
+     * @access private
+     */
+    private function digest_signature($method) {
+        if (!$this->_digestchallenge) {
+            $this->digest_auth();
+        }
+
+        $signature = array();
+        $signature['username'] = '"' . $this->_user . '"';
+        $signature['realm'] = '"' . $this->_digestchallenge['realm'] . '"';
+        $signature['nonce'] = '"' . $this->_digestchallenge['nonce'] . '"';
+        $signature['uri'] = '"' . $this->_path . '"';
+
+        if (isset($this->_digestchallenge['algorithm']) && $this->_digestchallenge['algorithm'] != 'MD5') {
+            $this->_error_log('Algorithm other than MD5 are not supported');
+            return false;
+        }
+
+        $a1 = $this->_user . ':' . $this->_digestchallenge['realm'] . ':' . $this->_pass;
+        $a2 = $method . ':' . $this->_path;
+
+        if (!isset($this->_digestchallenge['qop'])) {
+            $signature['response'] = '"' . md5(md5($a1) . ':' . $this->_digestchallenge['nonce'] . ':' . md5($a2)) . '"';
+        } else {
+            // Assume QOP is auth
+            if (empty($this->_cnonce)) {
+                $this->_cnonce = random_string();
+                $this->_nc = 0;
+            }
+            $this->_nc++;
+            $nc = sprintf('%08d', $this->_nc);
+            $signature['cnonce'] = '"' . $this->_cnonce . '"';
+            $signature['nc'] = '"' . $nc . '"';
+            $signature['qop'] = '"' . $this->_digestchallenge['qop'] . '"';
+            $signature['response'] = '"' . md5(md5($a1) . ':' . $this->_digestchallenge['nonce'] . ':' .
+                    $nc . ':' . $this->_cnonce . ':' . $this->_digestchallenge['qop'] . ':' . md5($a2)) . '"';
+        }
+
+        $response = array();
+        foreach ($signature as $key => $value) {
+            $response[] = "$key=$value";
+        }
+        return 'Authorization: Digest ' . implode(', ', $response);
+    }
+
+    /**
      * Private method send_request
      *
      * Sends a ready formed http/webdav request to webdav server.
@@ -1373,7 +1470,10 @@ EOD;
             // Therefore we need to reopen the socket, before are sending the next request...
             $this->_error_log('Connection: close found');
             $this->_connection_closed = true;
+        } else if (preg_match('@^HTTP/1\.(1|0) 401 @', $header)) {
+            $this->_error_log('The server requires an authentication');
         }
+
         // check how to get the data on socket stream
         // chunked or content-length (HTTP/1.1) or
         // one block until feof is received (HTTP/1.0)
@@ -1472,6 +1572,7 @@ EOD;
         // $this->_buffer = $header . "\r\n\r\n" . $buffer;
         $this->_error_log($this->_header);
         $this->_error_log($this->_body);
+
     }
 
 
diff --git a/repository/webdav/lib.php b/repository/webdav/lib.php
index 07c66b1..51826c8 100644
--- a/repository/webdav/lib.php
+++ b/repository/webdav/lib.php
@@ -166,7 +166,7 @@ class repository_webdav extends repository {
         $choices = array();
         $choices['none'] = get_string('none');
         $choices['basic'] = get_string('webdavbasicauth', 'repository_webdav');
-        //$choices['digest'] = get_string('webdavdigestauth', 'repository_webdav');
+        $choices['digest'] = get_string('webdavdigestauth', 'repository_webdav');
         $mform->addElement('select', 'webdav_auth', get_string('authentication', 'admin'), $choices);
         $mform->addRule('webdav_auth', get_string('required'), 'required', null, 'client');
 
-- 
1.7.9.5


From e1d2c7452b58e841124453bbcd3df1ab442c0e8f Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 3 Aug 2012 16:06:54 +0800
Subject: [PATCH 337/903] MDL-34716 outcomes: Fix admin tree location

---
 grade/edit/outcome/edit.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/edit/outcome/edit.php b/grade/edit/outcome/edit.php
index d273289..596fd68 100644
--- a/grade/edit/outcome/edit.php
+++ b/grade/edit/outcome/edit.php
@@ -96,7 +96,7 @@ if ($id) {
 
 if (!$courseid) {
     require_once $CFG->libdir.'/adminlib.php';
-    admin_externalpage_setup('scales');
+    admin_externalpage_setup('outcomes');
 }
 
 // default return url
-- 
1.7.9.5


From 7a0664fbb4ef97067731cdf93978093c29635d46 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 3 Aug 2012 11:45:29 +0200
Subject: [PATCH 338/903] Automatically generated installer lang files

---
 install/lang/cs/install.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/install/lang/cs/install.php b/install/lang/cs/install.php
index bf1040d..8918b2f 100644
--- a/install/lang/cs/install.php
+++ b/install/lang/cs/install.php
@@ -68,7 +68,10 @@ $string['pathserrcreatedataroot'] = 'Datový adresář ({$a->dataroot}) nemůže
 $string['pathshead'] = 'Potvrdit cesty';
 $string['pathsrodataroot'] = 'Do datového adresáře nelze zapisovat.';
 $string['pathsroparentdataroot'] = 'Do nadřazeného adresáře ({$a->parent}) nelze zapisovat. Datový adresář ({$a->dataroot}) nemůže být tímto průvodcem instalací vytvořen.';
+$string['pathssubadmindir'] = 'Na některých serverech je URL adresa /admin vyhrazena pro speciální účely (např. pro ovládací panel). Na takových serverech může dojít ke kolizi se standardním umístěním stránek pro správu Moodle. Máte-li tento problém, přejmenujte adresář <eM>admin</em> ve vaší instalaci Moodle a sem zadejte jeho nový název - například <em>moodleadmin</em>. Všechny generované odkazy na stránky správy Moodle budou používat tento nový název.';
+$string['pathssubdataroot'] = 'Moodle potřebuje prostor, kam si bude ukládat nahrané soubory a další údaje. K tomuto adresáři musí mít proces webového serveru právo ke čtení i k zápisu (webový server bývá většinou spouštěn pod uživatelem "www-data" nebo "apache"). Tento adresář ale zároveň nesmí být dostupný přímo přes webové rozhraní. Instalační skript se pokusí tento adresář vytvořit, pokud nebude existovat.';
 $string['pathssubdirroot'] = 'Absolutní cesta k adresáři s instalací Moodle';
+$string['pathssubwwwroot'] = 'Zadejte úplnou webovou adresu, na níž bude Moodle dostupný. Moodle potřebuje jedinečnou adresu, není možné jej provozovat na několika URL současně. Používáte-li několik veřejných domén, musíte si sami nastavit permanentní přesměrování na jednu z nich a tu pak použít. Pokud je váš server dostupný z vnější a z vnitřní sítě pod různými IP adresami, použijte jeho veřejnou adresu a nastavte si váš DNS server tak, že ji mohou používat i uživatelé z vnitřní sítě.';
 $string['pathsunsecuredataroot'] = 'Umístění datového adresáře není bezpečné';
 $string['pathswrongadmindir'] = 'Adresář pro správu serveru (admin) neexistuje';
 $string['phpextension'] = '{$a} PHP rozšíření';
-- 
1.7.9.5


From 4d8138c96aa2dc2089996fa714218db007f941ab Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Fri, 3 Aug 2012 00:24:55 +0200
Subject: [PATCH 339/903] MDL-34658 - Saving failed because missing or false
 values

---
 mod/feedback/item/numeric/lib.php |    7 ++++++-
 mod/feedback/lib.php              |    7 +++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/mod/feedback/item/numeric/lib.php b/mod/feedback/item/numeric/lib.php
index 829dd1b..86d4be0 100644
--- a/mod/feedback/item/numeric/lib.php
+++ b/mod/feedback/item/numeric/lib.php
@@ -540,8 +540,13 @@ class feedback_item_numeric extends feedback_item_base {
     }
 
     public function clean_input_value($value) {
+        $value = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $value);
         if (!is_numeric($value)) {
-            return null;
+            if ($value == '') {
+                return null; //an empty string should be null
+            } else {
+                return clean_param($value, PARAM_TEXT); //we have to know the value if it is wrong
+            }
         }
         return clean_param($value, $this->value_type());
     }
diff --git a/mod/feedback/lib.php b/mod/feedback/lib.php
index 8705bbc..8c6dd59 100644
--- a/mod/feedback/lib.php
+++ b/mod/feedback/lib.php
@@ -2203,10 +2203,13 @@ function feedback_check_values($firstitem, $lastitem) {
         $formvalname = $item->typ . '_' . $item->id;
 
         if ($itemobj->value_is_array()) {
-            $value = optional_param_array($formvalname, null, $itemobj->value_type());
+            //get the raw value here. It is cleaned after that by the object itself
+            $value = optional_param_array($formvalname, null, PARAM_RAW);
         } else {
-            $value = optional_param($formvalname, null, $itemobj->value_type());
+            //get the raw value here. It is cleaned after that by the object itself
+            $value = optional_param($formvalname, null, PARAM_RAW);
         }
+        $value = $itemobj->clean_input_value($value);
 
         //check if the value is set
         if (is_null($value) AND $item->required == 1) {
-- 
1.7.9.5


From 2963abadf9f76b998fff47defda5f3797a438e5b Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 27 Jul 2012 13:19:17 +0100
Subject: [PATCH 340/903] MDL-34590 javascript-static: full-screep popups for
 Chrome.

I have left in both:
1. the code to get the window size correct initially, becuase that seems
sensible; and
2. the subsequent resize (with the setTimeout that Chrome requires,
thanks Jeff Rader for finding that) becuase on Chrome, it gets the size
a bit too big initially, so this correction is necessary.
---
 lib/javascript-static.js |   14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 463f824..f802776 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1182,13 +1182,23 @@ function openpopup(event, args) {
     if (!args.url.match(/https?:\/\//)) {
         fullurl = M.cfg.wwwroot + args.url;
     }
+    if (args.fullscreen) {
+        args.options = args.options.
+                replace(/top=\d+/, 'top=0').
+                replace(/left=\d+/, 'left=0').
+                replace(/width=\d+/, 'width=' + screen.availWidth).
+                replace(/height=\d+/, 'height=' + screen.availHeight);
+    }
     var windowobj = window.open(fullurl,args.name,args.options);
     if (!windowobj) {
         return true;
     }
+
     if (args.fullscreen) {
-        windowobj.moveTo(0,0);
-        windowobj.resizeTo(screen.availWidth,screen.availHeight);
+        setTimeout(function() {
+            windowobj.moveTo(0, 0);
+            windowobj.resizeTo(screen.availWidth, screen.availHeight)
+        }, 0);
     }
     windowobj.focus();
 
-- 
1.7.9.5


From e071bc1aa4366ceb44466afa0bcec81e7d294f6c Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 2 Aug 2012 17:21:32 +0100
Subject: [PATCH 341/903] MDL-34704 couse, accesslib: improve
 $CFG->courselistshortnames

1. get_context_name should respect the $CFG->courselistshortnames
setting.

2. When $CFG->courselistshortnames is on, what to display should use a
language string, rather than string concatenation. This makes it
possible for people to configure the display. For example, they might
want 'My first course [M101]' instead of 'M101 My first course'.
---
 course/lib.php     |   16 ----------------
 lang/en/admin.php  |    4 ++--
 lang/en/moodle.php |    1 +
 lib/accesslib.php  |    2 +-
 lib/moodlelib.php  |   16 ++++++++++++++++
 5 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index a2ff961..f799b0d 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -2256,22 +2256,6 @@ function make_categories_options() {
 }
 
 /**
- * Gets the name of a course to be displayed when showing a list of courses.
- * By default this is just $course->fullname but user can configure it. The
- * result of this function should be passed through print_string.
- * @param object $course Moodle course object
- * @return string Display name of course (either fullname or short + fullname)
- */
-function get_course_display_name_for_list($course) {
-    global $CFG;
-    if (!empty($CFG->courselistshortnames)) {
-        return $course->shortname . ' ' .$course->fullname;
-    } else {
-        return $course->fullname;
-    }
-}
-
-/**
  * Prints the category info in indented fashion
  * This function is only used by print_whole_category_list() above
  */
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 974b2bc..6b571c4 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -352,8 +352,8 @@ $string['cookiesecure'] = 'Secure cookies only';
 $string['country'] = 'Default country';
 $string['coursecontact'] = 'Course contacts';
 $string['coursecontact_desc'] = 'This setting allows you to control who appears on the course description. Users need to have at least one of these roles in a course to be shown on the course description for that course.';
-$string['courselistshortnames'] = 'Display short names';
-$string['courselistshortnames_desc'] = 'Show short name as well as full name when displaying lists of courses.';
+$string['courselistshortnames'] = 'Display extended course names';
+$string['courselistshortnames_desc'] = 'When showing lists of courses, or when referring to courses on administration screens, show the course short name as well as the full name. In fact, when you turn this setting on, the display uses the \'courseextendednamedisplay\' language string, so you can changewhat is displayed using Language customisation.';
 $string['coursemgmt'] = 'Add/edit courses';
 $string['courseoverview'] = 'Course overview';
 $string['courserequestnotify'] = 'Course request notification';
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index ec475fa..377b840 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -299,6 +299,7 @@ $string['coursedisplay_help'] = 'This setting determines whether the whole cours
 $string['coursedisplay_single'] = 'Show all sections on one page';
 $string['coursedisplay_multi'] = 'Show one section per page';
 $string['coursedeleted'] = 'Deleted course {$a}';
+$string['courseextendednamedisplay'] = '{$a->shortname} {$a->fullname}';
 $string['coursefiles'] = 'Legacy course files';
 $string['coursefilesedit'] = 'Edit legacy course files';
 $string['coursefileswarning'] = 'Course files are deprecated';
diff --git a/lib/accesslib.php b/lib/accesslib.php
index b8aa9f9..c62dae4 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -6319,7 +6319,7 @@ class context_course extends context {
                 if ($short){
                     $name .= format_string($course->shortname, true, array('context' => $this));
                 } else {
-                    $name .= format_string($course->fullname);
+                    $name .= format_string(get_course_display_name_for_list($course));
                }
             }
         }
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 6591795..b609389 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -10781,6 +10781,22 @@ function get_home_page() {
 }
 
 /**
+ * Gets the name of a course to be displayed when showing a list of courses.
+ * By default this is just $course->fullname but user can configure it. The
+ * result of this function should be passed through print_string.
+ * @param object $course Moodle course object
+ * @return string Display name of course (either fullname or short + fullname)
+ */
+function get_course_display_name_for_list($course) {
+    global $CFG;
+    if (!empty($CFG->courselistshortnames)) {
+        return get_string('courseextendednamedisplay', '', $course);
+    } else {
+        return $course->fullname;
+    }
+}
+
+/**
  * The lang_string class
  *
  * This special class is used to create an object representation of a string request.
-- 
1.7.9.5


From abdc9e17faac9c80a529df5d1eee694c860254bb Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 4 Aug 2012 00:31:59 +0000
Subject: [PATCH 342/903] Automatically generated installer lang files

---
 install/lang/lt/moodle.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/lt/moodle.php b/install/lang/lt/moodle.php
index abfff84..aa66eff 100644
--- a/install/lang/lt/moodle.php
+++ b/install/lang/lt/moodle.php
@@ -31,6 +31,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['language'] = 'Kalba';
-$string['next'] = 'Toliau';
+$string['next'] = 'Pirmyn';
 $string['previous'] = 'Ankstesnis';
 $string['reload'] = 'Įkelti iš naujo';
-- 
1.7.9.5


From 142b18a835ee51f9f2d1ede3f3497208f55b792f Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Sat, 4 Aug 2012 17:03:39 +0800
Subject: [PATCH 343/903] MDL-34560 accessibility compliance for message: Add
 label for  input text and select tag

---
 lang/en/message.php |    1 +
 message/lib.php     |    7 ++++---
 message/search.html |    1 +
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/lang/en/message.php b/lang/en/message.php
index 10c83e8..5594c8c 100644
--- a/lang/en/message.php
+++ b/lang/en/message.php
@@ -80,6 +80,7 @@ $string['maxmessages'] = 'Maximum number of messages to show in the discussion h
 $string['message'] = 'Message';
 $string['messagehistory'] = 'Message history';
 $string['messagehistoryfull'] = 'All messages';
+$string['messagenavigation'] = 'Message navigation:';
 $string['messages'] = 'Messages';
 $string['messaging'] = 'Messaging';
 $string['messagingblockednoncontact'] = '{$a} will not be able to reply as you have blocked non-contacts';
diff --git a/message/lib.php b/message/lib.php
index feb364b..1e759d6 100644
--- a/message/lib.php
+++ b/message/lib.php
@@ -507,9 +507,10 @@ function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $
     }
 
     echo html_writer::start_tag('form', array('id' => 'usergroupform','method' => 'get','action' => ''));
-        echo html_writer::start_tag('fieldset');
-            echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
-        echo html_writer::end_tag('fieldset');
+    echo html_writer::start_tag('fieldset');
+    echo html_writer::label(get_string('messagenavigation', 'message'), 'viewing');
+    echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
+    echo html_writer::end_tag('fieldset');
     echo html_writer::end_tag('form');
 }
 
diff --git a/message/search.html b/message/search.html
index 7adedc2..b396135 100644
--- a/message/search.html
+++ b/message/search.html
@@ -4,6 +4,7 @@
     <tr>
         <td colspan="3" class="message_heading mdl-left">
             <input type="hidden" name="sesskey" value="<?php p(sesskey()); ?>" />
+            <label for="combinedsearch" class="accesshide"><?php print_string('searchcombined', 'message'); ?></label>
             <input type="text" name="combinedsearch" size="40" id="combinedsearch" value="<?php p($combinedsearchstring); ?>" />
             <input type="submit" name="combinedsubmit" value="<?php print_string('searchcombined','message') ?>" />
             <a href="index.php?usergroup=<?php echo MESSAGE_VIEW_SEARCH ?>&advanced=1" id="advancedcontactsearchlink"><?php print_string('advanced') ?></a>
-- 
1.7.9.5


From 201816346877bde81b2673908efd2bb598fdccf5 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Sun, 5 Aug 2012 23:27:31 +0800
Subject: [PATCH 344/903] MDL-34708 Forms library : Fixed incorrect calendar
 day displayed across timezones. Credit to Matthew
 Davidson and team at rose-hulman.edu.

---
 lib/formslib.php |   38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/lib/formslib.php b/lib/formslib.php
index 77b960e..31a5419 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -81,25 +81,25 @@ function form_init_date_js() {
         $function = 'M.form.dateselector.init_date_selectors';
         $config = array(array(
             'firstdayofweek'    =>  get_string('firstdayofweek', 'langconfig'),
-            'mon'               => strftime('%a', 360000),      // 5th Jan 1970 at 12pm
-            'tue'               => strftime('%a', 446400),
-            'wed'               => strftime('%a', 532800),
-            'thu'               => strftime('%a', 619200),
-            'fri'               => strftime('%a', 705600),
-            'sat'               => strftime('%a', 792000),
-            'sun'               => strftime('%a', 878400),
-            'january'           => strftime('%B', 14400),       // 1st Jan 1970 at 12pm
-            'february'          => strftime('%B', 2692800),
-            'march'             => strftime('%B', 5112000),
-            'april'             => strftime('%B', 7790400),
-            'may'               => strftime('%B', 10382400),
-            'june'              => strftime('%B', 13060800),
-            'july'              => strftime('%B', 15652800),
-            'august'            => strftime('%B', 18331200),
-            'september'         => strftime('%B', 21009600),
-            'october'           => strftime('%B', 23601600),
-            'november'          => strftime('%B', 26280000),
-            'december'          => strftime('%B', 28872000)
+            'mon'               => strftime('%a', strtotime("Monday")),      // 5th Jan 1970 at 12pm
+            'tue'               => strftime('%a', strtotime("Tuesday")),
+            'wed'               => strftime('%a', strtotime("Wednesday")),
+            'thu'               => strftime('%a', strtotime("Thursday")),
+            'fri'               => strftime('%a', strtotime("Friday")),
+            'sat'               => strftime('%a', strtotime("Saturday")),
+            'sun'               => strftime('%a', strtotime("Sunday")),
+            'january'           => strftime('%B', strtotime("January")),       // 1st Jan 1970 at 12pm
+            'february'          => strftime('%B', strtotime("February")),
+            'march'             => strftime('%B', strtotime("March")),
+            'april'             => strftime('%B', strtotime("April")),
+            'may'               => strftime('%B', strtotime("May")),
+            'june'              => strftime('%B', strtotime("June")),
+            'july'              => strftime('%B', strtotime("July")),
+            'august'            => strftime('%B', strtotime("August")),
+            'september'         => strftime('%B', strtotime("September")),
+            'october'           => strftime('%B', strtotime("October")),
+            'november'          => strftime('%B', strtotime("November")),
+            'december'          => strftime('%B', strtotime("December"))
         ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
-- 
1.7.9.5


From 5f152b5c900a9ab5dc200332c7ade5692bcf986b Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Thu, 2 Aug 2012 23:03:26 +0200
Subject: [PATCH 345/903] MDL-34670 - undefined variable  in feedback
 templates

---
 mod/feedback/edit_form.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/feedback/edit_form.php b/mod/feedback/edit_form.php
index 281e596..84ec317 100644
--- a/mod/feedback/edit_form.php
+++ b/mod/feedback/edit_form.php
@@ -123,11 +123,11 @@ class feedback_edit_use_template_form extends moodleform {
             $elementgroup[] = $mform->createElement('submit',
                                                      'use_template',
                                                      get_string('use_this_template', 'feedback'));
+
+            $mform->addGroup($elementgroup, 'elementgroup', '', array(' '), false);
         } else {
             $mform->addElement('static', 'info', get_string('no_templates_available_yet', 'feedback'));
         }
-        $mform->addGroup($elementgroup, 'elementgroup', '', array(' '), false);
-
     }
 }
 
-- 
1.7.9.5


From d939a4dec8c3c74ef4969329f4b0a382f58a83de Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 6 Aug 2012 09:25:24 +0800
Subject: [PATCH 346/903] MDL-28486 - tests: fix broken youtube tests

---
 lib/tests/medialib_test.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/tests/medialib_test.php b/lib/tests/medialib_test.php
index dd12e90..8df9c7d 100644
--- a/lib/tests/medialib_test.php
+++ b/lib/tests/medialib_test.php
@@ -338,13 +338,13 @@ class medialib_testcase extends advanced_testcase {
         // Format: youtube playlist.
         $url = new moodle_url('http://www.youtube.com/view_play_list?p=PL6E18E2927047B662');
         $t = $renderer->embed_url($url);
-        $this->assertTrue(self::str_contains($t, '</object>'));
+        $this->assertTrue(self::str_contains($t, '</iframe>'));
         $url = new moodle_url('http://www.youtube.com/playlist?list=PL6E18E2927047B662');
         $t = $renderer->embed_url($url);
-        $this->assertTrue(self::str_contains($t, '</object>'));
+        $this->assertTrue(self::str_contains($t, '</iframe>'));
         $url = new moodle_url('http://www.youtube.com/p/PL6E18E2927047B662');
         $t = $renderer->embed_url($url);
-        $this->assertTrue(self::str_contains($t, '</object>'));
+        $this->assertTrue(self::str_contains($t, '</iframe>'));
 
         // Format: vimeo.
         $url = new moodle_url('http://vimeo.com/1176321');
-- 
1.7.9.5


From ea22072a6232edf194f271d4db1bbb18c78d24a0 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 6 Aug 2012 12:08:35 +0800
Subject: [PATCH 347/903] MDL-34575 lang/notes: reorder string to be
 alphabetical

---
 lang/en/notes.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/notes.php b/lang/en/notes.php
index e176ce8..bfe2bf4 100644
--- a/lang/en/notes.php
+++ b/lang/en/notes.php
@@ -58,7 +58,7 @@ $string['publishstate_help'] = 'A note\'s context determines who can see the not
 * Personal - The note will be visible only to you
 * Course - The note will be visible to teachers in this course
 * Site - The note will be visible to teachers in all courses';
+$string['selectnotestate'] = "Select note state";
 $string['site'] = 'site';
 $string['sitenotes'] = 'Site notes';
-$string['selectnotestate'] = "Select note state";
 $string['unknown'] = 'unknown';
-- 
1.7.9.5


From cf162f933283ad830d5cd36094df2a820688c71e Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Sat, 28 Jul 2012 17:22:44 -0400
Subject: [PATCH 348/903] MDL-34629 wiki: convert default format value during
 restore

---
 mod/wiki/backup/moodle1/lib.php |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/mod/wiki/backup/moodle1/lib.php b/mod/wiki/backup/moodle1/lib.php
index 199f850..10cc4f7 100644
--- a/mod/wiki/backup/moodle1/lib.php
+++ b/mod/wiki/backup/moodle1/lib.php
@@ -135,6 +135,8 @@ class moodle1_mod_wiki_handler extends moodle1_mod_handler {
      * data available
      */
     public function process_wiki($data) {
+        global $CFG;    // We need to check a config setting.
+
         if (!empty($data['initialcontent'])) {
             //convert file in <INITIALCONTENT>filename</INITIALCONTENT> into a subwiki page if no entry created.
             $temppath = $this->converter->get_tempdir_path();
@@ -168,6 +170,12 @@ class moodle1_mod_wiki_handler extends moodle1_mod_handler {
         $this->fileman->itemid   = 0;
         $data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);
 
+        // convert the introformat if necessary
+        if ($CFG->texteditors !== 'textarea') {
+            $data['intro'] = text_to_html($data['intro'], false, false, true);
+            $data['introformat'] = FORMAT_HTML;
+        }
+
         // we now have all information needed to start writing into the file
         $this->open_xml_writer("activities/wiki_{$this->moduleid}/wiki.xml");
         $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
-- 
1.7.9.5


From ac1bbfa1cd7fcb8fa5be0b88342c9c31dc2a1a2b Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 6 Aug 2012 15:07:52 +0800
Subject: [PATCH 349/903] MDL-34561 accessibility compliance for assignment
 module: add accesshide class

---
 mod/assignment/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assignment/lib.php b/mod/assignment/lib.php
index 3266274..0104331 100644
--- a/mod/assignment/lib.php
+++ b/mod/assignment/lib.php
@@ -1475,7 +1475,7 @@ class assignment_base {
                                 } else if ($quickgrade) {
                                     $attributes = array();
                                     $attributes['tabindex'] = $tabindex++;
-                                    $menu = html_writer::label(get_string('assignment:grade', 'assignment'), 'menumenu'. $auser->id, false, array('class' => ''));
+                                    $menu = html_writer::label(get_string('assignment:grade', 'assignment'), 'menumenu'. $auser->id, false, array('class' => 'accesshide'));
                                     $menu .= html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes);
                                     $grade = '<div id="g'.$auser->id.'">'. $menu .'</div>';
                                 } else {
-- 
1.7.9.5


From 2ab9801b192630508f26fb043b9bd4d04ef8f495 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 6 Aug 2012 16:26:28 +0800
Subject: [PATCH 350/903] MDL-34562 accessibility compliance for chat module:
 Add <label> for input text and select tag

---
 mod/chat/gui_ajax/index.php          |    2 +-
 mod/chat/gui_header_js/chatinput.php |    1 +
 mod/chat/gui_sockets/chatinput.php   |    1 +
 mod/chat/lang/en/chat.php            |    1 +
 4 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/mod/chat/gui_ajax/index.php b/mod/chat/gui_ajax/index.php
index db7f340..a2706e6 100644
--- a/mod/chat/gui_ajax/index.php
+++ b/mod/chat/gui_ajax/index.php
@@ -77,7 +77,7 @@ echo $OUTPUT->box('', '', 'chat-options');
 echo $OUTPUT->box('<ul id="messages-list"></ul>', '', 'chat-messages');
 $table = new html_table();
 $table->data = array(
-    array(' &raquo; <input type="text" disabled="true" id="input-message" value="Loading..." size="50" /> <input type="button" id="button-send" value="'.get_string('send', 'chat').'" /> <a id="choosetheme" href="###">'.get_string('themes').' &raquo; </a>')
+    array(' &raquo; <label class="accesshide" for="input-message">' . get_string('entermessage', 'chat') . ' </label><input type="text" disabled="true" id="input-message" value="Loading..." size="50" /> <input type="button" id="button-send" value="'.get_string('send', 'chat').'" /> <a id="choosetheme" href="###">'.get_string('themes').' &raquo; </a>')
 );
 echo $OUTPUT->box(html_writer::table($table), '', 'chat-input-area');
 echo $OUTPUT->box('', '', 'chat-notify');
diff --git a/mod/chat/gui_header_js/chatinput.php b/mod/chat/gui_header_js/chatinput.php
index a228a92..02545f5 100644
--- a/mod/chat/gui_header_js/chatinput.php
+++ b/mod/chat/gui_header_js/chatinput.php
@@ -46,6 +46,7 @@ $PAGE->set_cacheable(false);
 echo $OUTPUT->header();
 
 echo html_writer::start_tag('form', array('action'=>'../empty.php', 'method'=>'post', 'target'=>'empty', 'id'=>'inputForm', 'style'=>'margin:0'));
+echo html_writer::label(get_string('entermessage', 'chat'), 'input_chat_message', false, array('class' => 'accesshide'));
 echo html_writer::empty_tag('input', array('type'=>'text', 'id'=>'input_chat_message', 'name'=>'chat_message', 'size'=>'50', 'value'=>''));
 echo html_writer::empty_tag('input', array('type'=>'checkbox', 'id'=>'auto', 'checked'=>'checked', 'value'=>''));
 echo html_writer::tag('label', get_string('autoscroll', 'chat'), array('for'=>'auto'));
diff --git a/mod/chat/gui_sockets/chatinput.php b/mod/chat/gui_sockets/chatinput.php
index fe369b5..237f488 100644
--- a/mod/chat/gui_sockets/chatinput.php
+++ b/mod/chat/gui_sockets/chatinput.php
@@ -28,6 +28,7 @@ echo $OUTPUT->header();
 
     <form action="../empty.php" method="get" target="empty" id="inputform"
           onsubmit="return empty_field_and_submit();">
+        <label class="accesshide" for="chat_message"><?php print_string('entermessage', 'chat'); ?></label>
         <input type="text" name="chat_message" id="chat_message" size="60" value="" />
         <?php echo $OUTPUT->help_icon('usingchat', 'chat'); ?>
     </form>
diff --git a/mod/chat/lang/en/chat.php b/mod/chat/lang/en/chat.php
index 662aadc..facf60f 100644
--- a/mod/chat/lang/en/chat.php
+++ b/mod/chat/lang/en/chat.php
@@ -58,6 +58,7 @@ $string['chat:readlog'] = 'Read chat logs';
 $string['chatreport'] = 'Chat sessions';
 $string['chat:talk'] = 'Talk in a chat';
 $string['chattime'] = 'Next chat time';
+$string['entermessage'] = "Enter your message";
 $string['idle'] = 'Idle';
 $string['inputarea'] = 'Input area';
 $string['invalidid'] = 'Could not find that chat room!';
-- 
1.7.9.5


From 5f2f276f82c7e4afe89aae4202b93567e3e31957 Mon Sep 17 00:00:00 2001
From: Kirill Astashov <kirill.astashov@netspot.com.au>
Date: Mon, 6 Aug 2012 16:57:24 +0800
Subject: [PATCH 351/903] MDL-34669: Fix editor filepicker context bt trying
 to use page context

---
 lib/form/editor.php |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lib/form/editor.php b/lib/form/editor.php
index 50d32ef..99ee930 100644
--- a/lib/form/editor.php
+++ b/lib/form/editor.php
@@ -80,7 +80,12 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
             $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
         }
         if (!$this->_options['context']) {
-            $this->_options['context'] = get_context_instance(CONTEXT_SYSTEM);
+            // trying to set context to the current page context to make legacy files show in filepicker (e.g. forum post)
+            if (!empty($PAGE->context->id)) {
+                $this->_options['context'] = $PAGE->context;
+            } else {
+                $this->_options['context'] = context_system::instance();
+            }
         }
         $this->_options['trusted'] = trusttext_trusted($this->_options['context']);
         parent::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-- 
1.7.9.5


From 9881439068e63cd93dd653cd05f9aced59f42c20 Mon Sep 17 00:00:00 2001
From: Tomasz Muras <nexor1984@gmail.com>
Date: Thu, 23 Feb 2012 11:51:03 +0000
Subject: [PATCH 352/903] MDL-31753 Get correct course ID for Community finder
 search link.

---
 blocks/community/block_community.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/blocks/community/block_community.php b/blocks/community/block_community.php
index c3071c4..35e3f2e 100644
--- a/blocks/community/block_community.php
+++ b/blocks/community/block_community.php
@@ -71,7 +71,7 @@ class block_community extends block_list {
         $icon = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('i/group'),
                     'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
         $addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
-                        array('add' => true, 'courseid' => $coursecontext->instanceid));
+                        array('add' => true, 'courseid' => $this->page->course->id));
         $searchlink = html_writer::tag('a', $icon . '&nbsp;' . get_string('addcourse', 'block_community'),
                         array('href' => $addcourseurl->out(false)));
         $this->content->items[] = $searchlink;
@@ -91,7 +91,7 @@ class block_community extends block_list {
                                     'alt' => get_string('removecommunitycourse', 'block_community')));
                 $deleteurl = new moodle_url('/blocks/community/communitycourse.php',
                                 array('remove' => true,
-                                    'courseid' => $coursecontext->instanceid,
+                                    'courseid' => $this->page->course->id,
                                     'communityid' => $course->id, 'sesskey' => sesskey()));
                 $deleteatag = html_writer::tag('a', $deleteicon, array('href' => $deleteurl));
 
-- 
1.7.9.5


From d8ff3aae9f4c234b592eca6577a3af4f64d1dc1e Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 7 Aug 2012 00:31:55 +0000
Subject: [PATCH 353/903] Automatically generated installer lang files

---
 install/lang/nl/langconfig.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/nl/langconfig.php b/install/lang/nl/langconfig.php
index 5591fe5..705cb6c 100644
--- a/install/lang/nl/langconfig.php
+++ b/install/lang/nl/langconfig.php
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Nederlands';
-- 
1.7.9.5


From b97532dd8e5164c00bebbba50c0fabfdb4eb9bb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 27 Jul 2012 10:49:16 +0200
Subject: [PATCH 354/903] MDL-34600 fix question table to match install.xml

The oldquestiontextformat was used during previous upgrade and is not necessary any more.
Next time we should add these temporary upgrade columns to install.xml files.
---
 lib/db/upgrade.php |   13 +++++++++++++
 version.php        |    2 +-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index c948d5f..2bc7149 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -937,5 +937,18 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.06);
     }
 
+    if ($oldversion < 2012062501.08) {
+        // Drop obsolete question upgrade field that should have been added to the install.xml.
+        $table = new xmldb_table('question');
+        $field = new xmldb_field('oldquestiontextformat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
+
+        if ($dbman->field_exists($table, $field)) {
+            $dbman->drop_field($table, $field);
+        }
+
+        upgrade_main_savepoint(true, 2012062501.08);
+    }
+
+    
     return true;
 }
diff --git a/version.php b/version.php
index b4eb988..2d2dea3 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.07;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.08;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From ebc5b65ab3504ca9b1a7941c21e6b882ecdbe297 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 7 Aug 2012 08:42:03 +0800
Subject: [PATCH 355/903] MDL-34600 upgrade.php - fix trailing whitespace

---
 lib/db/upgrade.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 2bc7149..dcb9f2d 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -949,6 +949,5 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.08);
     }
 
-    
     return true;
 }
-- 
1.7.9.5


From 74b83c18fb38db78ce89106fb4c8786331fc5e2f Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 7 Aug 2012 13:36:43 +0800
Subject: [PATCH 356/903] MDL-34559: removing accesshide class

---
 grade/edit/tree/index.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php
index b044fe0..8208c45 100644
--- a/grade/edit/tree/index.php
+++ b/grade/edit/tree/index.php
@@ -343,7 +343,7 @@ if (!$moving && count($grade_edit_tree->categories) > 1) {
     echo '<br /><br />';
     echo '<input type="hidden" name="bulkmove" value="0" id="bulkmoveinput" />';
     $attributes = array('id'=>'menumoveafter');
-    echo html_writer::label(get_string('moveselectedto', 'grades'), 'menumoveafter', false, array('class' => 'accesshide'));
+    echo html_writer::label(get_string('moveselectedto', 'grades'), 'menumoveafter');
     echo html_writer::select($grade_edit_tree->categories, 'moveafter', '', array(''=>'choosedots'), $attributes);
     $OUTPUT->add_action_handler(new component_action('change', 'submit_bulk_move'), 'menumoveafter');
     echo '<div id="noscriptgradetreeform" class="hiddenifjs">
-- 
1.7.9.5


From e83629096b727db45ab9b29d4738ae395fcfab0f Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Tue, 7 Aug 2012 14:27:55 +0800
Subject: [PATCH 357/903] Revert "Merge branch 'MDL-28531-23' of
 git://github.com/FMCorz/moodle into
 MOODLE_23_STABLE"

This reverts commit 162510801f6c639ac07632b7a0a8ef1e6c90e7fa, reversing
changes made to 5af69f5282a282b4ef1cdce9291865ed20f6f185.
---
 backup/util/helper/backup_cron_helper.class.php |   70 ++---
 lib/moodlelib.php                               |    4 +-
 lib/tests/backup_test.php                       |  336 +++--------------------
 3 files changed, 66 insertions(+), 344 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 353d451..00db13d 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -110,7 +110,7 @@ abstract class backup_cron_automated_helper {
             $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
             $showtime = "undefined";
             if ($nextstarttime > 0) {
-                $showtime = date('r', $nextstarttime);
+                $showtime = userdate($nextstarttime,"",$admin->timezone);
             }
 
             $rs = $DB->get_recordset('course');
@@ -124,14 +124,7 @@ abstract class backup_cron_automated_helper {
                 }
 
                 // Skip courses that do not yet need backup
-                $skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
-                if ($skipped && $backupcourse->nextstarttime != $nextstarttime) {
-                    $backupcourse->nextstarttime = $nextstarttime;
-                    $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
-                    $DB->update_record('backup_courses', $backupcourse);
-                    mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
-                }
-
+                $skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
                 // Skip backup of unavailable courses that have remained unmodified in a month
                 if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + settings were unmodified last month
                     //Check log if there were any modifications to the course content
@@ -146,10 +139,9 @@ abstract class backup_cron_automated_helper {
                         $skipped = true;
                     }
                 }
-
                 //Now we backup every non-skipped course
                 if (!$skipped) {
-                    mtrace('Backing up '.$course->fullname.'...');
+                    mtrace('Backing up '.$course->fullname, '...');
 
                     //We have to send a email because we have included at least one backup
                     $emailpending = true;
@@ -278,47 +270,38 @@ abstract class backup_cron_automated_helper {
     /**
      * Works out the next time the automated backup should be run.
      *
-     * @param mixed $timezone user timezone
-     * @param int $now timestamp, should not be in the past, most likely time()
-     * @return int timestamp of the next execution at server time
+     * @param mixed $timezone
+     * @param int $now
+     * @return int
      */
     public static function calculate_next_automated_backup($timezone, $now) {
 
-        $result = 0;
+        $result = -1;
         $config = get_config('backup');
-        $autohour = $config->backup_auto_hour;
-        $automin = $config->backup_auto_minute;
-
-        // Gets the user time relatively to the server time.
+        $midnight = usergetmidnight($now, $timezone);
         $date = usergetdate($now, $timezone);
-        $usertime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
-        $diff = $now - $usertime;
 
-        // Get number of days (from user's today) to execute backups.
+        // Get number of days (from today) to execute backups
         $automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
-        $daysfromnow = strpos($automateddays, "1");
+        $daysfromtoday = strpos($automateddays, "1", 1);
 
-        // Error, there are no days to schedule the backup for.
-        if ($daysfromnow === false) {
-            return 0;
+        // If we can't find the next day, we set it to tomorrow
+        if (empty($daysfromtoday)) {
+            $daysfromtoday = 1;
         }
 
-        // Checks if the date would happen in the future (of the user).
-        $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
-        if ($userresult <= $usertime) {
-            // If not, we skip the first scheduled day, that should fix it.
-            $daysfromnow = strpos($automateddays, "1", 1);
-            $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
+        // If some day has been found
+        if ($daysfromtoday !== false) {
+            // Calculate distance
+            $dist = ($daysfromtoday * 86400) +                // Days distance
+                    ($config->backup_auto_hour * 3600) +      // Hours distance
+                    ($config->backup_auto_minute * 60);       // Minutes distance
+            $result = $midnight + $dist;
         }
 
-        // Now we generate the time relative to the server.
-        $result = $userresult + $diff;
-
-        // If that time is past, call the function recursively to obtain the next valid day.
-        if ($result <= $now) {
-            // Checking time() in here works, but makes PHPUnit Tests extremely hard to predict.
-            // $now should never be earlier than time() anyway...
-            $result = self::calculate_next_automated_backup($timezone, $now + DAYSECS);
+        // If that time is past, call the function recursively to obtain the next valid day
+        if ($result > 0 && $result < time()) {
+            $result = self::calculate_next_automated_backup($timezone, $result);
         }
 
         return $result;
@@ -428,12 +411,7 @@ abstract class backup_cron_automated_helper {
 
         $config = get_config('backup');
         $active = (int)$config->backup_auto_active;
-        $weekdays = (string)$config->backup_auto_weekdays;
-
-        // In case of automated backup also check that it is scheduled for at least one weekday.
-        if ($active === self::AUTO_BACKUP_DISABLED ||
-                ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL) ||
-                ($rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false)) {
+        if ($active === self::AUTO_BACKUP_DISABLED || ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL)) {
             return self::STATE_DISABLED;
         } else if (!empty($config->backup_auto_running)) {
             // Detect if the backup_auto_running semaphore is a valid one
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 5cf0b7e..6591795 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -2324,10 +2324,10 @@ function get_user_timezone($tz = 99) {
 
     $tz = 99;
 
-    // Loop while $tz is, empty but not zero, or 99, and there is another timezone is the array
-    while(((empty($tz) && !is_numeric($tz)) || $tz == 99) && $next = each($timezones)) {
+    while(($tz == '' || $tz == 99 || $tz == NULL) && $next = each($timezones)) {
         $tz = $next['value'];
     }
+
     return is_numeric($tz) ? (float) $tz : $tz;
 }
 
diff --git a/lib/tests/backup_test.php b/lib/tests/backup_test.php
index 5b44435..1830f56 100644
--- a/lib/tests/backup_test.php
+++ b/lib/tests/backup_test.php
@@ -36,405 +36,149 @@ class backup_testcase extends advanced_testcase {
     public function test_next_automated_backup() {
 
         $this->resetAfterTest();
-        set_config('backup_auto_active', '1', 'backup');
+        $admin = get_admin();
+        $timezone = $admin->timezone;
 
         // Notes
+        // - The next automated backup will never be on the same date than $now
         // - backup_auto_weekdays starts on Sunday
-        // - Tests cannot be done in the past
-        // - Only the DST on the server side is handled.
+        // - Tests cannot be done in the past.
 
-        // Every Tue and Fri at 11pm.
+        // Every Wed and Sat at 11pm.
+        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '0010010', 'backup');
         set_config('backup_auto_hour', '23', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
 
-        $now = strtotime('next Monday 17:00:00');
+        $now = strtotime('next Monday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday 18:00:00');
+        $now = strtotime('next Tuesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday 17:00:00');
+        $now = strtotime('next Wednesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday 17:00:00');
+        $now = strtotime('next Thursday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday 17:00:00');
+        $now = strtotime('next Friday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday 17:00:00');
+        $now = strtotime('next Saturday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday 17:00:00');
+        $now = strtotime('next Sunday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
         // Every Sun and Sat at 12pm.
+        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000001', 'backup');
         set_config('backup_auto_hour', '0', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
 
-        $now = strtotime('next Monday 17:00:00');
+        $now = strtotime('next Monday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday 17:00:00');
+        $now = strtotime('next Tuesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday 17:00:00');
+        $now = strtotime('next Wednesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday 17:00:00');
+        $now = strtotime('next Thursday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday 17:00:00');
+        $now = strtotime('next Friday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday 17:00:00');
+        $now = strtotime('next Saturday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday 17:00:00');
+        $now = strtotime('next Sunday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
         // Every Sun at 4am.
+        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000000', 'backup');
         set_config('backup_auto_hour', '4', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
 
-        $now = strtotime('next Monday 17:00:00');
+        $now = strtotime('next Monday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday 17:00:00');
+        $now = strtotime('next Tuesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday 17:00:00');
+        $now = strtotime('next Wednesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday 17:00:00');
+        $now = strtotime('next Thursday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday 17:00:00');
+        $now = strtotime('next Friday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday 17:00:00');
+        $now = strtotime('next Saturday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday 17:00:00');
+        $now = strtotime('next Sunday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
         // Every day but Wed at 8:30pm.
+        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1110111', 'backup');
         set_config('backup_auto_hour', '20', 'backup');
         set_config('backup_auto_minute', '30', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('1-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday 17:00:00');
+        $now = strtotime('next Monday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday 17:00:00');
+        $now = strtotime('next Tuesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday 17:00:00');
+        $now = strtotime('next Wednesday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Friday 17:00:00');
+        $now = strtotime('next Thursday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday 17:00:00');
+        $now = strtotime('next Friday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday 17:00:00');
+        $now = strtotime('next Saturday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-20:30', date('w-H:i', $next));
 
-        // Sun, Tue, Thu, Sat at 12pm.
-        set_config('backup_auto_weekdays', '1010101', 'backup');
-        set_config('backup_auto_hour', '0', 'backup');
-        set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 13:00:00');
+        $now = strtotime('next Sunday');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-00:00', date('w-H:i', $next));
-
-        // None.
-        set_config('backup_auto_weekdays', '0000000', 'backup');
-        set_config('backup_auto_hour', '15', 'backup');
-        set_config('backup_auto_minute', '30', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Sunday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0', $next);
-
-        // Playing with timezones.
-        set_config('backup_auto_weekdays', '1111111', 'backup');
-        set_config('backup_auto_hour', '20', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        $timezone = 99;
-        date_default_timezone_set('Australia/Perth');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 99;
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 99;
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        // Viva Australia! (UTC+8).
-        date_default_timezone_set('Australia/Perth');
-        $now = strtotime('18:00:00');
-
-        $timezone = -10.0; // 12am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = -5.0; // 5am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 0.0;  // 10am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 3.0; // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 8.0; // 6pm for the user (same than the server).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 9.0; // 7pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
-
-        $timezone = 13.0; // 12am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('18:00:00');
-        $dst = date('I');
-
-        $timezone = -10.0; // 7am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -5.0; // 12pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 5pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-21:00') : date('w-22:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 8.0; // 1am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 9.0; // 2am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 13.0; // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // The big apple! (UTC-5 / UTC-4 DST).
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('18:00:00');
-        $dst = date('I');
-
-        $timezone = -10.0; // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -5.0; // 6pm for the user (server time).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-20:00') : date('w-21:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 11pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 3.0; // 2am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 8.0; // 7am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 9.0; // 8am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 13.0; // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // Some more timezone tests
-        set_config('backup_auto_weekdays', '0100001', 'backup');
-        set_config('backup_auto_hour', '20', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('next Monday 18:00:00');
-        $dst = date('I');
-
-        $timezone = -12.0;  // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '2-09:00' : '2-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -4.0;  // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '2-01:00' : '2-02:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 5pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-21:00' : '1-22:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 2.0;  // 7pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-19:00' : '1-20:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 4.0;  // 9pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-17:00' : '6-18:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 12.0;  // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-09:00' : '6-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // Some more timezone tests
-        set_config('backup_auto_weekdays', '0100001', 'backup');
-        set_config('backup_auto_hour', '02', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('next Monday 04:00:00');
-        $dst = date('I');
-
-        $timezone = -12.0;  // 8pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-09:00' : '1-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -4.0;  // 4am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-01:00' : '6-02:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 8am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-21:00' : '5-22:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 2.0;  // 10am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-19:00' : '5-20:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 4.0;  // 12pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-17:00' : '5-18:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 12.0;  // 8pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-09:00' : '5-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
 
     }
 }
-- 
1.7.9.5


From 57f9291b23410bc63f86b5ff8d42d7232c9569e1 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 3 Aug 2012 11:58:37 +0100
Subject: [PATCH 358/903] MDL-34727 restore UI: use checkboxes for userdata.

It was using select menus for the convenience of the code, but the
inconvenience of users.

The way this fix is done is a bit hacky, but it works, makes users'
lives much better, but it would be good if someone would dehackify
this in the future.
---
 backup/moodle2/restore_activity_task.class.php |   30 ++++++++++++++++++------
 backup/moodle2/restore_section_task.class.php  |   29 +++++++++++++++++------
 2 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/backup/moodle2/restore_activity_task.class.php b/backup/moodle2/restore_activity_task.class.php
index 6917b33..5838a8e 100644
--- a/backup/moodle2/restore_activity_task.class.php
+++ b/backup/moodle2/restore_activity_task.class.php
@@ -293,30 +293,46 @@ abstract class restore_activity_task extends restore_task {
         // Define activity_userinfo. Dependent of:
         // - users root setting
         // - section_userinfo setting (if exists)
-        // - activity_included setting
+        // - activity_included setting.
         $settingname = $settingprefix . 'userinfo';
-        $selectvalues = array(0=>get_string('no')); // Safer options
-        $defaultvalue = false;                      // Safer default
+        $defaultvalue = false;
         if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
-            $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
             $defaultvalue = true;
         }
+
         $activity_userinfo = new restore_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
-        $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+        if (!$defaultvalue) {
+            // This is a bit hacky, but if there is no user data to restore, then
+            // we replace the standard check-box with a select menu with the
+            // single choice 'No', and the select menu is clever enough that if
+            // there is only one choice, it just displays a static string.
+            //
+            // It would probably be better design to have a special UI class
+            // setting_ui_checkbox_or_no, rather than this hack, but I am not
+            // going to do that today.
+            $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, '-',
+                    array(0 => get_string('no'))));
+        } else {
+            $activity_userinfo->get_ui()->set_label('-');
+        }
+
         $this->add_setting($activity_userinfo);
+
         // Look for "users" root setting
         $users = $this->plan->get_setting('users');
         $users->add_dependency($activity_userinfo);
+
         // Look for "section_userinfo" section setting (if exists)
         $settingname = 'section_' . $this->info->sectionid . '_userinfo';
         if ($this->plan->setting_exists($settingname)) {
             $section_userinfo = $this->plan->get_setting($settingname);
             $section_userinfo->add_dependency($activity_userinfo);
         }
-        // Look for "activity_included" setting
+
+        // Look for "activity_included" setting.
         $activity_included->add_dependency($activity_userinfo);
 
-        // End of common activity settings, let's add the particular ones
+        // End of common activity settings, let's add the particular ones.
         $this->define_my_settings();
     }
 
diff --git a/backup/moodle2/restore_section_task.class.php b/backup/moodle2/restore_section_task.class.php
index 9d48778..9112ea7 100644
--- a/backup/moodle2/restore_section_task.class.php
+++ b/backup/moodle2/restore_section_task.class.php
@@ -169,21 +169,36 @@ class restore_section_task extends restore_task {
 
         // Define section_userinfo. Dependent of:
         // - users root setting
-        // - section_included setting
+        // - section_included setting.
         $settingname = $settingprefix . 'userinfo';
-        $selectvalues = array(0=>get_string('no')); // Safer options
-        $defaultvalue = false;                      // Safer default
+        $defaultvalue = false;
         if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
-            $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
             $defaultvalue = true;
         }
+
         $section_userinfo = new restore_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
-        $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+        if (!$defaultvalue) {
+            // This is a bit hacky, but if there is no user data to restore, then
+            // we replace the standard check-box with a select menu with the
+            // single choice 'No', and the select menu is clever enough that if
+            // there is only one choice, it just displays a static string.
+            //
+            // It would probably be better design to have a special UI class
+            // setting_ui_checkbox_or_no, rather than this hack, but I am not
+            // going to do that today.
+            $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'),
+                    array(0 => get_string('no'))));
+        } else {
+            $section_userinfo->get_ui()->set_label(get_string('includeuserinfo','backup'));
+        }
+
         $this->add_setting($section_userinfo);
-        // Look for "users" root setting
+
+        // Look for "users" root setting.
         $users = $this->plan->get_setting('users');
         $users->add_dependency($section_userinfo);
-        // Look for "section_included" section setting
+
+        // Look for "section_included" section setting.
         $section_included->add_dependency($section_userinfo);
     }
 }
-- 
1.7.9.5


From 4c60068485edc60fdb391f64ba020b33c7892ec0 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Tue, 7 Aug 2012 10:19:08 -0400
Subject: [PATCH 359/903] MDL-34543 mod_assign Fixing problem where previous
 feedback does not populate when you re-enter the
 grading view. add_plugin_grade_elements() was
 expecting grade object, but was being given grade
 string.

---
 mod/assign/locallib.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 8c538fd..a933ab5 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -2923,13 +2923,13 @@ class assign {
         }
 
         if (has_all_capabilities(array('gradereport/grader:view', 'moodle/grade:viewall'), $this->get_course_context())) {
-            $grade = $this->output->action_link(new moodle_url('/grade/report/grader/index.php',
+            $gradestring = $this->output->action_link(new moodle_url('/grade/report/grader/index.php',
                                                               array('id'=>$this->get_course()->id)),
                                                 $gradinginfo->items[0]->grades[$userid]->str_grade);
         } else {
-            $grade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+            $gradestring = $gradinginfo->items[0]->grades[$userid]->str_grade;
         }
-        $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':' ,$grade);
+        $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':', $gradestring);
 
 
         $mform->addElement('static', 'progress', '', get_string('gradingstudentprogress', 'assign', array('index'=>$rownum+1, 'count'=>count($useridlist))));
-- 
1.7.9.5


From c86262ed73172c33a087d0a2230a1aeb3f574af6 Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Tue, 31 Jul 2012 11:50:20 -0700
Subject: [PATCH 360/903] MDL-29129 wiki: fix a hardcoded string

---
 mod/wiki/lang/en/wiki.php |    1 +
 mod/wiki/pagelib.php      |    2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/wiki/lang/en/wiki.php b/mod/wiki/lang/en/wiki.php
index 9781d7b..1c929d9 100644
--- a/mod/wiki/lang/en/wiki.php
+++ b/mod/wiki/lang/en/wiki.php
@@ -169,6 +169,7 @@ $string['pageindex_help'] = 'This wiki\'s page tree';
 $string['pageislocked'] = 'Someone is editing this page right now. Try to edit it in a few minutes.';
 $string['pagelist'] = 'Page list';
 $string['pagelist_help'] = 'Page list categorized by alphabetical order';
+$string['pagename'] = 'Page name';
 $string['peerreview'] = 'Peer review';
 $string['pluginadministration'] = 'Wiki administration';
 $string['pluginname'] = 'Wiki';
diff --git a/mod/wiki/pagelib.php b/mod/wiki/pagelib.php
index 1652371..4fe9d50 100644
--- a/mod/wiki/pagelib.php
+++ b/mod/wiki/pagelib.php
@@ -2483,7 +2483,7 @@ class page_wiki_admin extends page_wiki {
     protected function print_delete_content($showorphan = true) {
         $contents = array();
         $table = new html_table();
-        $table->head = array('','Page name');
+        $table->head = array('', get_string('pagename','wiki'));
         $table->attributes['class'] = 'generaltable mdl-align';
         $swid = $this->subwiki->id;
         if ($showorphan) {
-- 
1.7.9.5


From ed10bfb2b04fa8881068cf73b853c5f1cfc38a52 Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Tue, 13 Mar 2012 04:15:27 -0700
Subject: [PATCH 361/903] MDL-32023 wiki: remove hard-coded edit string

---
 mod/wiki/lang/en/wiki.php              |    1 +
 mod/wiki/parser/markups/wikimarkup.php |    3 +--
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/wiki/lang/en/wiki.php b/mod/wiki/lang/en/wiki.php
index 1c929d9..80fbdf4 100644
--- a/mod/wiki/lang/en/wiki.php
+++ b/mod/wiki/lang/en/wiki.php
@@ -59,6 +59,7 @@ $string['editfiles'] = 'Edit wiki files';
 $string['editing'] = 'Editing wiki page';
 $string['editingcomment'] = 'Editing comment';
 $string['editingpage'] = 'Editing this page \'{$a}\'';
+$string['editsection'] = 'edit';
 $string['files'] = 'Files';
 $string['filenotuploadederror'] = 'File \'{$a}\' could not be uploaded correctly.';
 $string['filtername'] = 'Wiki auto-linking';
diff --git a/mod/wiki/parser/markups/wikimarkup.php b/mod/wiki/parser/markups/wikimarkup.php
index cf7a2b3..78a3790 100644
--- a/mod/wiki/parser/markups/wikimarkup.php
+++ b/mod/wiki/parser/markups/wikimarkup.php
@@ -18,7 +18,6 @@ abstract class wiki_markup_parser extends generic_parser {
     protected $wiki_page_id;
 
     //sections
-    protected $section_edit_text = "[edit]";
     protected $repeated_sections;
 
     protected $section_editing = true;
@@ -181,7 +180,7 @@ abstract class wiki_markup_parser extends generic_parser {
         $text = trim($text);
 
         if (!$this->pretty_print && $level == 1) {
-            $text .= parser_utils::h('a', $this->section_edit_text, array('href' => "edit.php?pageid={$this->wiki_page_id}&section=" . urlencode($text), 'class' => 'wiki_edit_section'));
+            $text .= parser_utils::h('a', '['.get_string('editsection', 'wiki').']', array('href' => "edit.php?pageid={$this->wiki_page_id}&section=" . urlencode($text), 'class' => 'wiki_edit_section'));
         }
 
         if ($level < 4) {
-- 
1.7.9.5


From 8dc49e14c4b19006a106b32bb2493cc61ddb0d3f Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 1 Aug 2012 09:27:37 +1200
Subject: [PATCH 362/903] MDL-34656 prevent login form from being shown inside
 iframe - also prevent wantsurl from being set to
 loadsco.php which isn't a valid page for initial
 load.

---
 mod/scorm/loadSCO.php |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/mod/scorm/loadSCO.php b/mod/scorm/loadSCO.php
index 29f4972..bae1224 100644
--- a/mod/scorm/loadSCO.php
+++ b/mod/scorm/loadSCO.php
@@ -49,7 +49,16 @@ if (!empty($id)) {
 
 $PAGE->set_url('/mod/scorm/loadSCO.php', array('scoid'=>$scoid, 'id'=>$cm->id));
 
-require_login($course, false, $cm);
+if (!isloggedin()) { // Prevent login page from being shown in iframe.
+    // Using simple html instead of exceptions here as shown inside iframe/object.
+    echo html_writer::start_tag('html');
+    echo html_writer::tag('head', '');
+    echo html_writer::tag('body', get_string('loggedinnot'));
+    echo html_writer::end_tag('html');
+    exit;
+}
+
+require_login($course, false, $cm, false); // Call require_login anyway to set up globals correctly.
 
 //check if scorm closed
 $timenow = time();
-- 
1.7.9.5


From 25f8e4f2417018d454f7a0cbe3ffa51733a88927 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Wed, 8 Aug 2012 11:37:40 +0800
Subject: [PATCH 363/903] MDL-34575: fixed string typo and string duplication
 for label

---
 user/addnote.php |    2 +-
 user/index.php   |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/user/addnote.php b/user/addnote.php
index 79a8263..074891e 100644
--- a/user/addnote.php
+++ b/user/addnote.php
@@ -107,7 +107,7 @@ foreach ($users as $k => $v) {
     if(!$user = $DB->get_record('user', array('id'=>$v))) {
         continue;
     }
-    $checkbox = html_writer::label(get_string('selectnotestate', 'note'), 'menustates', false, array('class' => 'accesshide'));
+    $checkbox = html_writer::label(get_string('selectnotestate', 'notes'), 'menustates', false, array('class' => 'accesshide'));
     $checkbox .= html_writer::select($state_names, 'states[' . $k . ']', empty($states[$k]) ? NOTES_STATE_PUBLIC : $states[$k], false, array('id' => 'menustates'));
     $table->data[] = array(
         '<input type="hidden" name="userid['.$k.']" value="'.$v.'" />'. fullname($user, true),
diff --git a/user/index.php b/user/index.php
index 0f4a64a..b3abbbf 100644
--- a/user/index.php
+++ b/user/index.php
@@ -812,8 +812,8 @@
     }
 
     if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
-        echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
-        echo '<label class="accesshide" for="search">' . get_string('search', 'search') . '</label>';
+        echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />';
+        echo '<label for="search">' . get_string('search', 'search') . ' </label>';
         echo '<input type="text" id="search" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
     }
 
-- 
1.7.9.5


From c258605a8d9a2949c1f0e7a89debba1599c827f3 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Wed, 8 Aug 2012 13:50:47 +1200
Subject: [PATCH 364/903] MDL-33640 - Add ability to use custom filepicker
 templates

Allow repository plugins to register a template by defining a get_template() method, coupled with the ability to request the template be used by create_upload_form() instead of the standard 'uploadform' template.  The template is automatically registered using the plugin's name, and core templates will override any which clash; this also means that a theme can override these templates in a custom renderer if it wants to.
---
 repository/filepicker.js |    3 ++-
 repository/lib.php       |    7 ++++++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/repository/filepicker.js b/repository/filepicker.js
index 7c4e1f4..54b6bc1 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -1618,7 +1618,8 @@ M.core_filepicker.init = function(Y, options) {
             var client_id = this.options.client_id;
             var id = data.upload.id+'_'+client_id;
             var content = this.fpnode.one('.fp-content');
-            content.setContent(M.core_filepicker.templates.uploadform);
+            var template = data.template || 'uploadform';
+            content.setContent(M.core_filepicker.templates[template]);
 
             content.all('.fp-file,.fp-saveas,.fp-setauthor,.fp-setlicense').each(function (node) {
                 node.all('label').set('for', node.one('input,select').generateID());
diff --git a/repository/lib.php b/repository/lib.php
index 44e4fe4..7828ab7 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -2684,16 +2684,21 @@ function initialise_filepicker($args) {
     // provided by form element
     $return->accepted_types = file_get_typegroup('extension', $args->accepted_types);
     $return->return_types = $args->return_types;
+    $templates = array();
     foreach ($repositories as $repository) {
         $meta = $repository->get_meta();
         // Please note that the array keys for repositories are used within
         // JavaScript a lot, the key NEEDS to be the repository id.
         $return->repositories[$repository->id] = $meta;
+        // Register custom repository template if it has one
+        if(method_exists($repository, 'get_template')) {
+            $templates[$meta->type] = $repository->get_template();
+        }
     }
     if (!$templatesinitialized) {
         // we need to send filepicker templates to the browser just once
         $fprenderer = $PAGE->get_renderer('core', 'files');
-        $templates = $fprenderer->filepicker_js_templates();
+        $templates = array_merge($templates, $fprenderer->filepicker_js_templates());
         $PAGE->requires->js_init_call('M.core_filepicker.set_templates', array($templates), true);
         $templatesinitialized = true;
     }
-- 
1.7.9.5


From 55a2b03ef1d8f6d40e7b941cafb06a40a9d0afee Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Wed, 8 Aug 2012 10:51:14 +0100
Subject: [PATCH 365/903] MDL-34783 Retrieve the sectioncache parameter for
 enrolled courses in the course_overview block

The sectioncache field is used by course_modinfo and without it, the
modinfo cache is repeatedly reset.
---
 blocks/course_overview/block_course_overview.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/course_overview/block_course_overview.php b/blocks/course_overview/block_course_overview.php
index df79e3b..72b60cb 100644
--- a/blocks/course_overview/block_course_overview.php
+++ b/blocks/course_overview/block_course_overview.php
@@ -64,7 +64,7 @@ class block_course_overview extends block_base {
             $courses_limit = $courses_limit + 1;
         }
 
-        $courses = enrol_get_my_courses('id, shortname, modinfo', 'visible DESC,sortorder ASC', $courses_limit);
+        $courses = enrol_get_my_courses('id, shortname, modinfo, sectioncache', 'visible DESC,sortorder ASC', $courses_limit);
         $site = get_site();
         $course = $site; //just in case we need the old global $course hack
 
-- 
1.7.9.5


From 383639a5ef9bbb7db376518bf3eaabf1cbe73ef7 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Wed, 8 Aug 2012 10:01:28 -0400
Subject: [PATCH 366/903] MDL-34376 mod_assign Omit assigns with no due date
 from print_overview.

Modify assign_print_overview to omit assigns that have no due date set, in line with behaviour
in 2.2 and other tools.
---
 mod/assign/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index a6cdba7..5ca8423 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -212,8 +212,8 @@ function assign_print_overview($courses, &$htmlarray) {
     // Do assignment_base::isopen() here without loading the whole thing for speed
     foreach ($assignments as $key => $assignment) {
         $time = time();
-        $isopen = $assignment->allowsubmissionsfromdate <= $time;
         if ($assignment->duedate) {
+            $isopen = $assignment->allowsubmissionsfromdate <= $time;
             if ($assignment->preventlatesubmissions) {
                 $isopen = ($isopen && $time <= $assignment->duedate);
             }
-- 
1.7.9.5


From 55c91c8760147a8af65afa0ddeae68c1cc106a73 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Thu, 9 Aug 2012 09:43:53 +1200
Subject: [PATCH 367/903] MDL-33640 - change $templatesinitialized to an
 array; improve naming and automate use of template

* $templatesinitialized is now an array, so that subsequent calls to initialise_filepicker which request different repositories will include those (and only those) templates which it requires but have not yet been included
* The get_template method has also been renamed to get_upload_template (and the template to "uploadform_" followed by the repository type), since it only applies to upload forms
* If a plugin provides a get_upload_template method, the template it returns will now automatically be used instead of the standard uploadform template when generating an upload form
---
 repository/filepicker.js |    5 +++--
 repository/lib.php       |   15 +++++++++------
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/repository/filepicker.js b/repository/filepicker.js
index 54b6bc1..d277574 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -1618,8 +1618,9 @@ M.core_filepicker.init = function(Y, options) {
             var client_id = this.options.client_id;
             var id = data.upload.id+'_'+client_id;
             var content = this.fpnode.one('.fp-content');
-            var template = data.template || 'uploadform';
-            content.setContent(M.core_filepicker.templates[template]);
+            var template_name = 'uploadform_'+this.options.repositories[data.repo_id].type;
+            var template = M.core_filepicker.templates[template_name] || M.core_filepicker.templates['uploadform'];
+            content.setContent(template);
 
             content.all('.fp-file,.fp-saveas,.fp-setauthor,.fp-setlicense').each(function (node) {
                 node.all('label').set('for', node.one('input,select').generateID());
diff --git a/repository/lib.php b/repository/lib.php
index 7828ab7..3818cc9 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -2614,7 +2614,7 @@ final class repository_type_form extends moodleform {
  */
 function initialise_filepicker($args) {
     global $CFG, $USER, $PAGE, $OUTPUT;
-    static $templatesinitialized;
+    static $templatesinitialized = array();
     require_once($CFG->libdir . '/licenselib.php');
 
     $return = new stdClass();
@@ -2691,16 +2691,19 @@ function initialise_filepicker($args) {
         // JavaScript a lot, the key NEEDS to be the repository id.
         $return->repositories[$repository->id] = $meta;
         // Register custom repository template if it has one
-        if(method_exists($repository, 'get_template')) {
-            $templates[$meta->type] = $repository->get_template();
+        if(method_exists($repository, 'get_upload_template') && !array_key_exists('uploadform_' . $meta->type, $templatesinitialized)) {
+            $templates['uploadform_' . $meta->type] = $repository->get_upload_template();
+            $templatesinitialized['uploadform_' . $meta->type] = true;
         }
     }
-    if (!$templatesinitialized) {
-        // we need to send filepicker templates to the browser just once
+    if (!array_key_exists('core', $templatesinitialized)) {
+        // we need to send each filepicker template to the browser just once
         $fprenderer = $PAGE->get_renderer('core', 'files');
         $templates = array_merge($templates, $fprenderer->filepicker_js_templates());
+        $templatesinitialized['core'] = true;
+    }
+    if (sizeof($templates)) {
         $PAGE->requires->js_init_call('M.core_filepicker.set_templates', array($templates), true);
-        $templatesinitialized = true;
     }
     return $return;
 }
-- 
1.7.9.5


From 081889f26bc319c8f32b0b512d001e6dcfdc5b5c Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 9 Aug 2012 00:31:36 +0000
Subject: [PATCH 368/903] Automatically generated installer lang files

---
 install/lang/lt/admin.php |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/install/lang/lt/admin.php b/install/lang/lt/admin.php
index f97528e..464446a 100644
--- a/install/lang/lt/admin.php
+++ b/install/lang/lt/admin.php
@@ -30,5 +30,12 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['cliansweryes'] = 't';
+$string['cliincorrectvalueerror'] = 'Klaida, klaidinga "{$a->option}" reikšmė "{$a->value}"';
+$string['cliincorrectvalueretry'] = 'Klaidinga reikšmė, bandykite dar kartą';
+$string['clitypevalue'] = 'tipo reikšmė';
+$string['clitypevaluedefault'] = 'tipo reikšmė, paspauskite „Enter“, jei norite naudoti numatytąją reikšmę ({$a})';
+$string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno parinktį.';
+$string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
 $string['environmentrequireinstall'] = 'turi būti įdiegta ir įgalinta';
 $string['environmentrequireversion'] = 'reikalinga $a-needed, o Jūs turite $a-current';
-- 
1.7.9.5


From 4c0d64860a0f0e7717a8de4fc3417028049291f7 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 9 Aug 2012 12:52:11 +0100
Subject: [PATCH 369/903] MDL-34590 javascript-static: nuclear option in
 openpopup

I think we have finally tamed Chrome on all platforms. (Crosses fingers.)
---
 lib/javascript-static.js |   25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index f802776..6e7042d 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1195,10 +1195,29 @@ function openpopup(event, args) {
     }
 
     if (args.fullscreen) {
-        setTimeout(function() {
+        // In some browser / OS combinations (E.g. Chrome on Windows), the
+        // window initially opens slighly too big. The width and heigh options
+        // seem to control the area inside the browser window, so what with
+        // scroll-bars, etc. the actual window is bigger than the screen.
+        // Therefore, we need to fix things up after the window is open.
+        var hackcount = 100;
+        var get_size_exactly_right = function() {
             windowobj.moveTo(0, 0);
-            windowobj.resizeTo(screen.availWidth, screen.availHeight)
-        }, 0);
+            windowobj.resizeTo(screen.availWidth, screen.availHeight);
+
+            // Unfortunately, it seems that in Chrome on Ubuntu, if you call
+            // something like windowobj.resizeTo(1280, 1024) too soon (up to
+            // about 50ms) after the window is open, then it actually behaves
+            // as if you called windowobj.resizeTo(0, 0). Therefore, we need to
+            // check that the resize actually worked, and if not, repeatedly try
+            // again after a short delay until it works (but with a limit of
+            // hackcount repeats.
+            if (hackcount > 0 && (windowobj.innerHeight < 10 || windowobj.innerWidth < 10)) {
+                hackcount -= 1;
+                setTimeout(get_size_exactly_right, 10);
+            }
+        }
+        setTimeout(get_size_exactly_right, 0);
     }
     windowobj.focus();
 
-- 
1.7.9.5


From e6aac11d943c0d689a9cf8b2c9b5bd92148243bf Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 9 Aug 2012 20:51:56 +0200
Subject: [PATCH 370/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 2d2dea3..69b3a82 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.08;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.09;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120802)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120809)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From e9a743d385fc0927353db00d162f6067f6259a08 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 10 Aug 2012 00:31:47 +0000
Subject: [PATCH 371/903] Automatically generated installer lang files

---
 install/lang/lt/admin.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/install/lang/lt/admin.php b/install/lang/lt/admin.php
index 464446a..d35bbc8 100644
--- a/install/lang/lt/admin.php
+++ b/install/lang/lt/admin.php
@@ -30,6 +30,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['clianswerno'] = 'n';
 $string['cliansweryes'] = 't';
 $string['cliincorrectvalueerror'] = 'Klaida, klaidinga "{$a->option}" reikšmė "{$a->value}"';
 $string['cliincorrectvalueretry'] = 'Klaidinga reikšmė, bandykite dar kartą';
@@ -38,4 +39,4 @@ $string['clitypevaluedefault'] = 'tipo reikšmė, paspauskite „Enter“, jei n
 $string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno parinktį.';
 $string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
 $string['environmentrequireinstall'] = 'turi būti įdiegta ir įgalinta';
-$string['environmentrequireversion'] = 'reikalinga $a-needed, o Jūs turite $a-current';
+$string['environmentrequireversion'] = 'reikalinga {$a-needed} versija, o Jūs turite {$a-current}';
-- 
1.7.9.5


From 203e8d40321b8002a4d7213724089f5eacac6eab Mon Sep 17 00:00:00 2001
From: Lorenzo Nicora <lorenzo.nicora@gmail.com>
Date: Sun, 10 Jun 2012 09:25:19 +0200
Subject: [PATCH 372/903] MDL-33531 Fixed the regexp to find old backup files,
 considering backup_shortname backup option

---
 backup/util/helper/backup_cron_helper.class.php |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 00db13d..99c939d 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -508,7 +508,17 @@ abstract class backup_cron_automated_helper {
         if (!empty($dir) && ($storage == 1 || $storage == 2)) {
             // Calculate backup filename regex, ignoring the date/time/info parts that can be
             // variable, depending of languages, formats and automated backup settings
-            $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$course->id . '-';
+
+
+            // MDL-33531: use different filenames depending on backup_shortname option
+            if ( $config->backup_shortname ) {
+                $courseref = $course->shortname;
+                $courseref = str_replace(' ', '_', $courseref);
+                $courseref = textlib::strtolower(trim(clean_filename($courseref), '_'));
+            } else {
+                $courseref = $course->id;
+            }
+            $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$courseref . '-';
             $regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#';
 
             // Store all the matching files into fullpath => timemodified array
-- 
1.7.9.5


From 4af5c4ebf58c09b958c71a3a84378d446a1715bc Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Fri, 6 Jul 2012 15:16:09 +0800
Subject: [PATCH 373/903] MDL-33531 backup Avoiding possible Notice

---
 backup/util/helper/backup_cron_helper.class.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 99c939d..6b1677b 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -511,7 +511,7 @@ abstract class backup_cron_automated_helper {
 
 
             // MDL-33531: use different filenames depending on backup_shortname option
-            if ( $config->backup_shortname ) {
+            if ( !empty($config->backup_shortname) ) {
                 $courseref = $course->shortname;
                 $courseref = str_replace(' ', '_', $courseref);
                 $courseref = textlib::strtolower(trim(clean_filename($courseref), '_'));
-- 
1.7.9.5


From 3de32f8558831e3638272f3208c19d34d86146ba Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 16 Jul 2012 10:20:20 +0800
Subject: [PATCH 374/903] MDL-33531 backup Added format_string to course
 shortname

---
 backup/util/helper/backup_cron_helper.class.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 6b1677b..9715a5d 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -512,7 +512,8 @@ abstract class backup_cron_automated_helper {
 
             // MDL-33531: use different filenames depending on backup_shortname option
             if ( !empty($config->backup_shortname) ) {
-                $courseref = $course->shortname;
+                $context = get_context_instance(CONTEXT_COURSE, $course->id);
+                $courseref = format_string($course->shortname, true, array('context' => $context));
                 $courseref = str_replace(' ', '_', $courseref);
                 $courseref = textlib::strtolower(trim(clean_filename($courseref), '_'));
             } else {
-- 
1.7.9.5


From 15343304d205938a86557867718a7bbac1fa7e6d Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Thu, 26 Jul 2012 17:40:51 +0800
Subject: [PATCH 375/903] MDL-25347 blog Checking association capability at
 course and module levels instead of system level

---
 blog/edit_form.php |   33 ++++++++++++++++++++-------------
 blog/lib.php       |   16 +++++++++-------
 2 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/blog/edit_form.php b/blog/edit_form.php
index 55ce91d..1def593 100644
--- a/blog/edit_form.php
+++ b/blog/edit_form.php
@@ -71,24 +71,28 @@ class blog_edit_form extends moodleform {
         $allmodnames = array();
 
         if (!empty($CFG->useblogassociations)) {
-            if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid))) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+            if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid)))) {
                 if (!empty($courseid)) {
                     $course = $DB->get_record('course', array('id' => $courseid));
-                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                    $context = get_context_instance(CONTEXT_COURSE, $courseid);
+                    $context = context_course::instance($courseid);
                     $a = new stdClass();
                     $a->coursename = format_string($course->fullname, true, array('context' => $context));
                     $contextid = $context->id;
                 } else {
+                    $context = context::instance_by_id($entry->courseassoc);
                     $sql = 'SELECT fullname FROM {course} cr LEFT JOIN {context} ct ON ct.instanceid = cr.id WHERE ct.id = ?';
                     $a = new stdClass();
                     $a->coursename = $DB->get_field_sql($sql, array($entry->courseassoc));
                     $contextid = $entry->courseassoc;
                 }
 
-                $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
-                $mform->setDefault('courseassoc', $contextid);
-            } else if ((!empty($entry->modassoc) || !empty($modid)) && has_capability('moodle/blog:associatemodule', $sitecontext)) {
+                if (has_capability('moodle/blog:associatecourse', $context)) {
+                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
+                    $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
+                    $mform->setDefault('courseassoc', $contextid);
+                }
+
+            } else if ((!empty($entry->modassoc) || !empty($modid))) {
                 if (!empty($modid)) {
                     $mod = get_coursemodule_from_id(false, $modid);
                     $a = new stdClass();
@@ -104,9 +108,11 @@ class blog_edit_form extends moodleform {
                     $modid = $context->instanceid;
                 }
 
-                $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
-                $mform->setDefault('modassoc', $context->id);
+                if (has_capability('moodle/blog:associatemodule', $context)) {
+                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
+                    $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
+                    $mform->setDefault('modassoc', $context->id);
+                }
             }
         }
 
@@ -132,13 +138,13 @@ class blog_edit_form extends moodleform {
         global $CFG, $DB, $USER;
 
         $errors = array();
-        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
 
         // validate course association
-        if (!empty($data['courseassoc']) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+        if (!empty($data['courseassoc'])) {
             $coursecontext = context::instance_by_id($data['courseassoc'], IGNORE_MISSING);
 
-            if ($coursecontext and $coursecontext->contextlevel == CONTEXT_COURSE)  {
+            $canassociatecourse = has_capability('moodle/blog:associatecourse', $coursecontext);
+            if ($coursecontext->contextlevel == CONTEXT_COURSE && $canassociatecourse) {
                 if (!is_enrolled($coursecontext) and !is_viewing($coursecontext)) {
                     $errors['courseassoc'] = get_string('studentnotallowed', '', fullname($USER, true));
                 }
@@ -152,7 +158,8 @@ class blog_edit_form extends moodleform {
             $modcontextid = $data['modassoc'];
             $modcontext = context::instance_by_id($modcontextid, IGNORE_MISSING);
 
-            if ($modcontext and $modcontext->contextlevel == CONTEXT_MODULE) {
+            $canassociatemodule = has_capability('moodle/blog:associatecourse', $modcontext);
+            if ($modcontext->contextlevel == CONTEXT_MODULE && $canassociatemodule) {
                 // get context of the mod's course
                 $coursecontext = $modcontext->get_course_context(true);
 
diff --git a/blog/lib.php b/blog/lib.php
index 8a3b687..fc087b9 100644
--- a/blog/lib.php
+++ b/blog/lib.php
@@ -510,8 +510,9 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
     }
 
     // Check that the user can associate with the course
-    $sitecontext =      get_context_instance(CONTEXT_SYSTEM);
-    if (!has_capability('moodle/blog:associatecourse', $sitecontext)) {
+    $sitecontext = context_system::instance();
+    $coursecontext = context_course::instance($course->id);
+    if (!has_capability('moodle/blog:associatecourse', $coursecontext)) {
         return $options;
     }
     // Generate the cache key
@@ -526,7 +527,6 @@ function blog_get_options_for_course(stdClass $course, stdClass $user=null) {
         return $courseoptions[$key];
     }
 
-    $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
     $canparticipate = (is_enrolled($coursecontext) or is_viewing($coursecontext));
 
     if (has_capability('moodle/blog:view', $coursecontext)) {
@@ -587,8 +587,9 @@ function blog_get_options_for_module($module, $user=null) {
     }
 
     // Check the user can associate with the module
-    $sitecontext =      get_context_instance(CONTEXT_SYSTEM);
-    if (!has_capability('moodle/blog:associatemodule', $sitecontext)) {
+    $modcontext = context_module::instance($module->id);
+    $sitecontext = context_system::instance();
+    if (!has_capability('moodle/blog:associatemodule', $modcontext)) {
         return $options;
     }
 
@@ -604,7 +605,6 @@ function blog_get_options_for_module($module, $user=null) {
         return $moduleoptions[$module->id];
     }
 
-    $modcontext = get_context_instance(CONTEXT_MODULE, $module->id);
     $canparticipate = (is_enrolled($modcontext) or is_viewing($modcontext));
 
     if (has_capability('moodle/blog:view', $modcontext)) {
@@ -743,7 +743,9 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
     $PAGE->set_pagelayout('standard');
 
-    if (!empty($modid) && $CFG->useblogassociations && has_capability('moodle/blog:associatemodule', $sitecontext)) { // modid always overrides courseid, so the $course object may be reset here
+    // modid always overrides courseid, so the $course object may be reset here
+    if (!empty($modid) && $CFG->useblogassociations) {
+
         $headers['filters']['module'] = $modid;
         // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case
         $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
-- 
1.7.9.5


From ef38e70c410a0bd8e59cb414c55a1501dadab7f1 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 10 Aug 2012 13:49:53 +0800
Subject: [PATCH 376/903] MDL-34829 course - allow directly linked sections to
 work.

Even if not in single section mode.
---
 course/format/topics/format.php |    2 +-
 course/format/weeks/format.php  |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/course/format/topics/format.php b/course/format/topics/format.php
index 0764ceb..51acd38 100644
--- a/course/format/topics/format.php
+++ b/course/format/topics/format.php
@@ -46,7 +46,7 @@ if (($marker >=0) && has_capability('moodle/course:setcurrentsection', $context)
 
 $renderer = $PAGE->get_renderer('format_topics');
 
-if (!empty($displaysection) && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+if (!empty($displaysection)) {
     $renderer->print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection);
 } else {
     $renderer->print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused);
diff --git a/course/format/weeks/format.php b/course/format/weeks/format.php
index 5d70cc5..2f0eb51 100644
--- a/course/format/weeks/format.php
+++ b/course/format/weeks/format.php
@@ -39,7 +39,7 @@ if ($week = optional_param('week', 0, PARAM_INT)) {
 
 $renderer = $PAGE->get_renderer('format_weeks');
 
-if (!empty($displaysection) && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+if (!empty($displaysection)) {
     $renderer->print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection);
 } else {
     $renderer->print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused);
-- 
1.7.9.5


From bd3306f5cd9e2b84f90561c5432c4d22780a7ff4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 8 Aug 2012 11:57:04 +0200
Subject: [PATCH 377/903] MDL-34782 detect code abusing integer limits in
 mysql database

It is allowed to store only ranges specified in install.xml, for integers it means number of digits specified in size.
---
 lib/db/upgradelib.php |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/lib/db/upgradelib.php b/lib/db/upgradelib.php
index e0fb421..5103e0b 100644
--- a/lib/db/upgradelib.php
+++ b/lib/db/upgradelib.php
@@ -68,6 +68,23 @@ function upgrade_mysql_fix_unsigned_columns() {
 
             $column = (object)array_change_key_case((array)$column, CASE_LOWER);
             if (stripos($column->type, 'unsigned') !== false) {
+                $maxvalue = 0;
+                if (preg_match('/^int/i', $column->type)) {
+                    $maxvalue = 2147483647;
+                } else if (preg_match('/^medium/i', $column->type)) {
+                    $maxvalue = 8388607;
+                } else if (preg_match('/^smallint/i', $column->type)) {
+                    $maxvalue = 32767;
+                } else if (preg_match('/^tinyint/i', $column->type)) {
+                    $maxvalue = 127;
+                }
+                if ($maxvalue) {
+                    // Make sure nobody is abusing our integer ranges - moodle int sizes are in digits, not bytes!!!
+                    $invalidcount = $DB->get_field_sql("SELECT COUNT('x') FROM `{{$table}}` WHERE `$column->field` > :maxnumber", array('maxnumber'=>$maxvalue));
+                    if ($invalidcount) {
+                        throw new moodle_exception('notlocalisederrormessage', 'error', new moodle_url('/admin/'), "Database table '{$table}'' contains unsigned column '{$column->field}' with $invalidcount values that are out of allowed range, upgrade can not continue.");
+                    }
+                }
                 $type = preg_replace('/unsigned/i', 'signed', $column->type);
                 $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
                 $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
-- 
1.7.9.5


From d8ceb62387a15848793a65b7125dde1f6dac4cbe Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 10 Aug 2012 20:31:57 +0100
Subject: [PATCH 378/903] MDL-34835 theme_fusion: fixed displaced navbar by
 extending #region-header.inside bottom margin by
 70px in style/pagelayout.css

---
 theme/fusion/style/pagelayout.css |   96 +++++++++++++++++++------------------
 1 file changed, 50 insertions(+), 46 deletions(-)

diff --git a/theme/fusion/style/pagelayout.css b/theme/fusion/style/pagelayout.css
index c1f2d7b..04abd25 100644
--- a/theme/fusion/style/pagelayout.css
+++ b/theme/fusion/style/pagelayout.css
@@ -2,103 +2,107 @@
 
 /*********************************************************************************************
 
-	right column: 28%
-	padding left/right column: 10px
-	padding center column: 20px
+    right column: 28%
+    padding left/right column: 10px
+    padding center column: 20px
 
 **********************************************************************************************/
 
 body {
-	margin: auto 0px;
-	width: auto;
+    margin: auto 0px;
+    width: auto;
 }
 
 #page {
-	width: 100%;
+    width: 100%;
 }
 
 #page-header {
-	float: left;
-	width: 100%;
+    float: left;
+    width: 100%;
 }
 
 #page-content {
-	clear: both;
-	float: left;
-	overflow: hidden;
-	position: relative;
-	width: 100%;
+    clear: both;
+    float: left;
+    overflow: hidden;
+    position: relative;
+    width: 100%;
 }
 
 #page-content #region-main-box {
-	float: left;
-	right: 28%;
-	position: relative;
-	width: 100%;
+    float: left;
+    right: 28%;
+    position: relative;
+    width: 100%;
 }
 
 #page-content #region-post-box {
-	float: left;
-	right: 72%;
-	position: relative;
-	width: 100%;
+    float: left;
+    right: 72%;
+    position: relative;
+    width: 100%;
 }
 
 #page-content #region-main {
-	float: left;
-	overflow: hidden;
-	position: relative;
-	margin-right: 0px;
-	left: 100%;
-	width: 72%;
+    float: left;
+    overflow: hidden;
+    position: relative;
+    margin-right: 0px;
+    left: 100%;
+    width: 72%;
 }
 
 #page-content #region-post {
-	float: left;
-	overflow: hidden;
-	position: relative;
-	left: 100%;
-	width: 28%;
+    float: left;
+    overflow: hidden;
+    position: relative;
+    left: 100%;
+    width: 28%;
 }
 
 #page-content #region-main .region-content {
-	overflow: hidden;
-	padding: 50px 15px 20px 0;
+    overflow: hidden;
+    padding: 50px 15px 20px 0;
 }
 
 #page-content #region-post .region-content {
-	overflow: hidden;
-	padding: 0 0 0 10px;
+    overflow: hidden;
+    padding: 0 0 0 10px;
 }
 
 #page-footer {
-	clear: both;
-	float: left;
-	width: 100%;
+    clear: both;
+    float: left;
+    width: 100%;
 }
 
 /** No blocks whatsoever **/
 
 .content-only #page-content #region-main-box {
-	right: 0%;
+    right: 0%;
 }
 
 .content-only #page-content #region-post-box {
-	right: 100%;
+    right: 100%;
 }
 
 .content-only #page-content #region-main {
-	left: 100%;
-	width: 100%;
+    left: 100%;
+    width: 100%;
 }
 
 .content-only #page-content #region-pre {
-	width: 0%;
+    width: 0%;
 }
 
 .content-only #page-content #region-post {
-	width: 0%;
+    width: 0%;
 }
 
 .pagelayout-report #page-content #region-main {overflow:auto;}
-.pagelayout-report #page-content #region-main .region-content {overflow:visible;}
\ No newline at end of file
+.pagelayout-report #page-content #region-main .region-content {overflow:visible;}
+
+#page-enrol-manual-unenrolself #region-main .region-content #region-header.inside {
+    margin-bottom: 110px;
+}
\ No newline at end of file
-- 
1.7.9.5


From d077d1a0243ab6efc3ada3347465d018b81c66dd Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 11 Aug 2012 00:31:30 +0000
Subject: [PATCH 379/903] Automatically generated installer lang files

---
 install/lang/lt/admin.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/lt/admin.php b/install/lang/lt/admin.php
index d35bbc8..3c005d8 100644
--- a/install/lang/lt/admin.php
+++ b/install/lang/lt/admin.php
@@ -39,4 +39,4 @@ $string['clitypevaluedefault'] = 'tipo reikšmė, paspauskite „Enter“, jei n
 $string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno parinktį.';
 $string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
 $string['environmentrequireinstall'] = 'turi būti įdiegta ir įgalinta';
-$string['environmentrequireversion'] = 'reikalinga {$a-needed} versija, o Jūs turite {$a-current}';
+$string['environmentrequireversion'] = 'reikalinga {$a->needed} versija, o Jūs turite {$a->current}';
-- 
1.7.9.5


From c5cf1bc090c7462867ab79d3d4839e4bb469314b Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Fri, 10 Aug 2012 12:36:17 +0100
Subject: [PATCH 380/903] MDL-34446 Completion report: Add sideways text
 support to more browsers

---
 lib/moodlelib.php |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index afe9dc2..16106b4 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -8669,7 +8669,10 @@ function get_browser_version_classes() {
  */
 function can_use_rotated_text() {
     global $USER;
-    return ajaxenabled(array('Firefox' => 2.0)) && !$USER->screenreader;;
+    return (check_browser_version('MSIE', 9) || check_browser_version('Firefox', 2) ||
+            check_browser_version('Chrome', 21) || check_browser_version('Safari', 536.26) ||
+            check_browser_version('Opera', 12) || check_browser_version('Safari iOS', 533)) &&
+            !$USER->screenreader;
 }
 
 /**
-- 
1.7.9.5


From ff217758239df52cf3651b0485da0e023c21966c Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 13 Aug 2012 11:54:54 +0800
Subject: [PATCH 381/903] MDL-34748 repository_filesystem: Sort files by title
 by default

---
 repository/filesystem/lib.php |   58 +++++++++++++++++++++++++----------------
 1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/repository/filesystem/lib.php b/repository/filesystem/lib.php
index b295113..6eb3b3b 100644
--- a/repository/filesystem/lib.php
+++ b/repository/filesystem/lib.php
@@ -91,37 +91,49 @@ class repository_filesystem extends repository {
         $list['dynload'] = true;
         $list['nologin'] = true;
         $list['nosearch'] = true;
+        // retrieve list of files and directories and sort them
+        $fileslist = array();
+        $dirslist = array();
         if ($dh = opendir($this->root_path)) {
             while (($file = readdir($dh)) != false) {
                 if ( $file != '.' and $file !='..') {
-                    if (filetype($this->root_path.$file) == 'file') {
-                        $list['list'][] = array(
-                            'title' => $file,
-                            'source' => $path.'/'.$file,
-                            'size' => filesize($this->root_path.$file),
-                            'datecreated' => filectime($this->root_path.$file),
-                            'datemodified' => filemtime($this->root_path.$file),
-                            'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file, 90))->out(false),
-                            'icon' => $OUTPUT->pix_url(file_extension_icon($file, 24))->out(false)
-                        );
+                    if (is_file($this->root_path.$file)) {
+                        $fileslist[] = $file;
                     } else {
-                        if (!empty($path)) {
-                            $current_path = $path . '/'. $file;
-                        } else {
-                            $current_path = $file;
-                        }
-                        $list['list'][] = array(
-                            'title' => $file,
-                            'children' => array(),
-                            'datecreated' => filectime($this->root_path.$file),
-                            'datemodified' => filemtime($this->root_path.$file),
-                            'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
-                            'path' => $current_path
-                            );
+                        $dirslist[] = $file;
                     }
                 }
             }
         }
+        collatorlib::asort($fileslist, collatorlib::SORT_STRING);
+        collatorlib::asort($dirslist, collatorlib::SORT_STRING);
+        // fill the $list['list']
+        foreach ($dirslist as $file) {
+            if (!empty($path)) {
+                $current_path = $path . '/'. $file;
+            } else {
+                $current_path = $file;
+            }
+            $list['list'][] = array(
+                'title' => $file,
+                'children' => array(),
+                'datecreated' => filectime($this->root_path.$file),
+                'datemodified' => filemtime($this->root_path.$file),
+                'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
+                'path' => $current_path
+                );
+        }
+        foreach ($fileslist as $file) {
+            $list['list'][] = array(
+                'title' => $file,
+                'source' => $path.'/'.$file,
+                'size' => filesize($this->root_path.$file),
+                'datecreated' => filectime($this->root_path.$file),
+                'datemodified' => filemtime($this->root_path.$file),
+                'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file, 90))->out(false),
+                'icon' => $OUTPUT->pix_url(file_extension_icon($file, 24))->out(false)
+            );
+        }
         $list['list'] = array_filter($list['list'], array($this, 'filter'));
         return $list;
     }
-- 
1.7.9.5


From 37102468f79f474efe952b0e9a8d668ce667a92f Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:48:41 +0800
Subject: [PATCH 382/903] MDL-34565 accessibility compliance for forum module:
 Add forform input text and select tag

---
 mod/forum/lib.php    |    2 ++
 mod/forum/search.php |   14 ++++++++++++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index ab9a580..d052294 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -3834,9 +3834,11 @@ function forum_print_mode_form($id, $mode, $forumtype='') {
     global $OUTPUT;
     if ($forumtype == 'single') {
         $select = new single_select(new moodle_url("/mod/forum/view.php", array('f'=>$id)), 'mode', forum_get_layout_modes(), $mode, null, "mode");
+        $select->set_label(get_string('displaymode', 'forum'), array('class' => 'accesshide'));
         $select->class = "forummode";
     } else {
         $select = new single_select(new moodle_url("/mod/forum/discuss.php", array('d'=>$id)), 'mode', forum_get_layout_modes(), $mode, null, "mode");
+        $select->set_label(get_string('displaymode', 'forum'), array('class' => 'accesshide'));
     }
     echo $OUTPUT->render($select);
 }
diff --git a/mod/forum/search.php b/mod/forum/search.php
index ebbc99f..328bf24 100644
--- a/mod/forum/search.php
+++ b/mod/forum/search.php
@@ -343,10 +343,15 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timefromrestrict" type="checkbox" value="1" alt="'.get_string('searchdatefrom', 'forum').'" onclick="return lockoptions(\'searchform\', \'timefromrestrict\', timefromitems)" '.  $datefromchecked . ' /> ';
-    $selectors = html_writer::select_time('days', 'fromday', $datefrom)
+    $selectors = html_writer::label(get_string('day'), 'menufromday', false, array('class' => 'accesshide'))
+               . html_writer::select_time('days', 'fromday', $datefrom)
+               . html_writer::label(get_string('month'), 'menufrommonth', false, array('class' => 'accesshide'))
                . html_writer::select_time('months', 'frommonth', $datefrom)
+               . html_writer::label(get_string('year'), 'menufromyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'fromyear', $datefrom)
+               . html_writer::label(get_string('hour'), 'menufromhour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'fromhour', $datefrom)
+               . html_writer::label(get_string('minute'), 'menufromminute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'fromminute', $datefrom);
     echo $selectors;
     echo '<input type="hidden" name="hfromday" value="0" />';
@@ -369,10 +374,15 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timetorestrict" type="checkbox" value="1" alt="'.get_string('searchdateto', 'forum').'" onclick="return lockoptions(\'searchform\', \'timetorestrict\', timetoitems)" ' .$datetochecked. ' /> ';
-    $selectors = html_writer::select_time('days', 'today', $dateto)
+    $selectors = html_writer::label(get_string('day'), 'menutoday', false, array('class' => 'accesshide'))
+               . html_writer::select_time('days', 'today', $dateto)
+               . html_writer::label(get_string('month'), 'menutomonth', false, array('class' => 'accesshide'))
                . html_writer::select_time('months', 'tomonth', $dateto)
+               . html_writer::label(get_string('year'), 'menutoyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'toyear', $dateto)
+               . html_writer::label(get_string('hour'), 'menutohour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'tohour', $dateto)
+               . html_writer::label(get_string('minute'), 'menutominute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'tominute', $dateto);
     echo $selectors;
 
-- 
1.7.9.5


From 33222ed24a984ccbfaa768182b61271a575b6155 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 7 Aug 2012 15:28:52 +0800
Subject: [PATCH 383/903] MDL-34565: change to plural strings

---
 mod/forum/search.php |   20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/mod/forum/search.php b/mod/forum/search.php
index 328bf24..433269d 100644
--- a/mod/forum/search.php
+++ b/mod/forum/search.php
@@ -343,15 +343,15 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timefromrestrict" type="checkbox" value="1" alt="'.get_string('searchdatefrom', 'forum').'" onclick="return lockoptions(\'searchform\', \'timefromrestrict\', timefromitems)" '.  $datefromchecked . ' /> ';
-    $selectors = html_writer::label(get_string('day'), 'menufromday', false, array('class' => 'accesshide'))
+    $selectors = html_writer::label(get_string('days'), 'menufromday', false, array('class' => 'accesshide'))
                . html_writer::select_time('days', 'fromday', $datefrom)
-               . html_writer::label(get_string('month'), 'menufrommonth', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('months'), 'menufrommonth', false, array('class' => 'accesshide'))
                . html_writer::select_time('months', 'frommonth', $datefrom)
-               . html_writer::label(get_string('year'), 'menufromyear', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('years'), 'menufromyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'fromyear', $datefrom)
-               . html_writer::label(get_string('hour'), 'menufromhour', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('hours'), 'menufromhour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'fromhour', $datefrom)
-               . html_writer::label(get_string('minute'), 'menufromminute', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('minutes'), 'menufromminute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'fromminute', $datefrom);
     echo $selectors;
     echo '<input type="hidden" name="hfromday" value="0" />';
@@ -374,15 +374,15 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timetorestrict" type="checkbox" value="1" alt="'.get_string('searchdateto', 'forum').'" onclick="return lockoptions(\'searchform\', \'timetorestrict\', timetoitems)" ' .$datetochecked. ' /> ';
-    $selectors = html_writer::label(get_string('day'), 'menutoday', false, array('class' => 'accesshide'))
+    $selectors = html_writer::label(get_string('days'), 'menutoday', false, array('class' => 'accesshide'))
                . html_writer::select_time('days', 'today', $dateto)
-               . html_writer::label(get_string('month'), 'menutomonth', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('months'), 'menutomonth', false, array('class' => 'accesshide'))
                . html_writer::select_time('months', 'tomonth', $dateto)
-               . html_writer::label(get_string('year'), 'menutoyear', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('years'), 'menutoyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'toyear', $dateto)
-               . html_writer::label(get_string('hour'), 'menutohour', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('hours'), 'menutohour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'tohour', $dateto)
-               . html_writer::label(get_string('minute'), 'menutominute', false, array('class' => 'accesshide'))
+               . html_writer::label(get_string('minutes'), 'menutominute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'tominute', $dateto);
     echo $selectors;
 
-- 
1.7.9.5


From ee53ceb3eb39c8bbe0aea515a5cf319246599c19 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:48:20 +0800
Subject: [PATCH 384/903] MDL-34563 accessibility compliance for data module:
 Add forform input text and select tag

---
 mod/data/field.php                         |    1 +
 mod/data/field/date/field.class.php        |   14 ++++++++++----
 mod/data/field/file/field.class.php        |    3 ++-
 mod/data/field/file/mod.html               |    1 +
 mod/data/field/latlong/field.class.php     |    8 ++++++--
 mod/data/field/menu/field.class.php        |    6 ++++--
 mod/data/field/multimenu/field.class.php   |    4 +++-
 mod/data/field/number/field.class.php      |    3 ++-
 mod/data/field/picture/field.class.php     |    3 ++-
 mod/data/field/picture/mod.html            |    1 +
 mod/data/field/radiobutton/field.class.php |    4 +++-
 mod/data/field/text/field.class.php        |    2 +-
 mod/data/field/textarea/field.class.php    |    6 ++++--
 mod/data/field/url/field.class.php         |    8 ++++++--
 14 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/mod/data/field.php b/mod/data/field.php
index db5eb05..0688b1a 100644
--- a/mod/data/field.php
+++ b/mod/data/field.php
@@ -352,6 +352,7 @@ if (($mode == 'new') && (!empty($newtype)) && confirm_sesskey()) {          ///
 
     $options = array(0 => get_string('ascending', 'data'),
                      1 => get_string('descending', 'data'));
+    echo html_writer::label(get_string('sortby'), 'menudefaultsortdir', false, array('class' => 'accesshide'));
     echo html_writer::select($options, 'defaultsortdir', $data->defaultsortdir, false);
     echo '<input type="submit" value="'.get_string('save', 'data').'" />';
     echo '</div>';
diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php
index 313058c..5e13222 100644
--- a/mod/data/field/date/field.class.php
+++ b/mod/data/field/date/field.class.php
@@ -44,9 +44,12 @@ class data_field_date extends data_field_base {
         }
 
         $str = '<div title="'.s($this->field->description).'">';
-        $dayselector = html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content);
-        $monthselector = html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content);
-        $yearselector = html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content);
+        $dayselector = html_writer::label(get_string('day'), 'menufield_'.$this->field->id.'_day', false, array('class' => 'accesshide'))
+                     . html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content);
+        $monthselector = html_writer::label(get_string('month'), 'menufield_'.$this->field->id.'_month', false, array('class' => 'accesshide'))
+                       . html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content);
+        $yearselector = html_writer::label(get_string('year'), 'menufield_'.$this->field->id.'_year', false, array('class' => 'accesshide'))
+                      . html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content);
         $str .= $dayselector . $monthselector . $yearselector;
         $str .= '</div>';
 
@@ -55,8 +58,11 @@ class data_field_date extends data_field_base {
 
     //Enable the following three functions once core API issues have been addressed.
     function display_search_field($value=0) {
-        $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
+        $selectors = html_writer::label(get_string('day'), 'menuf_'.$this->field->id.'_d', false, array('class' => 'accesshide'))
+           . html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
+           . html_writer::label(get_string('month'), 'menuf_'.$this->field->id.'_m', false, array('class' => 'accesshide'))
            . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value)
+           . html_writer::label(get_string('year'), 'menuf_'.$this->field->id.'_y', false, array('class' => 'accesshide'))
            . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value);
        return $selectors;
 
diff --git a/mod/data/field/file/field.class.php b/mod/data/field/file/field.class.php
index aede3f0..4c7fdc1 100644
--- a/mod/data/field/file/field.class.php
+++ b/mod/data/field/file/field.class.php
@@ -91,7 +91,8 @@ class data_field_file extends data_field_base {
     }
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for=f_"' . $this->field->id . '">' . $this->field->name . '</label>' .
+               '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function generate_sql($tablealias, $value) {
diff --git a/mod/data/field/file/mod.html b/mod/data/field/file/mod.html
index 7a67a16..8330260 100644
--- a/mod/data/field/file/mod.html
+++ b/mod/data/field/file/mod.html
@@ -14,6 +14,7 @@
             <?php
                 $course = $DB->get_record('course', array('id'=>$this->data->course));
                 $choices = get_max_upload_sizes($CFG->maxbytes, $course->maxbytes);
+                echo html_writer::label($this->field->param3, 'menuparam3', false, array('class' => 'accesshide'));
                 echo html_writer::select($choices, 'param3', $this->field->param3, false, array('id' => 'param3'));
             ?>
         </td>
diff --git a/mod/data/field/latlong/field.class.php b/mod/data/field/latlong/field.class.php
index 794f3d0..a6f6889 100644
--- a/mod/data/field/latlong/field.class.php
+++ b/mod/data/field/latlong/field.class.php
@@ -82,7 +82,9 @@ class data_field_latlong extends data_field_base {
         }
         $latlongsrs->close();
 
-       return html_writer::select($options, 'f_'.$this->field->id, $value);
+        $return = html_writer::label(get_string('latlong', 'data'), 'menuf_'.$this->field->id, false, array('class' => 'accesshide'));
+        $return .= html_writer::select($options, 'f_'.$this->field->id, $value);
+       return $return;
     }
 
     function parse_search_field() {
@@ -150,7 +152,9 @@ class data_field_latlong extends data_field_base {
                           . str_replace(array_keys($urlreplacements), array_values($urlreplacements), $this->linkoutservices[$servicesshown[0]])
                           ."' title='$servicesshown[0]'>$compasslat, $compasslong</a>";
             } elseif (sizeof($servicesshown)>1) {
-                $str .= "$compasslat, $compasslong\n<select name='jumpto'>";
+                $str .= "$compasslat, $compasslong\n";
+                $str .= "<label class='accesshide' for='jumpto'>". get_string('jumpto') ."</label>";
+                $str .= "<select id='jumpto' name='jumpto'>";
                 foreach($servicesshown as $servicename){
                     // Add a link to a service
                     $str .= "\n  <option value='"
diff --git a/mod/data/field/menu/field.class.php b/mod/data/field/menu/field.class.php
index 6a948a1..0414f22 100644
--- a/mod/data/field/menu/field.class.php
+++ b/mod/data/field/menu/field.class.php
@@ -46,7 +46,7 @@ class data_field_menu extends data_field_base {
             }
         }
 
-
+        $str .= html_writer::label(get_string('menuchoose', 'data'), 'field_'.$this->field->id, false, array('class' => 'accesshide'));
         $str .= html_writer::select($options, 'field_'.$this->field->id, $content, array(''=>get_string('menuchoose', 'data')), array('id'=>'field_'.$this->field->id));
 
         $str .= '</div>';
@@ -86,7 +86,9 @@ class data_field_menu extends data_field_base {
             return '';
         }
 
-        return html_writer::select($options, 'f_'.$this->field->id, $content);
+        $return = html_writer::label(get_string('namemenu', 'data'), 'menuf_'. $this->field->id, false, array('class' => 'accesshide'));
+        $return .= html_writer::select($options, 'f_'.$this->field->id, $content);
+        return $return;
     }
 
      function parse_search_field() {
diff --git a/mod/data/field/multimenu/field.class.php b/mod/data/field/multimenu/field.class.php
index f3fe90b..30a4a6a 100644
--- a/mod/data/field/multimenu/field.class.php
+++ b/mod/data/field/multimenu/field.class.php
@@ -38,6 +38,7 @@ class data_field_multimenu extends data_field_base {
 
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<input name="field_' . $this->field->id . '[xxx]" type="hidden" value="xxx"/>'; // hidden field - needed for empty selection
+        $str .= '<label class="accesshide" for="field_' . $this->field->id . '">' . $this->field->name. ': </label>';
         $str .= '<select name="field_' . $this->field->id . '[]" id="field_' . $this->field->id . '" multiple="multiple">';
 
         foreach (explode("\n",$this->field->param1) as $option) {
@@ -71,7 +72,8 @@ class data_field_multimenu extends data_field_base {
 
         static $c = 0;
 
-        $str = '<select name="f_'.$this->field->id.'[]" multiple="multiple">';
+        $str = '<label class="accesshide" for="f_' . $this->field->id . '">' . $this->field->name . '</label>';
+        $str .= '<select id="f_'.$this->field->id.'" name="f_'.$this->field->id.'[]" multiple="multiple">';
 
         // display only used options
         $varcharcontent =  $DB->sql_compare_text('content', 255);
diff --git a/mod/data/field/number/field.class.php b/mod/data/field/number/field.class.php
index 9c5d17f..d04be45 100644
--- a/mod/data/field/number/field.class.php
+++ b/mod/data/field/number/field.class.php
@@ -70,7 +70,8 @@ class data_field_number extends data_field_base {
     }
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for="f_'.$this->field->id.'">' . get_string('fieldname', 'data') . '</label>' .
+               '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function parse_search_field() {
diff --git a/mod/data/field/picture/field.class.php b/mod/data/field/picture/field.class.php
index fe2053d..67d80f8 100644
--- a/mod/data/field/picture/field.class.php
+++ b/mod/data/field/picture/field.class.php
@@ -118,7 +118,8 @@ class data_field_picture extends data_field_base {
     }
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for="f_'.$this->field->id.'">' . get_string('fieldname', 'data') . '</label>' .
+               '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function parse_search_field() {
diff --git a/mod/data/field/picture/mod.html b/mod/data/field/picture/mod.html
index 4b32474..349f424 100644
--- a/mod/data/field/picture/mod.html
+++ b/mod/data/field/picture/mod.html
@@ -46,6 +46,7 @@
             <?php
                 $course = $DB->get_record('course', array('id'=>$this->data->course));
                 $choices = get_max_upload_sizes($CFG->maxbytes, $course->maxbytes);
+                echo html_writer::label($this->field->param3, 'menuparam3', false, array('class' => 'accesshide'));
                 echo html_writer::select($choices, 'param3', $this->field->param3, false, array('id'=>'param3'));
             ?>
         </td>
diff --git a/mod/data/field/radiobutton/field.class.php b/mod/data/field/radiobutton/field.class.php
index 5396b2d..f3115c1 100644
--- a/mod/data/field/radiobutton/field.class.php
+++ b/mod/data/field/radiobutton/field.class.php
@@ -78,7 +78,9 @@ class data_field_radiobutton extends data_field_base {
                 $options[$rec->content] = $rec->content;  //Build following indicies from the sql.
             }
         }
-        return html_writer::select($options, 'f_'.$this->field->id, $value);
+        $return = html_writer::label(get_string('nameradiobutton', 'data'), 'menuf_'. $this->field->id, false, array('class' => 'accesshide'));
+        $return .= html_writer::select($options, 'f_'.$this->field->id, $value);
+        return $return;
     }
 
     function parse_search_field() {
diff --git a/mod/data/field/text/field.class.php b/mod/data/field/text/field.class.php
index 36c391a..54cd497 100644
--- a/mod/data/field/text/field.class.php
+++ b/mod/data/field/text/field.class.php
@@ -27,7 +27,7 @@ class data_field_text extends data_field_base {
     var $type = 'text';
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for="f_' . $this->field->id . '">'. $this->field->name.'</label>' . '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function parse_search_field() {
diff --git a/mod/data/field/textarea/field.class.php b/mod/data/field/textarea/field.class.php
index 089a98d..847bae1 100644
--- a/mod/data/field/textarea/field.class.php
+++ b/mod/data/field/textarea/field.class.php
@@ -126,7 +126,8 @@ class data_field_textarea extends data_field_base {
         $editor->use_editor($field, $options, $fpoptions);
         $str .= '<input type="hidden" name="'.$field.'_itemid" value="'.$draftitemid.'" />';
         $str .= '<div><textarea id="'.$field.'" name="'.$field.'" rows="'.$this->field->param3.'" cols="'.$this->field->param2.'">'.s($text).'</textarea></div>';
-        $str .= '<div><select name="'.$field.'_content1">';
+        $str .= '<div><label class="accesshide" for="' . $field . '_content1">' . get_string('format') . '</label>';
+        $str .= '<select id="' . $field . '_content1" name="'.$field.'_content1">';
         foreach ($formats as $key=>$desc) {
             $selected = ($format == $key) ? 'selected="selected"' : '';
             $str .= '<option value="'.s($key).'" '.$selected.'>'.$desc.'</option>';
@@ -140,7 +141,8 @@ class data_field_textarea extends data_field_base {
 
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for="f_' . $this->field->id . '">' . $this->field->name . '</label>' .
+               '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function parse_search_field() {
diff --git a/mod/data/field/url/field.class.php b/mod/data/field/url/field.class.php
index 1c45373..89c8c7c 100644
--- a/mod/data/field/url/field.class.php
+++ b/mod/data/field/url/field.class.php
@@ -52,11 +52,14 @@ class data_field_url extends data_field_base {
         $str = '<div title="'.s($this->field->description).'">';
         if (!empty($this->field->param1) and empty($this->field->param2)) {
             $str .= '<table><tr><td align="right">';
-            $str .= get_string('url','data').':</td><td><input type="text" name="field_'.$this->field->id.'_0" id="'.$fieldid.'" value="'.$url.'" size="60" /></td></tr>';
+            $str .= get_string('url','data').':</td><td>';
+            $str .= '<label class="accesshide" for="' . $fieldid . '">'. $this->field->name .'</label>';
+            $str .= '<input type="text" name="field_'.$this->field->id.'_0" id="'.$fieldid.'" value="'.$url.'" size="60" /></td></tr>';
             $str .= '<tr><td align="right">'.get_string('text','data').':</td><td><input type="text" name="field_'.$this->field->id.'_1" id="field_'.$this->field->id.'_1" value="'.s($text).'" size="60" /></td></tr>';
             $str .= '</table>';
         } else {
             // Just the URL field
+            $str .= '<label class="accesshide" for="' . $fieldid . '">'. $this->field->name .'</label>';
             $str .= '<input type="text" name="field_'.$this->field->id.'_0" id="'.$fieldid.'" value="'.s($url).'" size="60" />';
         }
 
@@ -74,7 +77,8 @@ class data_field_url extends data_field_base {
     }
 
     function display_search_field($value = '') {
-        return '<input type="text" size="16" name="f_'.$this->field->id.'" value="'.$value.'" />';
+        return '<label class="accesshide" for="f_'.$this->field->id.'">' . get_string('fieldname', 'data') . '</label>' .
+               '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
     function parse_search_field() {
-- 
1.7.9.5


From 3350475e36c5858fec55c5ad9b833182158046de Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 7 Aug 2012 12:57:51 +0100
Subject: [PATCH 385/903] MDL-34728 forms: woy for other JS to trigger
 disableIf update.

This was discovered while working on MDL-32705. If some JavaScript (for
example a select all/none link) changes the state of some form fields,
then the disabledIf state of other form elements does not automatically
update.

The existing form JS was so well encapsulated that this was impossible.
This change pokes a hole in the encapsulation, and provides an API
    M.form.updateFormState(formid);
that other bits of JS code can call when necessary.
---
 lib/form/form.js |   23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lib/form/form.js b/lib/form/form.js
index b49d76a..1f7856b 100644
--- a/lib/form/form.js
+++ b/lib/form/form.js
@@ -59,6 +59,11 @@ M.form.initShowAdvanced = function(Y, config) {
 };
 
 /**
+ * Stores a list of the dependencyManager for each form on the page.
+ */
+M.form.dependencyManagers = {};
+
+/**
  * Initialises a manager for a forms dependencies.
  * This should happen once per form.
  */
@@ -128,7 +133,7 @@ M.form.initFormDependencies = function(Y, formid, dependencies) {
                 return this.checkDependencies(null);
             },
             /**
-             * Gets all elements in the form by thier name and returns
+             * Gets all elements in the form by their name and returns
              * a YUI NodeList
              * @return Y.NodeList
              */
@@ -352,5 +357,17 @@ M.form.initFormDependencies = function(Y, formid, dependencies) {
         return dependencyManager;
     })();
 
-    return new M.form.dependencyManager();
-};
\ No newline at end of file
+    M.form.dependencyManagers[formid] = new M.form.dependencyManager();
+    return M.form.dependencyManagers[formid];
+};
+
+/**
+ * Update the state of a form. You need to call this after, for example, changing
+ * the state of some of the form input elements in your own code, in order that
+ * things like the disableIf state of elements can be updated.
+ */
+M.form.updateFormState = function(formid) {
+    if (formid in M.form.dependencyManagers) {
+        M.form.dependencyManagers[formid].checkDependencies(null);
+    }
+};
-- 
1.7.9.5


From 0a571db22b533f8543054ea3586a3ad00a6b8520 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 9 Aug 2012 13:48:56 +0100
Subject: [PATCH 386/903] MDL-34807 question bank: navigation loses place.

The symptom is that where we are now is not shown in the settings
navigation. However, the underlying cause is that question/edit.php is
doing some crazy thing of its own to build $PAGE->url, rather than using
the one returned by question_edit_setup.

Not that this patch itentionally removes the returnurl param. It was
added as part of a big change MDL-20276, which I think just got this
detail wrong. That variable is never used.
---
 question/edit.php |   25 ++++---------------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/question/edit.php b/question/edit.php
index 411cb37..58fe57c 100644
--- a/question/edit.php
+++ b/question/edit.php
@@ -27,32 +27,15 @@
 require_once(dirname(__FILE__) . '/../config.php');
 require_once($CFG->dirroot . '/question/editlib.php');
 
-$url = new moodle_url('/question/edit.php');
+list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) =
+        question_edit_setup('questions', '/question/edit.php');
+
+$url = new moodle_url($thispageurl);
 if (($lastchanged = optional_param('lastchanged', 0, PARAM_INT)) !== 0) {
     $url->param('lastchanged', $lastchanged);
 }
-if (($category = optional_param('category', 0, PARAM_TEXT)) !== 0) {
-    $url->param('category', $category);
-}
-if (($qpage = optional_param('qpage', 0, PARAM_INT)) !== 0) {
-    $url->param('qpage', $qpage);
-}
-if (($cat = optional_param('cat', 0, PARAM_TEXT)) !== 0) {
-    $url->param('cat', $cat);
-}
-if (($courseid = optional_param('courseid', 0, PARAM_INT)) !== 0) {
-    $url->param('courseid', $courseid);
-}
-if (($returnurl = optional_param('returnurl', 0, PARAM_INT)) !== 0) {
-    $url->param('returnurl', $returnurl);
-}
-if (($cmid = optional_param('cmid', 0, PARAM_INT)) !== 0) {
-    $url->param('cmid', $cmid);
-}
 $PAGE->set_url($url);
 
-list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) =
-        question_edit_setup('questions', '/question/edit.php');
 $questionbank = new question_bank_view($contexts, $thispageurl, $COURSE, $cm);
 $questionbank->process_actions();
 
-- 
1.7.9.5


From 94dd25e03b8945ea428ab903ad129ccb92c6ff55 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 13 Aug 2012 16:53:15 +0100
Subject: [PATCH 387/903] MDL-34862 question preview: improve preview
 ownership check.

Users should only be able to access their own quetion preview. In the
past, for reasons I can no longer remember, this was enforced
using the session. It is much better to set the question_usage to belong
to the user's context.
---
 question/engine/questionusage.php |    4 ++--
 question/preview.php              |   14 ++++++--------
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/question/engine/questionusage.php b/question/engine/questionusage.php
index f9470c0..e4de197 100644
--- a/question/engine/questionusage.php
+++ b/question/engine/questionusage.php
@@ -63,7 +63,7 @@ class question_usage_by_activity {
      */
     protected $preferredbehaviour = null;
 
-    /** @var object the context this usage belongs to. */
+    /** @var context the context this usage belongs to. */
     protected $context;
 
     /** @var string plugin name of the plugin this usage belongs to. */
@@ -104,7 +104,7 @@ class question_usage_by_activity {
         return $this->preferredbehaviour;
     }
 
-    /** @return object the context this usage belongs to. */
+    /** @return context the context this usage belongs to. */
     public function get_owning_context() {
         return $this->context;
     }
diff --git a/question/preview.php b/question/preview.php
index 56513e7..7e24ba3 100644
--- a/question/preview.php
+++ b/question/preview.php
@@ -75,14 +75,10 @@ $options->set_from_request();
 $PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark,
         $options, $options->variant, $context));
 
-// Get and validate exitsing preview, or start a new one.
+// Get and validate existing preview, or start a new one.
 $previewid = optional_param('previewid', 0, PARAM_INT);
 
 if ($previewid) {
-    if (!isset($SESSION->question_previews[$previewid])) {
-        print_error('notyourpreview', 'question');
-    }
-
     try {
         $quba = question_engine::load_questions_usage_by_activity($previewid);
 
@@ -94,6 +90,10 @@ if ($previewid) {
                 $options->maxmark, $options, $options->variant, $context), null, $e);
     }
 
+    if ($quba->get_owning_context()->instanceid != $USER->id) {
+        print_error('notyourpreview', 'question');
+    }
+
     $slot = $quba->get_first_question_number();
     $usedquestion = $quba->get_question($slot);
     if ($usedquestion->id != $question->id) {
@@ -104,7 +104,7 @@ if ($previewid) {
 
 } else {
     $quba = question_engine::make_questions_usage_by_activity(
-            'core_question_preview', $context);
+            'core_question_preview', context_user::instance($USER->id));
     $quba->set_preferred_behaviour($options->behaviour);
     $slot = $quba->add_question($question, $options->maxmark);
 
@@ -119,8 +119,6 @@ if ($previewid) {
     $transaction = $DB->start_delegated_transaction();
     question_engine::save_questions_usage_by_activity($quba);
     $transaction->allow_commit();
-
-    $SESSION->question_previews[$quba->get_id()] = true;
 }
 $options->behaviour = $quba->get_preferred_behaviour();
 $options->maxmark = $quba->get_question_max_mark($slot);
-- 
1.7.9.5


From 25e107e5a2432b30b34b866df7f9fca4449eb93d Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Tue, 14 Aug 2012 10:16:40 +1200
Subject: [PATCH 388/903] MDL-34795 completion: Add course_completed event

---
 lib/completion/completion_completion.php |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/completion/completion_completion.php b/lib/completion/completion_completion.php
index e6523ea..abfe789 100644
--- a/lib/completion/completion_completion.php
+++ b/lib/completion/completion_completion.php
@@ -165,7 +165,11 @@ class completion_completion extends data_object {
         $this->timecompleted = $timecomplete;
 
         // Save record
-        return $this->_save();
+        if ($result = $this->_save()) {
+            events_trigger('course_completed', $this->get_record_data());
+        }
+
+        return $result;
     }
 
     /**
-- 
1.7.9.5


From 5b918d0101738cd824987e1f558de69201742920 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Mon, 13 Aug 2012 16:24:12 -0700
Subject: [PATCH 389/903] MDL-34866 - Make "course display" default a site
 configurable option

---
 admin/settings/courses.php |    5 +++++
 course/edit_form.php       |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/admin/settings/courses.php b/admin/settings/courses.php
index 92722eb..277501f 100644
--- a/admin/settings/courses.php
+++ b/admin/settings/courses.php
@@ -47,6 +47,11 @@ if ($hassiteconfig
         $temp->add(new admin_setting_configselect('moodlecourse/legacyfiles', new lang_string('courselegacyfiles'), new lang_string('courselegacyfiles_help'), key($choices), $choices));
     }
 
+    $choices = array();
+    $choices[0] = new lang_string('coursedisplay_single');
+    $choices[1] = new lang_string('coursedisplay_multi');
+    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), 0, $choices));        
+    
     $temp->add(new admin_setting_heading('groups', new lang_string('groups', 'group'), ''));
     $choices = array();
     $choices[NOGROUPS] = new lang_string('groupsnone', 'group');
diff --git a/course/edit_form.php b/course/edit_form.php
index dd3d4bd..75380f3 100644
--- a/course/edit_form.php
+++ b/course/edit_form.php
@@ -124,7 +124,7 @@ class course_edit_form extends moodleform {
             array(COURSE_DISPLAY_SINGLEPAGE => get_string('coursedisplay_single'),
                 COURSE_DISPLAY_MULTIPAGE => get_string('coursedisplay_multi')));
         $mform->addHelpButton('coursedisplay', 'coursedisplay');
-        $mform->setDefault('coursedisplay', COURSE_DISPLAY_SINGLEPAGE);
+        $mform->setDefault('coursedisplay', $courseconfig->coursedisplay);
 
         for ($i = 0; $i <= $courseconfig->maxsections; $i++) {
             $sectionmenu[$i] = "$i";
-- 
1.7.9.5


From 894446f7fd6ec75fde6d79e42defa2d127a9d2f2 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 14 Aug 2012 11:33:32 +0800
Subject: [PATCH 390/903] MDL-34539 course - allow negative section numbers

This gives course format authors more flexibility.

Thanks to Itamar Tzadok for the suggestion.
---
 course/view.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/view.php b/course/view.php
index c750205..cb978d8 100644
--- a/course/view.php
+++ b/course/view.php
@@ -97,7 +97,7 @@
     $logparam = 'id='. $course->id;
     $loglabel = 'view';
     $infoid = $course->id;
-    if(!empty($section)) {
+    if ($section and $section > 0) {
         $loglabel = 'view section';
 
         // Get section details and check it exists.
-- 
1.7.9.5


From b5cbe52bfc6992e2aa0499496423a60e75e87560 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 31 Jul 2012 11:46:53 +0800
Subject: [PATCH 391/903] MDL-32759 Assignment 2.2: Changing grade for
 existing assignments will show warning that grades
 will not be scaled

---
 mod/assignment/assignment.js          |   12 ++++++++++++
 mod/assignment/lang/en/assignment.php |    1 +
 mod/assignment/mod_form.php           |   17 ++++++++++++++++-
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/mod/assignment/assignment.js b/mod/assignment/assignment.js
index 8615c4b..8a58440 100644
--- a/mod/assignment/assignment.js
+++ b/mod/assignment/assignment.js
@@ -35,3 +35,15 @@ M.mod_assignment.init_tree = function(Y, expand_all, htmlid) {
         tree.render();
     });
 };
+
+M.mod_assignment.init_grade_change = function(Y) {
+    var gradenode = Y.one('#id_grade');
+    if (gradenode) {
+        var originalvalue = gradenode.get('value');
+        gradenode.on('change', function() {
+            if (gradenode.get('value') != originalvalue) {
+                alert(M.str.mod_assignment.changegradewarning);
+            }
+        });
+    }
+};
\ No newline at end of file
diff --git a/mod/assignment/lang/en/assignment.php b/mod/assignment/lang/en/assignment.php
index 879840e..104f3ab 100644
--- a/mod/assignment/lang/en/assignment.php
+++ b/mod/assignment/lang/en/assignment.php
@@ -56,6 +56,7 @@ $string['assignment:view'] = 'View assignment';
 $string['availabledate'] = 'Available from';
 $string['cannotdeletefiles'] = 'An error occurred and files could not be deleted';
 $string['cannotviewassignment'] = 'You can not view this assignment';
+$string['changegradewarning'] = 'This assignment has graded submissions and changing the grade will not automatically re-calculate existing submission grades. You must re-grade all existing submissions, if you wish to change the grade.';
 $string['comment'] = 'Comment';
 $string['commentinline'] = 'Comment inline';
 $string['commentinline_help'] = 'If enabled, the submission text will be copied into the feedback comment field during grading, making it easier to comment inline (using a different colour, perhaps) or to edit the original text.';
diff --git a/mod/assignment/mod_form.php b/mod/assignment/mod_form.php
index 85c8423..56b407d 100644
--- a/mod/assignment/mod_form.php
+++ b/mod/assignment/mod_form.php
@@ -9,7 +9,7 @@ class mod_assignment_mod_form extends moodleform_mod {
     protected $_assignmentinstance = null;
 
     function definition() {
-        global $CFG, $DB;
+        global $CFG, $DB, $PAGE;
         $mform =& $this->_form;
 
         // this hack is needed for different settings of each subtype
@@ -76,6 +76,21 @@ class mod_assignment_mod_form extends moodleform_mod {
         $this->standard_coursemodule_elements();
 
         $this->add_action_buttons();
+
+        // Add warning popup/noscript tag, if grades are changed by user.
+        if ($mform->elementExists('grade') && !empty($this->_instance) && $DB->record_exists_select('assignment_submissions', 'assignment = ? AND grade <> -1', array($this->_instance))) {
+            $module = array(
+                'name' => 'mod_assignment',
+                'fullpath' => '/mod/assignment/assignment.js',
+                'requires' => array('node', 'event'),
+                'strings' => array(array('changegradewarning', 'mod_assignment'))
+                );
+            $PAGE->requires->js_init_call('M.mod_assignment.init_grade_change', null, false, $module);
+
+            // Add noscript tag in case
+            $noscriptwarning = $mform->createElement('static', 'warning', null,  html_writer::tag('noscript', get_string('changegradewarning', 'mod_assignment')));
+            $mform->insertElementBefore($noscriptwarning, 'grade');
+        }
     }
 
     // Needed by plugin assignment types if they include a filemanager element in the settings form
-- 
1.7.9.5


From d54294de3433b8929863c965eb8a4c85a6a25797 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 31 Jul 2012 12:04:37 +0800
Subject: [PATCH 392/903] MDL-32759 Assignment: Grades will not be scaled for
 new assignment module, and added warning message
 for user

---
 lib/grade/grade_item.php      |    3 ++-
 mod/assign/lang/en/assign.php |    1 +
 mod/assign/mod_form.php       |   17 ++++++++++++++++-
 mod/assign/module.js          |   12 ++++++++++++
 4 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/lib/grade/grade_item.php b/lib/grade/grade_item.php
index 8b1d312..12afe84 100644
--- a/lib/grade/grade_item.php
+++ b/lib/grade/grade_item.php
@@ -742,7 +742,8 @@ class grade_item extends grade_object {
 
             // Standardise score to the new grade range
             // NOTE: this is not compatible with current assignment grading
-            if ($this->itemmodule != 'assignment' and ($rawmin != $this->grademin or $rawmax != $this->grademax)) {
+            $isassignmentmodule = ($this->itemmodule == 'assignment') || ($this->itemmodule == 'assign');
+            if (!$isassignmentmodule && ($rawmin != $this->grademin or $rawmax != $this->grademax)) {
                 $rawgrade = grade_grade::standardise_score($rawgrade, $rawmin, $rawmax, $this->grademin, $this->grademax);
             }
 
diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index 5b2438b..96c1c22 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -64,6 +64,7 @@ $string['batchoperationconfirmreverttodraft'] = 'Revert selected submissions to
 $string['batchoperationlock'] = 'lock submissions';
 $string['batchoperationunlock'] = 'unlock submissions';
 $string['batchoperationreverttodraft'] = 'revert submissions to draft';
+$string['changegradewarning'] = 'This assignment has graded submissions and changing the grade will not automatically re-calculate existing submission grades. You must re-grade all existing submissions, if you wish to change the grade.';
 $string['comment'] = 'Comment';
 $string['conversionexception'] = 'Could not convert assignment. Exception was: {$a}.';
 $string['configshowrecentsubmissions'] = 'Everyone can see notifications of submissions in recent activity reports.';
diff --git a/mod/assign/mod_form.php b/mod/assign/mod_form.php
index 8ad624c..4b9929f 100644
--- a/mod/assign/mod_form.php
+++ b/mod/assign/mod_form.php
@@ -45,7 +45,7 @@ class mod_assign_mod_form extends moodleform_mod {
      * @return void
      */
     function definition() {
-        global $CFG, $DB;
+        global $CFG, $DB, $PAGE;
         $mform = $this->_form;
 
         $mform->addElement('header', 'general', get_string('general', 'form'));
@@ -109,6 +109,21 @@ class mod_assign_mod_form extends moodleform_mod {
         $this->standard_coursemodule_elements();
 
         $this->add_action_buttons();
+
+        // Add warning popup/noscript tag, if grades are changed by user.
+        if ($mform->elementExists('grade') && !empty($this->_instance) && $DB->record_exists_select('assign_grades', 'assignment = ? AND grade <> -1', array($this->_instance))) {
+            $module = array(
+                'name' => 'mod_assign',
+                'fullpath' => '/mod/assign/module.js',
+                'requires' => array('node', 'event'),
+                'strings' => array(array('changegradewarning', 'mod_assign'))
+                );
+            $PAGE->requires->js_init_call('M.mod_assign.init_grade_change', null, false, $module);
+
+            // Add noscript tag in case
+            $noscriptwarning = $mform->createElement('static', 'warning', null,  html_writer::tag('noscript', get_string('changegradewarning', 'mod_assign')));
+            $mform->insertElementBefore($noscriptwarning, 'grade');
+        }
     }
 
     /**
diff --git a/mod/assign/module.js b/mod/assign/module.js
index d01c9b3..a1cbe07 100644
--- a/mod/assign/module.js
+++ b/mod/assign/module.js
@@ -127,4 +127,16 @@ M.mod_assign.init_grading_options = function(Y) {
             });
         }
     });
+};
+
+M.mod_assign.init_grade_change = function(Y) {
+    var gradenode = Y.one('#id_grade');
+    if (gradenode) {
+        var originalvalue = gradenode.get('value');
+        gradenode.on('change', function() {
+            if (gradenode.get('value') != originalvalue) {
+                alert(M.str.mod_assign.changegradewarning);
+            }
+        });
+    }
 };
\ No newline at end of file
-- 
1.7.9.5


From 6353a60ed31af154427f3424cd0ae9a9f5e461fd Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Tue, 14 Aug 2012 13:18:21 +0930
Subject: [PATCH 393/903] MDL-34870: Prevent cohort enrol sync when updating
 course record

---
 enrol/cohort/lib.php |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/enrol/cohort/lib.php b/enrol/cohort/lib.php
index 2009867..49d8fcb 100644
--- a/enrol/cohort/lib.php
+++ b/enrol/cohort/lib.php
@@ -124,9 +124,7 @@ class enrol_cohort_plugin extends enrol_plugin {
         global $CFG;
 
         if (!$inserted) {
-            // sync cohort enrols
-            require_once("$CFG->dirroot/enrol/cohort/locallib.php");
-            enrol_cohort_sync($course->id);
+            // Let's not sync cohorts anytime a course is updated...
         } else {
             // cohorts are never inserted automatically
         }
-- 
1.7.9.5


From 2a5378d2c67941da6749f89fa33fe6fdc1f71d6b Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Wed, 8 Aug 2012 14:27:19 -0400
Subject: [PATCH 394/903] MDL-34793 mod_assign Fix rendering error that causes
 student view to break in some cases.

When feedback is switched on for a assignment, and the teacher enters a grade through the gradebook, the student
view would become broken, throwing a coding error. Added check that $status->grade is not empty before passing
to assign_feedback_XXX::is_empty(), as that function expects an object.
---
 mod/assign/renderer.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/renderer.php b/mod/assign/renderer.php
index 8ffe18f..2c488ea 100644
--- a/mod/assign/renderer.php
+++ b/mod/assign/renderer.php
@@ -324,7 +324,7 @@ class mod_assign_renderer extends plugin_renderer_base {
         }
 
         foreach ($status->feedbackplugins as $plugin) {
-            if ($plugin->is_enabled() && $plugin->is_visible() && !$plugin->is_empty($status->grade)) {
+            if ($plugin->is_enabled() && $plugin->is_visible() && !empty($status->grade) && !$plugin->is_empty($status->grade)) {
                 $row = new html_table_row();
                 $cell1 = new html_table_cell($plugin->get_name());
                 $pluginfeedback = new assign_feedback_plugin_feedback($plugin, $status->grade, assign_feedback_plugin_feedback::SUMMARY, $status->coursemoduleid, $status->returnaction, $status->returnparams);
-- 
1.7.9.5


From 1f65a019807859dc1cf427dc027c01e639595c24 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 14 Aug 2012 13:58:23 +0800
Subject: [PATCH 395/903] MDL-34563 - change plural strings and removed colon
 for accesshide label

---
 mod/data/field/date/field.class.php      |   12 ++++++------
 mod/data/field/multimenu/field.class.php |    2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php
index 5e13222..4bffcc3 100644
--- a/mod/data/field/date/field.class.php
+++ b/mod/data/field/date/field.class.php
@@ -44,11 +44,11 @@ class data_field_date extends data_field_base {
         }
 
         $str = '<div title="'.s($this->field->description).'">';
-        $dayselector = html_writer::label(get_string('day'), 'menufield_'.$this->field->id.'_day', false, array('class' => 'accesshide'))
+        $dayselector = html_writer::label(get_string('days'), 'menufield_'.$this->field->id.'_day', false, array('class' => 'accesshide'))
                      . html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content);
-        $monthselector = html_writer::label(get_string('month'), 'menufield_'.$this->field->id.'_month', false, array('class' => 'accesshide'))
+        $monthselector = html_writer::label(get_string('months'), 'menufield_'.$this->field->id.'_month', false, array('class' => 'accesshide'))
                        . html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content);
-        $yearselector = html_writer::label(get_string('year'), 'menufield_'.$this->field->id.'_year', false, array('class' => 'accesshide'))
+        $yearselector = html_writer::label(get_string('years'), 'menufield_'.$this->field->id.'_year', false, array('class' => 'accesshide'))
                       . html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content);
         $str .= $dayselector . $monthselector . $yearselector;
         $str .= '</div>';
@@ -58,11 +58,11 @@ class data_field_date extends data_field_base {
 
     //Enable the following three functions once core API issues have been addressed.
     function display_search_field($value=0) {
-        $selectors = html_writer::label(get_string('day'), 'menuf_'.$this->field->id.'_d', false, array('class' => 'accesshide'))
+        $selectors = html_writer::label(get_string('days'), 'menuf_'.$this->field->id.'_d', false, array('class' => 'accesshide'))
            . html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
-           . html_writer::label(get_string('month'), 'menuf_'.$this->field->id.'_m', false, array('class' => 'accesshide'))
+           . html_writer::label(get_string('months'), 'menuf_'.$this->field->id.'_m', false, array('class' => 'accesshide'))
            . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value)
-           . html_writer::label(get_string('year'), 'menuf_'.$this->field->id.'_y', false, array('class' => 'accesshide'))
+           . html_writer::label(get_string('years'), 'menuf_'.$this->field->id.'_y', false, array('class' => 'accesshide'))
            . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value);
        return $selectors;
 
diff --git a/mod/data/field/multimenu/field.class.php b/mod/data/field/multimenu/field.class.php
index 30a4a6a..1f3de9f 100644
--- a/mod/data/field/multimenu/field.class.php
+++ b/mod/data/field/multimenu/field.class.php
@@ -38,7 +38,7 @@ class data_field_multimenu extends data_field_base {
 
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<input name="field_' . $this->field->id . '[xxx]" type="hidden" value="xxx"/>'; // hidden field - needed for empty selection
-        $str .= '<label class="accesshide" for="field_' . $this->field->id . '">' . $this->field->name. ': </label>';
+        $str .= '<label class="accesshide" for="field_' . $this->field->id . '">' . $this->field->name. '</label>';
         $str .= '<select name="field_' . $this->field->id . '[]" id="field_' . $this->field->id . '" multiple="multiple">';
 
         foreach (explode("\n",$this->field->param1) as $option) {
-- 
1.7.9.5


From 8e017950e9e3fcbc7c7a9519fd81c9f9a1d0974a Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 14 Aug 2012 14:41:00 +0800
Subject: [PATCH 396/903] MDL-34535 message: userto should use is_number
 instead of is_init

---
 lib/messagelib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/messagelib.php b/lib/messagelib.php
index f4674ce..1fee1b0 100644
--- a/lib/messagelib.php
+++ b/lib/messagelib.php
@@ -60,7 +60,7 @@ function message_send($eventdata) {
     //TODO: we need to solve problems with database transactions here somehow, for now we just prevent transactions - sorry
     $DB->transactions_forbidden();
 
-    if (is_int($eventdata->userto)) {
+    if (is_number($eventdata->userto)) {
         $eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto));
     }
     if (is_int($eventdata->userfrom)) {
-- 
1.7.9.5


From ba338db5b54eb2081d72255b2205e9c2bad33725 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 14 Aug 2012 14:06:24 +0100
Subject: [PATCH 397/903] MDL-34885 phpunit: better cygwin detection.

For some reason, on my computer, $_SERVER['SHELL'] was not set, so I
changed the test to also consider $_SERVER['TERM']. This now works for
me.
---
 lib/phpunit/bootstraplib.php |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/phpunit/bootstraplib.php b/lib/phpunit/bootstraplib.php
index bc74dc9..b7c9fde 100644
--- a/lib/phpunit/bootstraplib.php
+++ b/lib/phpunit/bootstraplib.php
@@ -150,8 +150,16 @@ function phpunit_boostrap_fix_file_permissions($file) {
  * @return bool
  */
 function phpunit_bootstrap_is_cygwin() {
-    if (empty($_SERVER['SHELL']) or empty($_SERVER['OS'])) {
+    if (empty($_SERVER['OS']) or $_SERVER['OS'] !== 'Windows_NT') {
+        return false;
+
+    } else if (!empty($_SERVER['SHELL']) and $_SERVER['SHELL'] === '/bin/bash') {
+        return true;
+
+    } else if (!empty($_SERVER['TERM']) and $_SERVER['TERM'] === 'cygwin') {
+        return true;
+
+    } else {
         return false;
     }
-    return ($_SERVER['OS'] === 'Windows_NT' and $_SERVER['SHELL'] === '/bin/bash');
 }
-- 
1.7.9.5


From 90c510cf9d6798207240a08e86b839bfd6c835bb Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Tue, 14 Aug 2012 12:12:14 -0700
Subject: [PATCH 398/903] MDL-34866 - Make "course display" default a site
 configurable option

* Moved COURSE_DISPLAY_SINGLEPAGE and COURSE_DISPLAY_MULTIPAGE constants from courselib to moodlelib.php
* Using course display constants in course default admin setting page
---
 admin/settings/courses.php |    6 +++---
 course/lib.php             |    3 ---
 lib/moodlelib.php          |    6 ++++++
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/admin/settings/courses.php b/admin/settings/courses.php
index 277501f..01b37a2 100644
--- a/admin/settings/courses.php
+++ b/admin/settings/courses.php
@@ -48,9 +48,9 @@ if ($hassiteconfig
     }
 
     $choices = array();
-    $choices[0] = new lang_string('coursedisplay_single');
-    $choices[1] = new lang_string('coursedisplay_multi');
-    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), 0, $choices));        
+    $choices[COURSE_DISPLAY_SINGLEPAGE] = new lang_string('coursedisplay_single');
+    $choices[COURSE_DISPLAY_MULTIPAGE] = new lang_string('coursedisplay_multi');
+    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));        
     
     $temp->add(new admin_setting_heading('groups', new lang_string('groups', 'group'), ''));
     $choices = array();
diff --git a/course/lib.php b/course/lib.php
index f799b0d..ac7a957 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -47,9 +47,6 @@ define('FIRSTUSEDEXCELROW', 3);
 define('MOD_CLASS_ACTIVITY', 0);
 define('MOD_CLASS_RESOURCE', 1);
 
-define('COURSE_DISPLAY_SINGLEPAGE', 0); // display all sections on one page
-define('COURSE_DISPLAY_MULTIPAGE', 1); // split pages into a page per section
-
 function make_log_url($module, $url) {
     switch ($module) {
         case 'course':
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index afe9dc2..ec35d0f 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -480,6 +480,12 @@ define('MOODLE_OFFICIAL_MOBILE_SERVICE', 'moodle_mobile_app');
  */
 define('USER_CAN_IGNORE_FILE_SIZE_LIMITS', -1);
 
+/**
+ * Course display settings
+ */
+define('COURSE_DISPLAY_SINGLEPAGE', 0); // display all sections on one page
+define('COURSE_DISPLAY_MULTIPAGE', 1); // split pages into a page per section
+
 /// PARAMETER HANDLING ////////////////////////////////////////////////////
 
 /**
-- 
1.7.9.5


From 02d8fb146dabbf284285b9771034cc8b8ab0cae2 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 7 Aug 2012 10:53:33 +0800
Subject: [PATCH 399/903] MDL-29192 - clarify email_to_user call

---
 mod/forum/lib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index d052294..daf6f02 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -1014,7 +1014,8 @@ function forum_cron() {
 
                 $attachment = $attachname='';
                 $usetrueaddress = true;
-                //directly email forum digests rather than sending them via messaging
+                // 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);
 
                 if (!$mailresult) {
-- 
1.7.9.5


From 9bf629bb64254683b7fa4985d46621d185cd81e2 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 15 Aug 2012 00:31:33 +0000
Subject: [PATCH 400/903] Automatically generated installer lang files

---
 install/lang/is/admin.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/install/lang/is/admin.php b/install/lang/is/admin.php
index 9bae23d..34600b2 100644
--- a/install/lang/is/admin.php
+++ b/install/lang/is/admin.php
@@ -36,5 +36,8 @@ $string['cliincorrectvalueerror'] = 'Villa, ótækt gildi "{$a->value}" fyrir "{
 $string['cliincorrectvalueretry'] = 'Rangt gildi, vinsamlegast reyndu aftur';
 $string['clitypevalue'] = 'Sláðu inn gildi';
 $string['clitypevaluedefault'] = 'Sláðu inn gildi, sláðu á Enter hnappinn á lyklaborðinu til að nota sjálfgefið gildi ({$a})';
+$string['cliunknowoption'] = 'Óþekktir valkostir:
+  {$a}
+Vinsamlegast notaðu --help valkostinn.';
 $string['environmentrequireinstall'] = 'verður að vera uppsett og virkjað';
 $string['environmentrequireversion'] = 'krafist er útgáfu {$a->needed} en þú notast við útgáfu {$a->current}';
-- 
1.7.9.5


From 9bdc95b7029db06d2f01aa692b8cedf50454f2b8 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 27 Jul 2012 09:31:43 +0800
Subject: [PATCH 401/903] MDL-34583: Assignment upgrade loses comments from
 onlinetext and offline assignment types.

---
 mod/assign/feedback/comments/locallib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/assign/feedback/comments/locallib.php b/mod/assign/feedback/comments/locallib.php
index 237a00d..6510353 100644
--- a/mod/assign/feedback/comments/locallib.php
+++ b/mod/assign/feedback/comments/locallib.php
@@ -213,7 +213,8 @@ class assign_feedback_comments extends assign_feedback_plugin {
      */
     public function can_upgrade($type, $version) {
 
-        if (($type == 'upload' || $type == 'uploadsingle') && $version >= 2011112900) {
+        if (($type == 'upload' || $type == 'uploadsingle' ||
+             $type == 'online' || $type == 'offline') && $version >= 2011112900) {
             return true;
         }
         return false;
-- 
1.7.9.5


From 829f5e876a30cacb2221c94034c2a9f4c24241c1 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Wed, 15 Aug 2012 16:24:14 +0800
Subject: [PATCH 402/903] MDL-34565 - remove duplicate labeling

---
 mod/forum/search.php |   14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/mod/forum/search.php b/mod/forum/search.php
index 433269d..ebbc99f 100644
--- a/mod/forum/search.php
+++ b/mod/forum/search.php
@@ -343,15 +343,10 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timefromrestrict" type="checkbox" value="1" alt="'.get_string('searchdatefrom', 'forum').'" onclick="return lockoptions(\'searchform\', \'timefromrestrict\', timefromitems)" '.  $datefromchecked . ' /> ';
-    $selectors = html_writer::label(get_string('days'), 'menufromday', false, array('class' => 'accesshide'))
-               . html_writer::select_time('days', 'fromday', $datefrom)
-               . html_writer::label(get_string('months'), 'menufrommonth', false, array('class' => 'accesshide'))
+    $selectors = html_writer::select_time('days', 'fromday', $datefrom)
                . html_writer::select_time('months', 'frommonth', $datefrom)
-               . html_writer::label(get_string('years'), 'menufromyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'fromyear', $datefrom)
-               . html_writer::label(get_string('hours'), 'menufromhour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'fromhour', $datefrom)
-               . html_writer::label(get_string('minutes'), 'menufromminute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'fromminute', $datefrom);
     echo $selectors;
     echo '<input type="hidden" name="hfromday" value="0" />';
@@ -374,15 +369,10 @@ function forum_print_big_search_form($course) {
     }
 
     echo '<input name="timetorestrict" type="checkbox" value="1" alt="'.get_string('searchdateto', 'forum').'" onclick="return lockoptions(\'searchform\', \'timetorestrict\', timetoitems)" ' .$datetochecked. ' /> ';
-    $selectors = html_writer::label(get_string('days'), 'menutoday', false, array('class' => 'accesshide'))
-               . html_writer::select_time('days', 'today', $dateto)
-               . html_writer::label(get_string('months'), 'menutomonth', false, array('class' => 'accesshide'))
+    $selectors = html_writer::select_time('days', 'today', $dateto)
                . html_writer::select_time('months', 'tomonth', $dateto)
-               . html_writer::label(get_string('years'), 'menutoyear', false, array('class' => 'accesshide'))
                . html_writer::select_time('years', 'toyear', $dateto)
-               . html_writer::label(get_string('hours'), 'menutohour', false, array('class' => 'accesshide'))
                . html_writer::select_time('hours', 'tohour', $dateto)
-               . html_writer::label(get_string('minutes'), 'menutominute', false, array('class' => 'accesshide'))
                . html_writer::select_time('minutes', 'tominute', $dateto);
     echo $selectors;
 
-- 
1.7.9.5


From 25e77f4f73118efcc4581c3a05bbdf4a260a2fcc Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Wed, 15 Aug 2012 16:56:06 +0800
Subject: [PATCH 403/903] MDL-30370 mod_forum - Removing duplicate seleted
 field in the DB query
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Credit to Iñigo Zendegi
---
 mod/forum/lib.php |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index ab9a580..960af25 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -2090,8 +2090,7 @@ function forum_search_posts($searchterms, $courseid=0, $limitfrom=0, $limitnum=5
                          u.lastname,
                          u.email,
                          u.picture,
-                         u.imagealt,
-                         u.email
+                         u.imagealt
                     FROM $fromsql
                    WHERE $selectsql
                 ORDER BY p.modified DESC";
-- 
1.7.9.5


From 2a077c0d1b1952cf1466c1585de4ab69bd3daf8b Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 15 Aug 2012 10:25:25 +0100
Subject: [PATCH 404/903] MDL-34905 quiz: missing global $DB;

This code normally only runs when JS is disabled, which is why this was
not noticed before.
---
 mod/quiz/attemptlib.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php
index a4e70fa..7018487 100644
--- a/mod/quiz/attemptlib.php
+++ b/mod/quiz/attemptlib.php
@@ -1335,6 +1335,8 @@ class quiz_attempt {
      * flagged state was changed in the request.
      */
     public function save_question_flags() {
+        global $DB;
+
         $transaction = $DB->start_delegated_transaction();
         $this->quba->update_question_flags();
         question_engine::save_questions_usage_by_activity($this->quba);
-- 
1.7.9.5


From c4f0004a0a30c46547cac2d42851b67468224e6c Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 31 Jul 2012 18:29:39 +0100
Subject: [PATCH 405/903] MDL-32705 backup ui: add select all/none JavaScript
 on schema screens

---
 backup/util/ui/base_moodleform.class.php           |    3 +
 .../util/ui/yui/backupselectall/backupselectall.js |   80 ++++++++++++++++++++
 2 files changed, 83 insertions(+)
 create mode 100644 backup/util/ui/yui/backupselectall/backupselectall.js

diff --git a/backup/util/ui/base_moodleform.class.php b/backup/util/ui/base_moodleform.class.php
index 3a72edc..ce95e7a 100644
--- a/backup/util/ui/base_moodleform.class.php
+++ b/backup/util/ui/base_moodleform.class.php
@@ -324,6 +324,9 @@ abstract class base_moodleform extends moodleform {
         $config->noLabel = get_string('confirmcancelno', 'backup');
         $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
 
+        $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.select_all_init',
+                array(array('select' => get_string('select'), 'all' => get_string('all'), 'none' => get_string('none'))));
+
         parent::display();
     }
 
diff --git a/backup/util/ui/yui/backupselectall/backupselectall.js b/backup/util/ui/yui/backupselectall/backupselectall.js
new file mode 100644
index 0000000..9f05b7f
--- /dev/null
+++ b/backup/util/ui/yui/backupselectall/backupselectall.js
@@ -0,0 +1,80 @@
+YUI.add('moodle-backup-backupselectall', function(Y) {
+
+// Namespace for the backup
+M.core_backup = M.core_backup || {};
+
+/**
+ * Adds select all/none links to the top of the backup/restore/import schema page.
+ */
+M.core_backup.select_all_init = function(str) {
+    var formid = null;
+
+    var helper = function(e, check, type) {
+        e.preventDefault();
+
+        var len = type.length;
+        Y.all('input[type="checkbox"]').each(function(checkbox) {
+            var name = checkbox.get('name');
+            if (name.substring(name.length - len) == type) {
+                checkbox.set('checked', check);
+            }
+        });
+
+        // At this point, we really need to persuade the form we are part of to
+        // update all of its disabledIf rules. However, as far as I can see,
+        // given the way that lib/form/form.js is written, that is impossible.
+        if (formid && M.form) {
+            M.form.updateFormState(formid);
+        }
+    };
+
+    var html_generator = function(classname, idtype) {
+        return '<div class="' + classname + '">' +
+                    '<div class="fitem fitem_fcheckbox">' +
+                        '<div class="fitemtitle">' + str.select + '</div>' +
+                        '<div class="felement">' +
+                            '<a id="backup-all-' + idtype + '" href="#">' + str.all + '</a> / ' +
+                            '<a id="backup-none-' + idtype + '" href="#">' + str.none + '</a>' +
+                        '</div>' +
+                    '</div>' +
+                '</div>';
+    };
+
+    var firstsection = Y.one('fieldset#coursesettings .fcontainer.clearfix .grouped_settings.section_level');
+    if (!firstsection) {
+        // This is not a relevant page.
+        return;
+    }
+    if (!firstsection.one('.felement.fcheckbox')) {
+        // No checkboxes.
+        return;
+    }
+
+    formid = firstsection.ancestor('form').getAttribute('id');
+
+    var withuserdata = false;
+    Y.all('input[type="checkbox"]').each(function(checkbox) {
+        var name = checkbox.get('name');
+        if (name.substring(name.length - 9) == '_userdata') {
+            withuserdata = '_userdata';
+        } else if (name.substring(name.length - 9) == '_userinfo') {
+            withuserdata = '_userinfo';
+        }
+    });
+
+    var html = html_generator('include_setting section_level', 'included');
+    if (withuserdata) {
+        html += html_generator('normal_setting', 'userdata');
+    }
+    var links = Y.Node.create('<div class="grouped_settings section_level">' + html + '</div>');
+    firstsection.insert(links, 'before');
+
+    Y.one('#backup-all-included').on('click',  function(e) { helper(e, true,  '_included'); });
+    Y.one('#backup-none-included').on('click', function(e) { helper(e, false, '_included'); });
+    if (withuserdata) {
+        Y.one('#backup-all-userdata').on('click',  function(e) { helper(e, true,  withuserdata); });
+        Y.one('#backup-none-userdata').on('click', function(e) { helper(e, false, withuserdata); });
+    }
+}
+
+}, '@VERSION@', {'requires':['base','node','event', 'node-event-simulate']});
-- 
1.7.9.5


From 44d24d1297d97f74350216fe8dc0e237a0c583b2 Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Thu, 16 Aug 2012 10:43:29 +0800
Subject: [PATCH 406/903] MDL-31810 - Fixing unclosed DIV tags throughout
 Moodle

---
 report/stats/locallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/report/stats/locallib.php b/report/stats/locallib.php
index f8548c4..1b7fbec 100644
--- a/report/stats/locallib.php
+++ b/report/stats/locallib.php
@@ -197,7 +197,7 @@ function report_stats_report($course, $report, $mode, $user, $roleid, $time) {
                 echo "(".get_string("gdneed").")";
             } else {
                 if ($mode == STATS_MODE_DETAILED) {
-                    echo '<div class="graph"><img src="'.$CFG->wwwroot.'/report/stats/graph.php?mode='.$mode.'&amp;course='.$course->id.'&amp;time='.$time.'&amp;report='.$report.'&amp;userid='.$userid.'" alt="'.get_string('statisticsgraph').'" /></div';
+                    echo '<div class="graph"><img src="'.$CFG->wwwroot.'/report/stats/graph.php?mode='.$mode.'&amp;course='.$course->id.'&amp;time='.$time.'&amp;report='.$report.'&amp;userid='.$userid.'" alt="'.get_string('statisticsgraph').'" /></div>';
                 } else {
                     echo '<div class="graph"><img src="'.$CFG->wwwroot.'/report/stats/graph.php?mode='.$mode.'&amp;course='.$course->id.'&amp;time='.$time.'&amp;report='.$report.'&amp;roleid='.$roleid.'" alt="'.get_string('statisticsgraph').'" /></div>';
                 }
-- 
1.7.9.5


From 8309268b429b585eb1ab9306c9f9255dd5a78ceb Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Wed, 15 Aug 2012 17:50:19 +0800
Subject: [PATCH 407/903] MDL-34563 - removed double labeling and add label
 for input text

---
 mod/data/field/date/field.class.php |   14 ++++----------
 mod/data/field/file/field.class.php |    2 +-
 mod/data/field/file/mod.html        |    1 -
 mod/data/field/picture/mod.html     |    1 -
 mod/data/field/url/mod.html         |    2 +-
 mod/data/lib.php                    |    5 +++--
 6 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php
index 4bffcc3..313058c 100644
--- a/mod/data/field/date/field.class.php
+++ b/mod/data/field/date/field.class.php
@@ -44,12 +44,9 @@ class data_field_date extends data_field_base {
         }
 
         $str = '<div title="'.s($this->field->description).'">';
-        $dayselector = html_writer::label(get_string('days'), 'menufield_'.$this->field->id.'_day', false, array('class' => 'accesshide'))
-                     . html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content);
-        $monthselector = html_writer::label(get_string('months'), 'menufield_'.$this->field->id.'_month', false, array('class' => 'accesshide'))
-                       . html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content);
-        $yearselector = html_writer::label(get_string('years'), 'menufield_'.$this->field->id.'_year', false, array('class' => 'accesshide'))
-                      . html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content);
+        $dayselector = html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content);
+        $monthselector = html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content);
+        $yearselector = html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content);
         $str .= $dayselector . $monthselector . $yearselector;
         $str .= '</div>';
 
@@ -58,11 +55,8 @@ class data_field_date extends data_field_base {
 
     //Enable the following three functions once core API issues have been addressed.
     function display_search_field($value=0) {
-        $selectors = html_writer::label(get_string('days'), 'menuf_'.$this->field->id.'_d', false, array('class' => 'accesshide'))
-           . html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
-           . html_writer::label(get_string('months'), 'menuf_'.$this->field->id.'_m', false, array('class' => 'accesshide'))
+        $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
            . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value)
-           . html_writer::label(get_string('years'), 'menuf_'.$this->field->id.'_y', false, array('class' => 'accesshide'))
            . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value);
        return $selectors;
 
diff --git a/mod/data/field/file/field.class.php b/mod/data/field/file/field.class.php
index 4c7fdc1..35f51f0 100644
--- a/mod/data/field/file/field.class.php
+++ b/mod/data/field/file/field.class.php
@@ -91,7 +91,7 @@ class data_field_file extends data_field_base {
     }
 
     function display_search_field($value = '') {
-        return '<label class="accesshide" for=f_"' . $this->field->id . '">' . $this->field->name . '</label>' .
+        return '<label class="accesshide" for="f_' . $this->field->id . '">' . $this->field->name . '</label>' .
                '<input type="text" size="16" id="f_'.$this->field->id.'" name="f_'.$this->field->id.'" value="'.$value.'" />';
     }
 
diff --git a/mod/data/field/file/mod.html b/mod/data/field/file/mod.html
index 8330260..7a67a16 100644
--- a/mod/data/field/file/mod.html
+++ b/mod/data/field/file/mod.html
@@ -14,7 +14,6 @@
             <?php
                 $course = $DB->get_record('course', array('id'=>$this->data->course));
                 $choices = get_max_upload_sizes($CFG->maxbytes, $course->maxbytes);
-                echo html_writer::label($this->field->param3, 'menuparam3', false, array('class' => 'accesshide'));
                 echo html_writer::select($choices, 'param3', $this->field->param3, false, array('id' => 'param3'));
             ?>
         </td>
diff --git a/mod/data/field/picture/mod.html b/mod/data/field/picture/mod.html
index 349f424..4b32474 100644
--- a/mod/data/field/picture/mod.html
+++ b/mod/data/field/picture/mod.html
@@ -46,7 +46,6 @@
             <?php
                 $course = $DB->get_record('course', array('id'=>$this->data->course));
                 $choices = get_max_upload_sizes($CFG->maxbytes, $course->maxbytes);
-                echo html_writer::label($this->field->param3, 'menuparam3', false, array('class' => 'accesshide'));
                 echo html_writer::select($choices, 'param3', $this->field->param3, false, array('id'=>'param3'));
             ?>
         </td>
diff --git a/mod/data/field/url/mod.html b/mod/data/field/url/mod.html
index 0757afc..f39d376 100644
--- a/mod/data/field/url/mod.html
+++ b/mod/data/field/url/mod.html
@@ -8,7 +8,7 @@
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description);?>" /></td>
     </tr>
     <tr>
-        <td class="c0"><label for="param2"><?php echo get_string('forcelinkname', 'data'); ?></label></td>
+        <td class="c0"><label for="forcelinkname"><?php echo get_string('forcelinkname', 'data'); ?></label></td>
         <td class="c1"><input class="forcelinkname" type="text" name="param2" id="forcelinkname" value="<?php p($this->field->param2);?>" /></td>
     </tr>
     <tr>
diff --git a/mod/data/lib.php b/mod/data/lib.php
index 3b3b2a7..883a58e 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -243,6 +243,7 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
         }
 
         $str = '<div title="'.s($this->field->description).'">';
+        $str .= '<label class="accesshide" for="field_'.$this->field->id.'">'.$this->field->description.'</label>';
         $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
         $str .= '</div>';
 
@@ -1605,9 +1606,9 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     $fn = !empty($search_array[DATA_FIRSTNAME]->data) ? $search_array[DATA_FIRSTNAME]->data : '';
     $ln = !empty($search_array[DATA_LASTNAME]->data) ? $search_array[DATA_LASTNAME]->data : '';
     $patterns[]    = '/##firstname##/';
-    $replacement[] = '<input type="text" size="16" name="u_fn" value="'.$fn.'" />';
+    $replacement[] = '<label class="accesshide" for="u_fn">'.get_string('authorfirstname', 'data').'</label><input type="text" size="16" id="u_fn" name="u_fn" value="'.$fn.'" />';
     $patterns[]    = '/##lastname##/';
-    $replacement[] = '<input type="text" size="16" name="u_ln" value="'.$ln.'" />';
+    $replacement[] = '<label for="u_ln">'.get_string('authorfirstname', 'data').'</label><input type="text" size="16" id="u_ln" name="u_ln" value="'.$ln.'" />';
 
     // actual replacement of the tags
     $newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
-- 
1.7.9.5


From dc5d4f435a0859dac22f2328e63d3dbfa0f0b8e7 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 16 Aug 2012 12:26:31 +0800
Subject: [PATCH 408/903] MDL-34563 - change string firstname to lastname and
 add accesshide class

---
 mod/data/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/data/lib.php b/mod/data/lib.php
index 883a58e..7b139af 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -1608,7 +1608,7 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     $patterns[]    = '/##firstname##/';
     $replacement[] = '<label class="accesshide" for="u_fn">'.get_string('authorfirstname', 'data').'</label><input type="text" size="16" id="u_fn" name="u_fn" value="'.$fn.'" />';
     $patterns[]    = '/##lastname##/';
-    $replacement[] = '<label for="u_ln">'.get_string('authorfirstname', 'data').'</label><input type="text" size="16" id="u_ln" name="u_ln" value="'.$ln.'" />';
+    $replacement[] = '<label class="accesshide" for="u_ln">'.get_string('authorlastname', 'data').'</label><input type="text" size="16" id="u_ln" name="u_ln" value="'.$ln.'" />';
 
     // actual replacement of the tags
     $newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
-- 
1.7.9.5


From 1d075eadd9cb829e4897f5f7bca6e930a69230da Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Wed, 15 Aug 2012 13:32:19 +0100
Subject: [PATCH 409/903] MDL-34446 Fix bugs in previous commit

---
 lib/moodlelib.php |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 16106b4..f229b6b 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -8369,7 +8369,14 @@ function check_php_version($version='5.2.4') {
           if (empty($version)) {
               return true; // no version specified
           }
-          if (preg_match("/Opera\/([0-9\.]+)/i", $agent, $match)) {
+          // Recent Opera useragents have Version/ with the actual version, e.g.:
+          // Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/12.01
+          // That's Opera 12.01, not 9.8.
+          if (preg_match("/Version\/([0-9\.]+)/i", $agent, $match)) {
+              if (version_compare($match[1], $version) >= 0) {
+                  return true;
+              }
+          } else if (preg_match("/Opera\/([0-9\.]+)/i", $agent, $match)) {
               if (version_compare($match[1], $version) >= 0) {
                   return true;
               }
@@ -8384,7 +8391,7 @@ function check_php_version($version='5.2.4') {
           if (empty($version)) {
               return true; // no version specified
           }
-          if (preg_match("/AppleWebKit\/([0-9]+)/i", $agent, $match)) {
+          if (preg_match("/AppleWebKit\/([0-9.]+)/i", $agent, $match)) {
               if (version_compare($match[1], $version) >= 0) {
                   return true;
               }
@@ -8420,7 +8427,7 @@ function check_php_version($version='5.2.4') {
           if (empty($version)) {
               return true; // no version specified
           }
-          if (preg_match("/AppleWebKit\/([0-9]+)/i", $agent, $match)) {
+          if (preg_match("/AppleWebKit\/([0-9.]+)/i", $agent, $match)) {
               if (version_compare($match[1], $version) >= 0) {
                   return true;
               }
@@ -8670,7 +8677,7 @@ function get_browser_version_classes() {
 function can_use_rotated_text() {
     global $USER;
     return (check_browser_version('MSIE', 9) || check_browser_version('Firefox', 2) ||
-            check_browser_version('Chrome', 21) || check_browser_version('Safari', 536.26) ||
+            check_browser_version('Chrome', 21) || check_browser_version('Safari', 536.25) ||
             check_browser_version('Opera', 12) || check_browser_version('Safari iOS', 533)) &&
             !$USER->screenreader;
 }
-- 
1.7.9.5


From 5c57df4c9dd16b0f523a890523d4f1e6f6b0636a Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Thu, 16 Aug 2012 10:05:26 -0400
Subject: [PATCH 410/903] MDL-34376 mod_assign Fixing flaw in previous commit
 with not defining .

---
 mod/assign/lib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index 5ca8423..2da6610 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -212,6 +212,7 @@ function assign_print_overview($courses, &$htmlarray) {
     // Do assignment_base::isopen() here without loading the whole thing for speed
     foreach ($assignments as $key => $assignment) {
         $time = time();
+        $isopen = false;
         if ($assignment->duedate) {
             $isopen = $assignment->allowsubmissionsfromdate <= $time;
             if ($assignment->preventlatesubmissions) {
-- 
1.7.9.5


From 7033316dad688f1d35c9e619a922148f335fb4f2 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 16 Aug 2012 17:26:25 +0200
Subject: [PATCH 411/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 69b3a82..d362bf1 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.09;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.10;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120809)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120816)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 423030e7dc40ca99193ed0f2ec44f8b0d0cb966a Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 9 Aug 2012 15:40:08 +0100
Subject: [PATCH 412/903] MDL-34810 question bank: user prefs for some display
 options

The options that are remembered persistently are
* Also show questions from sub-categories
* Also show old questions
* Show question text in the question list
* Number of questions per page
---
 question/editlib.php |   60 +++++++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 27 deletions(-)

diff --git a/question/editlib.php b/question/editlib.php
index b2414a7..e688add 100644
--- a/question/editlib.php
+++ b/question/editlib.php
@@ -1639,12 +1639,8 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $requirec
         $pagevars['qpage'] = 0;
     }
 
-    $pagevars['qperpage'] = optional_param('qperpage', -1, PARAM_INT);
-    if ($pagevars['qperpage'] > -1) {
-        $thispageurl->param('qperpage', $pagevars['qperpage']);
-    } else {
-        $pagevars['qperpage'] = DEFAULT_QUESTIONS_PER_PAGE;
-    }
+    $pagevars['qperpage'] = question_get_display_preference(
+            'qperpage', DEFAULT_QUESTIONS_PER_PAGE, PARAM_INT, $thispageurl);
 
     for ($i = 1; $i <= question_bank_view::MAX_SORTS; $i++) {
         $param = 'qbs' . $i;
@@ -1672,28 +1668,12 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $requirec
         $pagevars['cat'] = "$category->id,$category->contextid";
     }
 
-    if(($recurse = optional_param('recurse', -1, PARAM_BOOL)) != -1) {
-        $pagevars['recurse'] = $recurse;
-        $thispageurl->param('recurse', $recurse);
-    } else {
-        $pagevars['recurse'] = 1;
-    }
+    // Display options.
+    $pagevars['recurse']    = question_get_display_preference('recurse',    1, PARAM_BOOL, $thispageurl);
+    $pagevars['showhidden'] = question_get_display_preference('showhidden', 0, PARAM_BOOL, $thispageurl);
+    $pagevars['qbshowtext'] = question_get_display_preference('qbshowtext', 0, PARAM_BOOL, $thispageurl);
 
-    if(($showhidden = optional_param('showhidden', -1, PARAM_BOOL)) != -1) {
-        $pagevars['showhidden'] = $showhidden;
-        $thispageurl->param('showhidden', $showhidden);
-    } else {
-        $pagevars['showhidden'] = 0;
-    }
-
-    if(($showquestiontext = optional_param('qbshowtext', -1, PARAM_BOOL)) != -1) {
-        $pagevars['qbshowtext'] = $showquestiontext;
-        $thispageurl->param('qbshowtext', $showquestiontext);
-    } else {
-        $pagevars['qbshowtext'] = 0;
-    }
-
-    //category list page
+    // Category list page.
     $pagevars['cpage'] = optional_param('cpage', 1, PARAM_INT);
     if ($pagevars['cpage'] != 1){
         $thispageurl->param('cpage', $pagevars['cpage']);
@@ -1703,6 +1683,32 @@ function question_edit_setup($edittab, $baseurl, $requirecmid = false, $requirec
 }
 
 /**
+ * Get a particular question preference that is also stored as a user preference.
+ * If the the value is given in the GET/POST request, then that value is used,
+ * and the user preference is updated to that value. Otherwise, the last set
+ * value of the user preference is used, or if it has never been set the default
+ * passed to this function.
+ *
+ * @param string $param the param name. The URL parameter set, and the GET/POST
+ *      parameter read. The user_preference name is 'question_bank_' . $param.
+ * @param mixed $default The default value to use, if not otherwise set.
+ * @param int $type one of the PARAM_... constants.
+ * @param moodle_url $thispageurl if the value has been explicitly set, we add
+ *      it to this URL.
+ * @return mixed the parameter value to use.
+ */
+function question_get_display_preference($param, $default, $type, $thispageurl) {
+    $submittedvalue = optional_param($param, null, $type);
+    if (is_null($submittedvalue)) {
+        return get_user_preferences('question_bank_' . $param, $default);
+    }
+
+    set_user_preference('question_bank_' . $param, $submittedvalue);
+    $thispageurl->param($param, $submittedvalue);
+    return $submittedvalue;
+}
+
+/**
  * Make sure user is logged in as required in this context.
  */
 function require_login_in_context($contextorid = null){
-- 
1.7.9.5


From 6247d0a82c379edff5527022153cc77fd9f521c2 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 14 Aug 2012 15:25:03 +0100
Subject: [PATCH 413/903] MDL-34889 phpunit: progress output in util.php
 --drop.

It is slow for me, and it is nice to know that something is going on.
---
 admin/tool/phpunit/cli/util.php |    2 +-
 lib/phpunit/classes/util.php    |   27 +++++++++++++++++++++++++--
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/admin/tool/phpunit/cli/util.php b/admin/tool/phpunit/cli/util.php
index 2986d64..5afd3ba 100644
--- a/admin/tool/phpunit/cli/util.php
+++ b/admin/tool/phpunit/cli/util.php
@@ -150,7 +150,7 @@ if ($diag) {
 } else if ($drop) {
     // make sure tests do not run in parallel
     phpunit_util::acquire_test_lock();
-    phpunit_util::drop_site();
+    phpunit_util::drop_site(true);
     // note: we must stop here because $CFG is messed up and we can not reinstall, sorry
     exit(0);
 
diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index 3380549..b580259 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -762,16 +762,20 @@ class phpunit_util {
      * Note: To be used from CLI scripts only.
      *
      * @static
+     * @param bool $displayprogress if true, this method will echo progress information.
      * @return void may terminate execution with exit code
      */
-    public static function drop_site() {
+    public static function drop_site($displayprogress = false) {
         global $DB, $CFG;
 
         if (!self::is_test_site()) {
             phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, 'Can not drop non-test site!!');
         }
 
-        // purge dataroot
+        // Purge dataroot
+        if ($displayprogress) {
+            echo "Purging dataroot:\n";
+        }
         self::reset_dataroot();
         phpunit_bootstrap_initdataroot($CFG->dataroot);
         $keep = array('.', '..', 'lock', 'webrunner.xml');
@@ -795,9 +799,28 @@ class phpunit_util {
             unset($tables['config']);
             $tables['config'] = 'config';
         }
+
+        if ($displayprogress) {
+            echo "Dropping tables:\n";
+        }
+        $dotsonline = 0;
         foreach ($tables as $tablename) {
             $table = new xmldb_table($tablename);
             $DB->get_manager()->drop_table($table);
+
+            if ($dotsonline == 60) {
+                if ($displayprogress) {
+                    echo "\n";
+                }
+                $dotsonline = 0;
+            }
+            if ($displayprogress) {
+                echo '.';
+            }
+            $dotsonline += 1;
+        }
+        if ($displayprogress) {
+            echo "\n";
         }
     }
 
-- 
1.7.9.5


From d1755c12a07cfc785c8b386677c0efdd2ec3e443 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 16 Aug 2012 17:33:08 +0100
Subject: [PATCH 414/903] MDL-34702 quiz DB: questiondecimalpoints has wrong
 default.

Thanks to the folks at UCL for tracking down this problem. It has only
hidden for 2+ years!
---
 mod/quiz/backup/moodle1/lib.php |    2 +-
 mod/quiz/db/install.xml         |    2 +-
 mod/quiz/db/upgrade.php         |   19 +++++++++++++++++++
 mod/quiz/version.php            |    2 +-
 4 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/mod/quiz/backup/moodle1/lib.php b/mod/quiz/backup/moodle1/lib.php
index 2e25b40..09efca0 100644
--- a/mod/quiz/backup/moodle1/lib.php
+++ b/mod/quiz/backup/moodle1/lib.php
@@ -56,7 +56,7 @@ class moodle1_mod_quiz_handler extends moodle1_mod_handler {
                 array(
                     'newfields' => array(
                         'showuserpicture'   => 0,
-                        'questiondecimalpoints' => -2,
+                        'questiondecimalpoints' => -1,
                         'introformat'   => 0,
                         'showblocks'    => 0,
                     )
diff --git a/mod/quiz/db/install.xml b/mod/quiz/db/install.xml
index fd12420..dede549 100644
--- a/mod/quiz/db/install.xml
+++ b/mod/quiz/db/install.xml
@@ -21,7 +21,7 @@
         <FIELD NAME="attemptonlast" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether subsequent attempts start from teh answer to the previous attempt (1) or start blank (0)." PREVIOUS="attempts" NEXT="grademethod"/>
         <FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="One of the values QUIZ_GRADEHIGHEST, QUIZ_GRADEAVERAGE, QUIZ_ATTEMPTFIRST or QUIZ_ATTEMPTLAST." PREVIOUS="attemptonlast" NEXT="decimalpoints"/>
         <FIELD NAME="decimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="2" SEQUENCE="false" COMMENT="Number of decimal points to use when displaying grades." PREVIOUS="grademethod" NEXT="questiondecimalpoints"/>
-        <FIELD NAME="questiondecimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="-2" SEQUENCE="false" COMMENT="Number of decimal points to use when displaying question grades. (-2 means use decimalpoints.)" PREVIOUS="decimalpoints" NEXT="reviewattempt"/>
+        <FIELD NAME="questiondecimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="-1" SEQUENCE="false" COMMENT="Number of decimal points to use when displaying question grades. (-1 means use decimalpoints.)" PREVIOUS="decimalpoints" NEXT="reviewattempt"/>
         <FIELD NAME="reviewattempt" TYPE="int" LENGTH="6" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. This is a bit field, decoded by the mod_quiz_display_options class. It is formed by ORing together the constants defined there." PREVIOUS="questiondecimalpoints" NEXT="reviewcorrectness"/>
         <FIELD NAME="reviewcorrectness" TYPE="int" LENGTH="6" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewattempt" NEXT="reviewmarks"/>
         <FIELD NAME="reviewmarks" TYPE="int" LENGTH="6" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewcorrectness" NEXT="reviewspecificfeedback"/>
diff --git a/mod/quiz/db/upgrade.php b/mod/quiz/db/upgrade.php
index 3bbbb6d..cb8e76d 100644
--- a/mod/quiz/db/upgrade.php
+++ b/mod/quiz/db/upgrade.php
@@ -341,6 +341,25 @@ function xmldb_quiz_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2012061702, 'quiz');
     }
 
+    if ($oldversion < 2012061703) {
+
+        // MDL-34702 the questiondecimalpoints column was created with default -2
+        // when it should have been -1, and no-one has noticed in the last 2+ years!
+
+        // Changing the default of field questiondecimalpoints on table quiz to -1.
+        $table = new xmldb_table('quiz');
+        $field = new xmldb_field('questiondecimalpoints', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '-1', 'decimalpoints');
+
+        // Launch change of default for field questiondecimalpoints.
+        $dbman->change_field_default($table, $field);
+
+        // Correct any wrong values.
+        $DB->set_field('quiz', 'questiondecimalpoints', -1, array('questiondecimalpoints' => -2));
+
+        // Quiz savepoint reached.
+        upgrade_mod_savepoint(true, 2012061703, 'quiz');
+    }
+
     return true;
 }
 
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index 67ca371..59c7b3c 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061702;       // The current module version (Date: YYYYMMDDXX).
+$module->version   = 2012061703;       // The current module version (Date: YYYYMMDDXX).
 $module->requires  = 2012061700;    // Requires this Moodle version.
 $module->component = 'mod_quiz';       // Full name of the plugin (used for diagnostics).
 $module->cron      = 60;
-- 
1.7.9.5


From 20d4ab97c02a3e9e4608c69b0c806cb0d7b7a410 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 16 Aug 2012 21:34:17 +0100
Subject: [PATCH 415/903] MDL-34937 quiz responses reports: attempt grade not
 shown.

---
 mod/quiz/report/responses/responses_table.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/report/responses/responses_table.php b/mod/quiz/report/responses/responses_table.php
index ed6ada4..a5a0c09 100644
--- a/mod/quiz/report/responses/responses_table.php
+++ b/mod/quiz/report/responses/responses_table.php
@@ -63,7 +63,7 @@ class quiz_responses_table extends quiz_attempts_report_table {
     }
 
     public function col_sumgrades($attempt) {
-        if ($attempt->state == quiz_attempt::FINISHED) {
+        if ($attempt->state != quiz_attempt::FINISHED) {
             return '-';
         }
 
-- 
1.7.9.5


From 16254fffc816a6ea8ca490f63e233e3538460624 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 17 Aug 2012 00:31:50 +0000
Subject: [PATCH 416/903] Automatically generated installer lang files

---
 install/lang/zh_cn/install.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/zh_cn/install.php b/install/lang/zh_cn/install.php
index c338c8b..93647de 100644
--- a/install/lang/zh_cn/install.php
+++ b/install/lang/zh_cn/install.php
@@ -81,7 +81,7 @@ $string['phpversionhelp'] = '<p>Moodle需要PHP 4.3.0或5.1.0（5.0.x有若干
 （如果正使用5.0.x，您也可以降级到4.4.x版）</p>
 ';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
-$string['welcomep20'] = '您看到这个页面表明您已经成功地在您的计算机上安装了<strong>{$a->packname} {$a->packversion}</strong>。恭喜您！';
+$string['welcomep20'] = '您看到这个页面表明您已经成功地在您的计算机上安装并启用了<strong>{$a->packname} {$a->packversion}</strong>软件包。恭喜您！';
 $string['welcomep30'] = '<strong>{$a->installername}</strong>的此发行版包含了可以创建<strong>Moodle</strong>运行环境的应用程序：';
 $string['welcomep40'] = '这个软件包还包含了<strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>。';
 $string['welcomep50'] = '使用本软件包中包含的应用程序时应遵循它们各自的授权协议。整个<strong>{$a->installername}</strong>软件包都是<a href="http://www.opensource.org/docs/definition_plain.html">开源</a>的，并且遵循<a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>授权协议发布。';
-- 
1.7.9.5


From 93dbb62f4567b1805bf15f32b7d478f6311e3a6a Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 14 Aug 2012 12:40:31 +0800
Subject: [PATCH 417/903] MDL-34569 accessibility compliance for wiki module:
 Add label for input text and select tag

---
 mod/wiki/editors/wikieditor.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/wiki/editors/wikieditor.php b/mod/wiki/editors/wikieditor.php
index e880493..4865a7c 100644
--- a/mod/wiki/editors/wikieditor.php
+++ b/mod/wiki/editors/wikieditor.php
@@ -120,7 +120,8 @@ class MoodleQuickForm_wikieditor extends MoodleQuickForm_textarea {
             $html .= html_writer::empty_tag('img', array('alt' => $button[1], 'src' => $CFG->wwwroot . '/mod/wiki/editors/wiki/images/' . $button[0]));
             $html .= "</a>";
         }
-        $html .= "<select onchange=\"insertTags('{$imagetag[0]}', '{$imagetag[1]}', this.value)\">";
+        $html .= "<label class='accesshide' for='addtags'>" . get_string('insertimage', 'wiki')  . "</label>";
+        $html .= "<select id='addtags' onchange=\"insertTags('{$imagetag[0]}', '{$imagetag[1]}', this.value)\">";
         $html .= "<option value='" . s(get_string('wikiimage', 'wiki')) . "'>" . get_string('insertimage', 'wiki') . '</option>';
         foreach ($this->files as $filename) {
             $html .= "<option value='".s($filename)."'>";
-- 
1.7.9.5


From 01dbe1fdadb6de18b8a1c0ee40a4f9c400d6176d Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 17 Aug 2012 11:33:40 +0800
Subject: [PATCH 418/903] MDL-34569 - add label for search wiki input text

---
 mod/wiki/lib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/wiki/lib.php b/mod/wiki/lib.php
index 35bee02..133178a 100644
--- a/mod/wiki/lib.php
+++ b/mod/wiki/lib.php
@@ -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 .= '<input name="searchstring" type="text" size="18" value="' . s($search, true) . '" alt="search" />';
+    $output .= '<label class="accesshide" for="searchwiki">' . get_string("searchwikis", "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 . '" />';
     $output .= '<input name="searchwikicontent" type="hidden" value="1" />';
-- 
1.7.9.5


From bf821575ece5ce063e2229f3f2ba75b6e78bb4eb Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 14 Aug 2012 17:19:28 +0800
Subject: [PATCH 419/903] MDL-26492 Lesson: lesson_get_user_grades will return
 grade of all users if userid=0

---
 mod/lesson/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php
index 8c7b4d9..dc3495b 100644
--- a/mod/lesson/lib.php
+++ b/mod/lesson/lib.php
@@ -345,7 +345,7 @@ function lesson_get_user_grades($lesson, $userid=0) {
 
     $params = array("lessonid" => $lesson->id,"lessonid2" => $lesson->id);
 
-    if (isset($userid)) {
+    if (!empty($userid)) {
         $params["userid"] = $userid;
         $params["userid2"] = $userid;
         $user = "AND u.id = :userid";
-- 
1.7.9.5


From a645f67aa5ae21237ace9b49d9640fb8e5a4669f Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 14 Aug 2012 15:48:38 +0800
Subject: [PATCH 420/903] MDL-31734 Course: removed unused sectiontitle string

---
 course/recent_form.php |    2 --
 1 file changed, 2 deletions(-)

diff --git a/course/recent_form.php b/course/recent_form.php
index b79e443..dc7fa19 100644
--- a/course/recent_form.php
+++ b/course/recent_form.php
@@ -101,8 +101,6 @@ class recent_form extends moodleform {
             $mform->setAdvanced('user');
         }
 
-        $sectiontitle = get_string('sectionname', 'format_'.$COURSE->format);
-
         $options = array(''=>get_string('allactivities'));
         $modsused = array();
 
-- 
1.7.9.5


From 054bcf69f6047f6fb8fe6feeb7ee452b4eda9ecc Mon Sep 17 00:00:00 2001
From: Matt Meisberger <mmeisberger@webcourseworks.com>
Date: Sun, 5 Aug 2012 15:06:04 -0500
Subject: [PATCH 421/903] MDL-34742 - adding ability to move blocks into empty
 column

---
 lib/blocklib.php |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/blocklib.php b/lib/blocklib.php
index 1c7097e..b41b67c 100644
--- a/lib/blocklib.php
+++ b/lib/blocklib.php
@@ -457,6 +457,12 @@ class block_manager {
         if (!$this->page->theme->enable_dock) {
             return false;
         }
+
+        // Do not dock the region when the user attemps to move a block.
+        if ($this->movingblock) {
+            return false;
+        }
+
         $this->check_is_loaded();
         $this->ensure_content_created($region, $output);
         foreach($this->visibleblockcontent[$region] as $instance) {
-- 
1.7.9.5


From bc2289cd528914dab229ccee0a5056508b3adc06 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 15 Aug 2012 17:27:11 +0800
Subject: [PATCH 422/903] MDL-34648 Chat: No more errors when sentence begin
 with 'To'

---
 mod/chat/lib.php |   79 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 47 insertions(+), 32 deletions(-)

diff --git a/mod/chat/lib.php b/mod/chat/lib.php
index c8936ec..483f0dc 100644
--- a/mod/chat/lib.php
+++ b/mod/chat/lib.php
@@ -767,16 +767,15 @@ function chat_format_message_manually($message, $courseid, $sender, $currentuser
     }
 
     // It's not a system event
-
-    $text = $message->message;
+    $text = trim($message->message);
 
     /// Parse the text to clean and filter it
-
     $options = new stdClass();
     $options->para = false;
     $text = format_text($text, FORMAT_MOODLE, $options, $courseid);
 
     // And now check for special cases
+    $patternTo = '#^\s*To\s([^:]+):(.*)#';
     $special = false;
 
     if (substr($text, 0, 5) == 'beep ') {
@@ -799,23 +798,32 @@ function chat_format_message_manually($message, $courseid, $sender, $currentuser
             return false;
         }
     } else if (substr($text, 0, 1) == '/') {     /// It's a user command
-        // support some IRC commands
+        $special = true;
         $pattern = '#(^\/)(\w+).*#';
-        preg_match($pattern, trim($text), $matches);
-        $command = $matches[2];
+        preg_match($pattern, $text, $matches);
+        $command = isset($matches[2]) ? $matches[2] : false;
+        // Support some IRC commands.
         switch ($command){
-        case 'me':
-            $special = true;
-            $outinfo = $message->strtime;
-            $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
-            break;
+            case 'me':
+                $outinfo = $message->strtime;
+                $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
+                break;
+            default:
+                // Error, we set special back to false to use the classic message output.
+                $special = false;
+                break;
         }
-    } elseif (substr($text, 0, 2) == 'To') {
-        $pattern = '#To[[:space:]](.*):(.*)#';
-        preg_match($pattern, trim($text), $matches);
+    } else if (preg_match($patternTo, $text)) {
         $special = true;
-        $outinfo = $message->strtime;
-        $outmain = $sender->firstname.' '.get_string('saidto', 'chat').' <i>'.$matches[1].'</i>: '.$matches[2];
+        $matches = array();
+        preg_match($patternTo, $text, $matches);
+        if (isset($matches[1]) && isset($matches[2])) {
+            $outinfo = $message->strtime;
+            $outmain = $sender->firstname.' '.get_string('saidto', 'chat').' <i>'.$matches[1].'</i>: '.$matches[2];
+        } else {
+            // Error, we set special back to false to use the classic message output.
+            $special = false;
+        }
     }
 
     if(!$special) {
@@ -929,7 +937,7 @@ function chat_format_message_theme ($message, $chatuser, $currentuser, $grouping
     }
 
     // It's not a system event
-    $text = $message->message;
+    $text = trim($message->message);
 
     /// Parse the text to clean and filter it
     $options = new stdClass();
@@ -940,8 +948,9 @@ function chat_format_message_theme ($message, $chatuser, $currentuser, $grouping
     $special = false;
     $outtime = $message->strtime;
 
-    //Initilise output variable.
+    // Initialise variables.
     $outmain = '';
+    $patternTo = '#^\s*To\s([^:]+):(.*)#';
 
     if (substr($text, 0, 5) == 'beep ') {
         $special = true;
@@ -969,26 +978,33 @@ function chat_format_message_theme ($message, $chatuser, $currentuser, $grouping
     } else if (substr($text, 0, 1) == '/') {     /// It's a user command
         $special = true;
         $result->type = 'command';
-        // support some IRC commands
         $pattern = '#(^\/)(\w+).*#';
-        preg_match($pattern, trim($text), $matches);
-        $command = $matches[2];
-        $special = true;
+        preg_match($pattern, $text, $matches);
+        $command = isset($matches[2]) ? $matches[2] : false;
+        // Support some IRC commands.
         switch ($command){
-        case 'me':
-            $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
-            break;
+            case 'me':
+                $outmain = '*** <b>'.$sender->firstname.' '.substr($text, 4).'</b>';
+                break;
+            default:
+                // Error, we set special back to false to use the classic message output.
+                $special = false;
+                break;
         }
-    } elseif (substr($text, 0, 2) == 'To') {
+    } else if (preg_match($patternTo, $text)) {
         $special = true;
         $result->type = 'dialogue';
-        $pattern = '#To[[:space:]](.*):(.*)#';
-        preg_match($pattern, trim($text), $matches);
-        $special = true;
-        $outmain = $sender->firstname.' <b>'.get_string('saidto', 'chat').'</b> <i>'.$matches[1].'</i>: '.$matches[2];
+        $matches = array();
+        preg_match($patternTo, $text, $matches);
+        if (isset($matches[1]) && isset($matches[2])) {
+            $outmain = $sender->firstname.' <b>'.get_string('saidto', 'chat').'</b> <i>'.$matches[1].'</i>: '.$matches[2];
+        } else {
+            // Error, we set special back to false to use the classic message output.
+            $special = false;
+        }
     }
 
-    if(!$special) {
+    if (!$special) {
         $outmain = $text;
     }
 
@@ -1034,7 +1050,6 @@ function chat_format_message_theme ($message, $chatuser, $currentuser, $grouping
     }
 }
 
-
 /**
  * @global object $DB
  * @global object $CFG
-- 
1.7.9.5


From 68576ef61d23d622a3fa79bc3efcda05dc2f399a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 12 Jul 2012 09:39:52 +0800
Subject: [PATCH 423/903] MDL-28531 Backup: Automated backups run when they
 are scheduled

---
 backup/util/helper/backup_cron_helper.class.php |   70 +++--
 lib/moodlelib.php                               |    4 +-
 lib/tests/backup_test.php                       |  336 ++++++++++++++++++++---
 3 files changed, 344 insertions(+), 66 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 9715a5d..e88805b 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -110,7 +110,7 @@ abstract class backup_cron_automated_helper {
             $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
             $showtime = "undefined";
             if ($nextstarttime > 0) {
-                $showtime = userdate($nextstarttime,"",$admin->timezone);
+                $showtime = date('r', $nextstarttime);
             }
 
             $rs = $DB->get_recordset('course');
@@ -124,7 +124,14 @@ abstract class backup_cron_automated_helper {
                 }
 
                 // Skip courses that do not yet need backup
-                $skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                $skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                if ($skipped && $backupcourse->nextstarttime != $nextstarttime) {
+                    $backupcourse->nextstarttime = $nextstarttime;
+                    $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+                    $DB->update_record('backup_courses', $backupcourse);
+                    mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
+                }
+
                 // Skip backup of unavailable courses that have remained unmodified in a month
                 if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + settings were unmodified last month
                     //Check log if there were any modifications to the course content
@@ -139,9 +146,10 @@ abstract class backup_cron_automated_helper {
                         $skipped = true;
                     }
                 }
+
                 //Now we backup every non-skipped course
                 if (!$skipped) {
-                    mtrace('Backing up '.$course->fullname, '...');
+                    mtrace('Backing up '.$course->fullname.'...');
 
                     //We have to send a email because we have included at least one backup
                     $emailpending = true;
@@ -270,38 +278,47 @@ abstract class backup_cron_automated_helper {
     /**
      * Works out the next time the automated backup should be run.
      *
-     * @param mixed $timezone
-     * @param int $now
-     * @return int
+     * @param mixed $timezone user timezone
+     * @param int $now timestamp, should not be in the past, most likely time()
+     * @return int timestamp of the next execution at server time
      */
     public static function calculate_next_automated_backup($timezone, $now) {
 
-        $result = -1;
+        $result = 0;
         $config = get_config('backup');
-        $midnight = usergetmidnight($now, $timezone);
+        $autohour = $config->backup_auto_hour;
+        $automin = $config->backup_auto_minute;
+
+        // Gets the user time relatively to the server time.
         $date = usergetdate($now, $timezone);
+        $usertime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
+        $diff = $now - $usertime;
 
-        // Get number of days (from today) to execute backups
+        // Get number of days (from user's today) to execute backups.
         $automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
-        $daysfromtoday = strpos($automateddays, "1", 1);
+        $daysfromnow = strpos($automateddays, "1");
 
-        // If we can't find the next day, we set it to tomorrow
-        if (empty($daysfromtoday)) {
-            $daysfromtoday = 1;
+        // Error, there are no days to schedule the backup for.
+        if ($daysfromnow === false) {
+            return 0;
         }
 
-        // If some day has been found
-        if ($daysfromtoday !== false) {
-            // Calculate distance
-            $dist = ($daysfromtoday * 86400) +                // Days distance
-                    ($config->backup_auto_hour * 3600) +      // Hours distance
-                    ($config->backup_auto_minute * 60);       // Minutes distance
-            $result = $midnight + $dist;
+        // Checks if the date would happen in the future (of the user).
+        $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
+        if ($userresult <= $usertime) {
+            // If not, we skip the first scheduled day, that should fix it.
+            $daysfromnow = strpos($automateddays, "1", 1);
+            $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
         }
 
-        // If that time is past, call the function recursively to obtain the next valid day
-        if ($result > 0 && $result < time()) {
-            $result = self::calculate_next_automated_backup($timezone, $result);
+        // Now we generate the time relative to the server.
+        $result = $userresult + $diff;
+
+        // If that time is past, call the function recursively to obtain the next valid day.
+        if ($result <= $now) {
+            // Checking time() in here works, but makes PHPUnit Tests extremely hard to predict.
+            // $now should never be earlier than time() anyway...
+            $result = self::calculate_next_automated_backup($timezone, $now + DAYSECS);
         }
 
         return $result;
@@ -411,7 +428,12 @@ abstract class backup_cron_automated_helper {
 
         $config = get_config('backup');
         $active = (int)$config->backup_auto_active;
-        if ($active === self::AUTO_BACKUP_DISABLED || ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL)) {
+        $weekdays = (string)$config->backup_auto_weekdays;
+
+        // In case of automated backup also check that it is scheduled for at least one weekday.
+        if ($active === self::AUTO_BACKUP_DISABLED ||
+                ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL) ||
+                ($rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false)) {
             return self::STATE_DISABLED;
         } else if (!empty($config->backup_auto_running)) {
             // Detect if the backup_auto_running semaphore is a valid one
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index f229b6b..096d467 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -2324,10 +2324,10 @@ function get_user_timezone($tz = 99) {
 
     $tz = 99;
 
-    while(($tz == '' || $tz == 99 || $tz == NULL) && $next = each($timezones)) {
+    // Loop while $tz is, empty but not zero, or 99, and there is another timezone is the array
+    while(((empty($tz) && !is_numeric($tz)) || $tz == 99) && $next = each($timezones)) {
         $tz = $next['value'];
     }
-
     return is_numeric($tz) ? (float) $tz : $tz;
 }
 
diff --git a/lib/tests/backup_test.php b/lib/tests/backup_test.php
index 1830f56..5b44435 100644
--- a/lib/tests/backup_test.php
+++ b/lib/tests/backup_test.php
@@ -36,149 +36,405 @@ class backup_testcase extends advanced_testcase {
     public function test_next_automated_backup() {
 
         $this->resetAfterTest();
-        $admin = get_admin();
-        $timezone = $admin->timezone;
+        set_config('backup_auto_active', '1', 'backup');
 
         // Notes
-        // - The next automated backup will never be on the same date than $now
         // - backup_auto_weekdays starts on Sunday
-        // - Tests cannot be done in the past.
+        // - Tests cannot be done in the past
+        // - Only the DST on the server side is handled.
 
-        // Every Wed and Sat at 11pm.
-        set_config('backup_auto_active', '1', 'backup');
+        // Every Tue and Fri at 11pm.
         set_config('backup_auto_weekdays', '0010010', 'backup');
         set_config('backup_auto_hour', '23', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 18:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-23:00', date('w-H:i', $next));
 
         // Every Sun and Sat at 12pm.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000001', 'backup');
         set_config('backup_auto_hour', '0', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-00:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-00:00', date('w-H:i', $next));
 
         // Every Sun at 4am.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1000000', 'backup');
         set_config('backup_auto_hour', '4', 'backup');
         set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Monday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-04:00', date('w-H:i', $next));
 
         // Every day but Wed at 8:30pm.
-        set_config('backup_auto_active', '1', 'backup');
         set_config('backup_auto_weekdays', '1110111', 'backup');
         set_config('backup_auto_hour', '20', 'backup');
         set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Monday');
+        $now = strtotime('next Tuesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('2-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Tuesday');
+        $now = strtotime('next Wednesday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Wednesday');
+        $now = strtotime('next Thursday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('4-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Thursday');
+        $now = strtotime('next Friday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('5-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Friday');
+        $now = strtotime('next Saturday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('6-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Saturday');
+        $now = strtotime('next Sunday 17:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
         $this->assertEquals('0-20:30', date('w-H:i', $next));
 
-        $now = strtotime('next Sunday');
+        // Sun, Tue, Thu, Sat at 12pm.
+        set_config('backup_auto_weekdays', '1010101', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 13:00:00');
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('1-20:30', date('w-H:i', $next));
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        // None.
+        set_config('backup_auto_weekdays', '0000000', 'backup');
+        set_config('backup_auto_hour', '15', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0', $next);
+
+        // Playing with timezones.
+        set_config('backup_auto_weekdays', '1111111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        $timezone = 99;
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        // Viva Australia! (UTC+8).
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+
+        $timezone = -10.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = -5.0; // 5am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 0.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 3.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 8.0; // 6pm for the user (same than the server).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 9.0; // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
+
+        $timezone = 13.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-21:00') : date('w-22:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 1am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // The big apple! (UTC-5 / UTC-4 DST).
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 6pm for the user (server time).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-20:00') : date('w-21:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 11pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('next Monday 18:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-09:00' : '2-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-01:00' : '2-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-21:00' : '1-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-19:00' : '1-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 9pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-17:00' : '6-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-09:00' : '6-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '02', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('next Monday 04:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-09:00' : '1-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 4am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-01:00' : '6-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-21:00' : '5-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-19:00' : '5-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-17:00' : '5-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-09:00' : '5-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
 
     }
 }
-- 
1.7.9.5


From d190fcd9d95772c9ba287a16b5159719d6022c77 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 14 Aug 2012 11:25:06 +0800
Subject: [PATCH 424/903] MDL-28531 Unit Tests: Fixed tests to work with core
 update

---
 lib/form/tests/dateselector_test.php     |    4 ++--
 lib/form/tests/datetimeselector_test.php |    4 ++--
 lib/tests/moodlelib_test.php             |    6 +++---
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/form/tests/dateselector_test.php b/lib/form/tests/dateselector_test.php
index ab8cb9a..8db9155 100644
--- a/lib/form/tests/dateselector_test.php
+++ b/lib/form/tests/dateselector_test.php
@@ -128,7 +128,7 @@ class dateselector_form_element_testcase extends basic_testcase {
                 'year' => 2011,
                 'usertimezone' => 0.0,
                 'timezone' => 0.0,
-                'timestamp' => 1309449600
+                'timestamp' => 1309478400 // 6am at UTC+0
             ),
             array (
                 'day' => 1,
@@ -136,7 +136,7 @@ class dateselector_form_element_testcase extends basic_testcase {
                 'year' => 2011,
                 'usertimezone' => 0.0,
                 'timezone' => 99,
-                'timestamp' => 1309449600
+                'timestamp' => 1309478400 // 6am at UTC+0
             )
         );
     }
diff --git a/lib/form/tests/datetimeselector_test.php b/lib/form/tests/datetimeselector_test.php
index b0ce16e..abd5cea 100644
--- a/lib/form/tests/datetimeselector_test.php
+++ b/lib/form/tests/datetimeselector_test.php
@@ -138,7 +138,7 @@ class datetimeselector_form_element_testcase extends basic_testcase {
                 'year' => 2011,
                 'usertimezone' => 0.0,
                 'timezone' => 0.0,
-                'timestamp' => 1309449600
+                'timestamp' => 1309478400 // 6am at UTC+0
             ),
             array (
                 'minute' => 0,
@@ -148,7 +148,7 @@ class datetimeselector_form_element_testcase extends basic_testcase {
                 'year' => 2011,
                 'usertimezone' => 0.0,
                 'timezone' => 99,
-                'timestamp' => 1309449600
+                'timestamp' => 1309478400 // 6am at UTC+0
             )
         );
     }
diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 2d03ffc..dd9665a 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -1549,9 +1549,9 @@ class moodlelib_testcase extends advanced_testcase {
                 'hour' => '10',
                 'minutes' => '00',
                 'seconds' => '00',
-                'timezone' => '0.0', //no dst offset
-                'applydst' => false,
-                'expectedoutput' => '1309528800'
+                'timezone' => '0.0',
+                'applydst' => false, //no dst offset
+                'expectedoutput' => '1309514400' // 6pm at UTC+0
             ),
             array(
                 'usertimezone' => 'America/Moncton',
-- 
1.7.9.5


From 7a4f9ba8e04962f2cfcced810d48b7125322f234 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Fri, 17 Aug 2012 11:00:14 +0800
Subject: [PATCH 425/903] MDL-34941 correct timestamp range: startdate of
 external fct create_course PHPunit test

---
 course/tests/externallib_test.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index ac3c4d9..08f8b4a 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -315,7 +315,7 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         $course2['format'] = 'weeks';
         $course2['showgrades'] = 1;
         $course2['newsitems'] = 3;
-        $course2['startdate'] = 32882306400; // 01/01/3012
+        $course2['startdate'] = 1420092000; // 01/01/2015
         $course2['numsections'] = 4;
         $course2['maxbytes'] = 100000;
         $course2['showreports'] = 1;
-- 
1.7.9.5


From 40f6697f2e78efc639b444b9959e71390d73ed9f Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Fri, 17 Aug 2012 10:39:38 +0100
Subject: [PATCH 426/903] MDL-31957 Course reset: Does not erase activity
 completion data

---
 course/reset_form.php  |    2 +-
 lang/en/completion.php |    1 +
 lib/completionlib.php  |   25 +++++++++++++++++++++++++
 lib/moodlelib.php      |    9 +++++----
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/course/reset_form.php b/course/reset_form.php
index cb899f0..09fb15b 100644
--- a/course/reset_form.php
+++ b/course/reset_form.php
@@ -19,7 +19,7 @@ class course_reset_form extends moodleform {
         $mform->addElement('checkbox', 'reset_logs', get_string('deletelogs'));
         $mform->addElement('checkbox', 'reset_notes', get_string('deletenotes', 'notes'));
         $mform->addElement('checkbox', 'reset_comments', get_string('deleteallcomments', 'moodle'));
-        $mform->addElement('checkbox', 'reset_course_completion', get_string('deletecoursecompletiondata', 'completion'));
+        $mform->addElement('checkbox', 'reset_completion', get_string('deletecompletiondata', 'completion'));
         $mform->addElement('checkbox', 'delete_blog_associations', get_string('deleteblogassociations', 'blog'));
         $mform->addHelpButton('delete_blog_associations', 'deleteblogassociations', 'blog');
 
diff --git a/lang/en/completion.php b/lang/en/completion.php
index 9a9d10c..f7e0829 100644
--- a/lang/en/completion.php
+++ b/lang/en/completion.php
@@ -71,6 +71,7 @@ $string['completionview_desc'] = 'Student must view this activity to complete it
 $string['configenablecompletion'] = 'When enabled, this lets you turn on completion tracking (progress) features at course level.';
 $string['csvdownload'] = 'Download in spreadsheet format (UTF-8 .csv)';
 $string['deletecoursecompletiondata'] = 'Delete course completion data';
+$string['deletecompletiondata'] = 'Delete completion data';
 $string['enablecompletion'] = 'Enable completion tracking';
 $string['err_noactivities'] = 'Completion information is not enabled for any activity, so none can be displayed. You can enable completion information by editing the settings for an activity.';
 $string['err_nousers'] = 'There are no students on this course or group for whom completion information is displayed. (By default, completion information is displayed only for students, so if there are no students, you will see this error. Administrators can alter this option via the admin screens.)';
diff --git a/lib/completionlib.php b/lib/completionlib.php
index 4df3bc0..cd07c45 100644
--- a/lib/completionlib.php
+++ b/lib/completionlib.php
@@ -712,6 +712,31 @@ class completion_info {
     }
 
     /**
+     * Deletes all activity and course completion data for an entire course
+     * (the below delete_all_state function does this for a single activity).
+     *
+     * Used by course reset page.
+     */
+    public function delete_all_completion_data() {
+        global $DB;
+
+        // Delete from database.
+        $DB->delete_records_select('course_modules_completion',
+                'coursemoduleid IN (SELECT id FROM {course_modules} WHERE course=?)',
+                array($this->course_id));
+
+        // Reset cache for current user.
+        if (isset($SESSION->completioncache) &&
+            array_key_exists($this->course_id, $SESSION->completioncache)) {
+
+            unset($SESSION->completioncache[$this->course_id]);
+        }
+
+        // Wipe course completion data too.
+        $this->delete_course_completion_data();
+    }
+
+    /**
      * Deletes completion state related to an activity for all users.
      *
      * Intended for use only when the activity itself is deleted.
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index f229b6b..2ec6c97 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -4829,12 +4829,13 @@ function reset_course_userdata($data) {
         $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteblogassociations', 'blog'), 'error'=>false);
     }
 
-    if (!empty($data->reset_course_completion)) {
-        // Delete course completion information
+    if (!empty($data->reset_completion)) {
+        // Delete course and activity completion information.
         $course = $DB->get_record('course', array('id'=>$data->courseid));
         $cc = new completion_info($course);
-        $cc->delete_course_completion_data();
-        $status[] = array('component'=>$componentstr, 'item'=>get_string('deletecoursecompletiondata', 'completion'), 'error'=>false);
+        $cc->delete_all_completion_data();
+        $status[] = array('component' => $componentstr,
+                'item' => get_string('deletecompletiondata', 'completion'), 'error' => false);
     }
 
     $componentstr = get_string('roles');
-- 
1.7.9.5


From 3e6b27698da14b7cf94bc983b54956c62099f92d Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 13 Aug 2012 18:55:09 +0100
Subject: [PATCH 427/903] MDL-29847 question preview: garbage collect old
 preview data.

This adds cron code which looks for question previews that have not been
touched for more than 24 hours, and deletes them.

We try to delete previews immediately. For example if the user clicks
start again, then we immediately delete their previous preview. However,
we can't do that if they just close the preview window. Hence we need
some cron code to clean up old preview that have got left lying around.

Normally, this code will not have much to do, so it will be very fast,
so we can afford to run it every cron.

This has been implemented in such a way that in future it will be easy
to add other cron code to the question bank.

Sadly, to make this work on MySQL, we require a horrible hack in the
already hacky delete_usage_records_for_mysql function.
---
 lib/cronlib.php             |    7 +++++++
 question/engine/bank.php    |   11 +++++++++++
 question/engine/datalib.php |   10 +++++++++-
 question/previewlib.php     |   27 +++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/lib/cronlib.php b/lib/cronlib.php
index 7155373..1e8b1c8 100644
--- a/lib/cronlib.php
+++ b/lib/cronlib.php
@@ -373,6 +373,13 @@ function cron_run() {
     }
 
 
+    // Run question bank clean-up.
+    mtrace("Starting the question bank cron...", '');
+    require_once($CFG->libdir . '/questionlib.php');
+    question_bank::cron();
+    mtrace('done.');
+
+
     //Run registration updated cron
     mtrace(get_string('siteupdatesstart', 'hub'));
     require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
diff --git a/question/engine/bank.php b/question/engine/bank.php
index 2864f04..29277ee 100644
--- a/question/engine/bank.php
+++ b/question/engine/bank.php
@@ -398,6 +398,17 @@ abstract class question_bank {
         self::ensure_fraction_options_initialised();
         return self::$fractionoptionsfull;
     }
+
+    /**
+     * Perform scheduled maintenance tasks relating to the question bank.
+     */
+    public static function cron() {
+        global $CFG;
+
+        // Delete any old question preview that got left in the database.
+        require_once($CFG->dirroot . '/question/previewlib.php');
+        question_preview_cron();
+    }
 }
 
 
diff --git a/question/engine/datalib.php b/question/engine/datalib.php
index e7f570e..6fbccbf 100644
--- a/question/engine/datalib.php
+++ b/question/engine/datalib.php
@@ -758,6 +758,14 @@ ORDER BY
      * @param qubaid_condition $qubaids identifies which question useages to delete.
      */
     protected function delete_usage_records_for_mysql(qubaid_condition $qubaids) {
+        $qubaidtest = $qubaids->usage_id_in();
+        if (strpos($qubaidtest, 'question_usages') !== false &&
+                strpos($qubaidtest, 'IN (SELECT') === 0) {
+            // This horrible hack is required by MDL-29847. It comes from
+            // http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/
+            $qubaidtest = 'IN (SELECT * FROM ' . substr($qubaidtest, 3) . ' AS hack_subquery_alias)';
+        }
+
         // TODO once MDL-29589 is fixed, eliminate this method, and instead use the new $DB API.
         $this->db->execute('
                 DELETE qu, qa, qas, qasd
@@ -765,7 +773,7 @@ ORDER BY
                   JOIN {question_attempts}          qa   ON qa.questionusageid = qu.id
              LEFT JOIN {question_attempt_steps}     qas  ON qas.questionattemptid = qa.id
              LEFT JOIN {question_attempt_step_data} qasd ON qasd.attemptstepid = qas.id
-                 WHERE qu.id ' . $qubaids->usage_id_in(),
+                 WHERE qu.id ' . $qubaidtest,
                 $qubaids->usage_id_in_params());
     }
 
diff --git a/question/previewlib.php b/question/previewlib.php
index f763557..e228245 100644
--- a/question/previewlib.php
+++ b/question/previewlib.php
@@ -316,3 +316,30 @@ function restart_preview($previewid, $questionid, $displayoptions, $context) {
     redirect(question_preview_url($questionid, $displayoptions->behaviour,
             $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context));
 }
+
+/**
+ * Scheduled tasks relating to question preview. Specifically, delete any old
+ * previews that are left over in the database.
+ */
+function question_preview_cron() {
+    $maxage = 24*60*60; // We delete previews that have not been touched for 24 hours.
+    $lastmodifiedcutoff = time() - $maxage;
+
+    mtrace("\n  Cleaning up old question previews...", '');
+    $oldpreviews = new qubaid_join('{question_usages} quba', 'quba.id',
+            '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)
+                    )
+            ',
+            array('qubacomponent' => 'core_question_preview',
+                'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff));
+
+    question_engine::delete_questions_usage_by_activities($oldpreviews);
+    mtrace('done.');
+}
-- 
1.7.9.5


From 71a03114e07925f1596736b7b4a37247287bbeaf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 15 Aug 2012 11:44:26 +0200
Subject: [PATCH 428/903] MDL-34912 fix invalid descriptionformat default
 handling

---
 lib/phpunit/classes/data_generator.php |   12 ++++++------
 lib/phpunit/tests/generator_test.php   |   12 ++++++++++++
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/lib/phpunit/classes/data_generator.php b/lib/phpunit/classes/data_generator.php
index 48a459f..8225f23 100644
--- a/lib/phpunit/classes/data_generator.php
+++ b/lib/phpunit/classes/data_generator.php
@@ -240,11 +240,11 @@ EOD;
         }
 
         if (!isset($record['descriptionformat'])) {
-            $record['description'] = FORMAT_MOODLE;
+            $record['descriptionformat'] = FORMAT_MOODLE;
         }
 
         if (!isset($record['parent'])) {
-            $record['descriptionformat'] = 0;
+            $record['parent'] = 0;
         }
 
         if (empty($record['parent'])) {
@@ -310,12 +310,12 @@ EOD;
             $record['numsections'] = 5;
         }
 
-        if (!isset($record['description'])) {
-            $record['description'] = "Test course $i\n$this->loremipsum";
+        if (!isset($record['summary'])) {
+            $record['summary'] = "Test course $i\n$this->loremipsum";
         }
 
-        if (!isset($record['descriptionformat'])) {
-            $record['description'] = FORMAT_MOODLE;
+        if (!isset($record['summaryformat'])) {
+            $record['summaryformat'] = FORMAT_MOODLE;
         }
 
         if (!isset($record['category'])) {
diff --git a/lib/phpunit/tests/generator_test.php b/lib/phpunit/tests/generator_test.php
index eb5df6b..316ee70 100644
--- a/lib/phpunit/tests/generator_test.php
+++ b/lib/phpunit/tests/generator_test.php
@@ -48,10 +48,22 @@ class core_phpunit_generator_testcase extends advanced_testcase {
         $count = $DB->count_records('course_categories');
         $category = $generator->create_category();
         $this->assertEquals($count+1, $DB->count_records('course_categories'));
+        $this->assertRegExp('/^Course category \d/', $category->name);
+        $this->assertSame('', $category->idnumber);
+        $this->assertRegExp('/^Test course category \d/', $category->description);
+        $this->assertSame(FORMAT_MOODLE, $category->descriptionformat);
 
         $count = $DB->count_records('course');
         $course = $generator->create_course();
         $this->assertEquals($count+1, $DB->count_records('course'));
+        $this->assertRegExp('/^Test course \d/', $course->fullname);
+        $this->assertRegExp('/^tc_\d/', $course->shortname);
+        $this->assertSame('', $course->idnumber);
+        $this->assertSame('topics', $course->format);
+        $this->assertEquals(0, $course->newsitems);
+        $this->assertEquals(5, $course->numsections);
+        $this->assertRegExp('/^Test course \d/', $course->summary);
+        $this->assertSame(FORMAT_MOODLE, $course->summaryformat);
 
         $section = $generator->create_course_section(array('course'=>$course->id, 'section'=>3));
         $this->assertEquals($course->id, $section->course);
-- 
1.7.9.5


From e3a5ed9dd719fb2b3c95cc5cf7266d903c1f771d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 11 Aug 2012 20:05:56 +0200
Subject: [PATCH 429/903] MDL-34776 improve multiple "NOT IN" enrolment and
 role related queries

---
 admin/roles/lib.php       |   10 ++++------
 enrol/locallib.php        |   14 +++++---------
 enrol/manual/locallib.php |    8 +++-----
 user/selector/lib.php     |    5 ++---
 4 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/admin/roles/lib.php b/admin/roles/lib.php
index d57233f..93703c8 100644
--- a/admin/roles/lib.php
+++ b/admin/roles/lib.php
@@ -1042,12 +1042,10 @@ class potential_assignees_below_course extends role_assign_user_selector_base {
         $countfields = 'SELECT COUNT(u.id)';
 
         $sql   = " FROM {user} u
-                  WHERE u.id IN ($enrolsql) $wherecondition
-                        AND u.id NOT IN (
-                           SELECT r.userid
-                             FROM {role_assignments} r
-                            WHERE r.contextid = :contextid
-                                  AND r.roleid = :roleid)";
+              LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
+                  WHERE u.id IN ($enrolsql)
+                        $wherecondition
+                        AND ra.id IS NULL";
         $order = ' ORDER BY lastname ASC, firstname ASC';
 
         $params['contextid'] = $this->context->id;
diff --git a/enrol/locallib.php b/enrol/locallib.php
index f7d5030..41b7337 100644
--- a/enrol/locallib.php
+++ b/enrol/locallib.php
@@ -278,7 +278,7 @@ class course_enrolment_manager {
         global $DB, $CFG;
 
         // Add some additional sensible conditions
-        $tests = array("id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
+        $tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
         $params = array('guestid' => $CFG->siteguest);
         if (!empty($search)) {
             $conditions = get_extra_user_fields($this->get_context());
@@ -306,10 +306,9 @@ class course_enrolment_manager {
         $fields      = 'SELECT '.$ufields;
         $countfields = 'SELECT COUNT(1)';
         $sql = " FROM {user} u
+            LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
                 WHERE $wherecondition
-                      AND u.id NOT IN (SELECT ue.userid
-                                         FROM {user_enrolments} ue
-                                         JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))";
+                      AND ue.id IS NULL";
         $order = ' ORDER BY u.lastname ASC, u.firstname ASC';
         $params['enrolid'] = $enrolid;
         $totalusers = $DB->count_records_sql($countfields . $sql, $params);
@@ -353,12 +352,9 @@ class course_enrolment_manager {
         $fields      = 'SELECT '.user_picture::fields('u', array('username','lastaccess'));
         $countfields = 'SELECT COUNT(u.id)';
         $sql   = " FROM {user} u
+              LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid)
                   WHERE $wherecondition
-                    AND u.id NOT IN (
-                           SELECT u.id
-                             FROM {role_assignments} r, {user} u
-                            WHERE r.contextid = :contextid AND
-                                  u.id = r.userid)";
+                    AND ra.id IS NULL";
         $order = ' ORDER BY lastname ASC, firstname ASC';
 
         $params['contextid'] = $this->context->id;
diff --git a/enrol/manual/locallib.php b/enrol/manual/locallib.php
index 3255882..1d09681 100644
--- a/enrol/manual/locallib.php
+++ b/enrol/manual/locallib.php
@@ -55,11 +55,9 @@ class enrol_manual_potential_participant extends user_selector_base {
         $countfields = 'SELECT COUNT(1)';
 
         $sql = " FROM {user} u
-                WHERE $wherecondition AND
-                      u.id NOT IN (
-                          SELECT ue.userid
-                            FROM {user_enrolments} ue
-                            JOIN {enrol} e ON (e.id = ue.enrolid AND e.id = :enrolid))";
+            LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
+                WHERE $wherecondition
+                      AND ue.id IS NULL";
         $order = ' ORDER BY u.lastname ASC, u.firstname ASC';
 
         if (!$this->is_validating()) {
diff --git a/user/selector/lib.php b/user/selector/lib.php
index b2aa1c42..2319332 100644
--- a/user/selector/lib.php
+++ b/user/selector/lib.php
@@ -832,10 +832,9 @@ class group_non_members_selector extends groups_user_selector_base {
                    JOIN ($enrolsql) e ON e.id = u.id
               LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid " . get_related_contexts_string($context) . " AND ra.roleid $roleids)
               LEFT JOIN {role} r ON r.id = ra.roleid
+              LEFT JOIN {groups_members} gm ON (gm.userid = u.id AND gm.groupid = :groupid)
                   WHERE u.deleted = 0
-                        AND u.id NOT IN (SELECT userid
-                                          FROM {groups_members}
-                                         WHERE groupid = :groupid)
+                        AND gm.id IS NULL
                         AND $searchcondition";
         $orderby = "ORDER BY u.lastname, u.firstname";
 
-- 
1.7.9.5


From 8a8dd7d8c8a4330d306f6d34edd0c7b7b68a38b4 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Mon, 6 Aug 2012 18:16:00 +0200
Subject: [PATCH 430/903] MDL-34738 qformat blackboard: blackboard format is
 broken

---
 question/format.php                                |   54 ++
 question/format/blackboard/format.php              |  641 ++++++++++++--------
 .../blackboard/lang/en/qformat_blackboard.php      |    6 +-
 .../blackboard/tests/blackboardformat_test.php     |  469 ++++++++++++++
 .../tests/fixtures/sample_blackboard.dat           |  142 +++++
 question/format/blackboard/version.php             |    3 +-
 6 files changed, 1046 insertions(+), 269 deletions(-)
 create mode 100644 question/format/blackboard/tests/blackboardformat_test.php
 create mode 100644 question/format/blackboard/tests/fixtures/sample_blackboard.dat

diff --git a/question/format.php b/question/format.php
index 0ccdbce..a0e9df4 100644
--- a/question/format.php
+++ b/question/format.php
@@ -898,3 +898,57 @@ class qformat_default {
                 $question->questiontextformat, $formatoptions), 0, false);
     }
 }
+
+class qformat_based_on_xml extends qformat_default {
+
+    /**
+     * Return the array moodle is expecting
+     * for an HTML text. No processing is done on $text.
+     * qformat classes that want to process $text
+     * for instance to import external images files
+     * and recode urls in $text must overwrite this method.
+     * @param array $text some HTML text string
+     * @return array with keys text, format and files.
+     */
+    public function text_field($text) {
+        return array(
+            'text' => trim($text),
+            'format' => FORMAT_HTML,
+            'files' => array(),
+        );
+    }
+
+    /**
+     * Return the value of a node, given a path to the node
+     * if it doesn't exist return the default value.
+     * @param array xml data to read
+     * @param array path path to node expressed as array
+     * @param mixed default
+     * @param bool istext process as text
+     * @param string error if set value must exist, return false and issue message if not
+     * @return mixed value
+     */
+    public function getpath($xml, $path, $default, $istext=false, $error='') {
+        foreach ($path as $index) {
+            if (!isset($xml[$index])) {
+                if (!empty($error)) {
+                    $this->error($error);
+                    return false;
+                } else {
+                    return $default;
+                }
+            }
+
+            $xml = $xml[$index];
+        }
+
+        if ($istext) {
+            if (!is_string($xml)) {
+                $this->error(get_string('invalidxml', 'qformat_xml'));
+            }
+            $xml = trim($xml);
+        }
+
+        return $xml;
+    }
+}
diff --git a/question/format/blackboard/format.php b/question/format/blackboard/format.php
index 9ce23d0..1626489 100644
--- a/question/format/blackboard/format.php
+++ b/question/format/blackboard/format.php
@@ -17,8 +17,7 @@
 /**
  * Blackboard question importer.
  *
- * @package    qformat
- * @subpackage blackboard
+ * @package qformat_blackboard
  * @copyright  2003 Scott Elliott
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-require_once ($CFG->libdir . '/xmlize.php');
+require_once($CFG->libdir . '/xmlize.php');
 
 
 /**
@@ -35,19 +34,67 @@ require_once ($CFG->libdir . '/xmlize.php');
  * @copyright  2003 Scott Elliott
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class qformat_blackboard extends qformat_default {
+class qformat_blackboard extends qformat_based_on_xml {
+    // Is the current question's question text escaped HTML (true for most if not all Blackboard files).
+    public $ishtml = true;
+
 
     public function provide_import() {
         return true;
     }
 
-    function readquestions($lines) {
-        /// Parses an array of lines into an array of questions,
-        /// where each item is a question object as defined by
-        /// readquestion().
+    public function mime_type() {
+        return mimeinfo('type', '.dat');
+    }
+
+    /**
+     * Some softwares put entities in exported files.
+     * This method try to clean up known problems.
+     * @param string str string to correct
+     * @return string the corrected string
+     */
+    public function cleaninput($str) {
+        if (!$this->ishtml) {
+            return $str;
+        }
+        $html_code_list = array(
+            "&#039;" => "'",
+            "&#8217;" => "'",
+            "&#091;" => "[",
+            "&#8220;" => "\"",
+            "&#8221;" => "\"",
+            "&#093;" => "]",
+            "&#039;" => "'",
+            "&#8211;" => "-",
+            "&#8212;" => "-",
+        );
+        $str = strtr($str, $html_code_list);
+        // Use textlib entities_to_utf8 function to convert only numerical entities.
+        $str = textlib::entities_to_utf8($str, false);
+        return $str;
+    }
 
-        $text = implode($lines, " ");
-        $xml = xmlize($text, 0);
+    /**
+     * Parse the array of lines into an array of questions
+     * this *could* burn memory - but it won't happen that much
+     * so fingers crossed!
+     * @param array of lines from the input file.
+     * @param stdClass $context
+     * @return array (of objects) question objects.
+     */
+    protected function readquestions($lines) {
+
+        $text = implode($lines, ' ');
+        unset($lines);
+
+        // This converts xml to big nasty data structure,
+        // the 0 means keep white space as it is.
+        try {
+            $xml = xmlize($text, 0, 'UTF-8', true);
+        } catch (xml_format_exception $e) {
+            $this->error($e->getMessage(), '');
+            return false;
+        }
 
         $questions = array();
 
@@ -61,341 +108,405 @@ class qformat_blackboard extends qformat_default {
         return $questions;
     }
 
-//----------------------------------------
-// Process Essay Questions
-//----------------------------------------
-    function process_essay($xml, &$questions ) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_ESSAY"])) {
-            $essayquestions = $xml["POOL"]["#"]["QUESTION_ESSAY"];
+    /**
+     * Do question import processing common to every qtype.
+     * @param array $questiondata the xml tree related to the current question
+     * @return object initialized question object.
+     */
+    public function process_common($questiondata) {
+        global $CFG;
+
+        // This routine initialises the question object.
+        $question = $this->defaultquestion();
+
+        // Determine if the question is already escaped html.
+        $this->ishtml = $this->getpath($questiondata,
+                array('#', 'BODY', 0, '#', 'FLAGS', 0, '#', 'ISHTML', 0, '@', 'value'),
+                false, false);
+
+        // Put questiontext in question object.
+        $text = $this->getpath($questiondata,
+                array('#', 'BODY', 0, '#', 'TEXT', 0, '#'),
+                '', true, get_string('importnotext', 'qformat_blackboard'));
+
+        if ($this->ishtml) {
+            $question->questiontext = $this->cleaninput($text);
+            $question->questiontextformat = FORMAT_HTML;
+            $question->questiontextfiles = array();
+
+        } else {
+            $question->questiontext = $text;
         }
-        else {
-            return;
+        // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
+        $question->name = shorten_text(strip_tags($question->questiontext), 200);
+        $question->name = substr($question->name, 0, 250);
+        if (!$question->name) {
+            $id = $this->getpath($questiondata,
+                    array('@', 'id'), '',  true);
+            $question->name = get_string('defaultname', 'qformat_blackboard' , $id);
         }
 
-        foreach ($essayquestions as $essayquestion) {
+        $question->generalfeedback = '';
+        $question->generalfeedbackformat = FORMAT_HTML;
+        $question->generalfeedbackfiles = array();
 
-            $question = $this->defaultquestion();
+        // TODO : read the mark from the POOL TITLE QUESTIONLIST section.
+        $question->defaultmark = 1;
+        return $question;
+    }
+
+    /**
+     * Process Essay Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_essay($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_ESSAY'), false, false)) {
+            $essayquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_ESSAY'), false, false);
+        } else {
+            return;
+        }
 
-            $question->qtype = ESSAY;
+        foreach ($essayquestions as $thisquestion) {
 
-            // determine if the question is already escaped html
-            $ishtml = $essayquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
+            $question = $this->process_common($thisquestion);
 
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($essayquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]));
-            }
+            $question->qtype = 'essay';
 
-            // put name in question object
-            $question->name = substr($question->questiontext, 0, 254);
             $question->answer = '';
+            $answer = $this->getpath($thisquestion,
+                    array('#', 'ANSWER', 0, '#', 'TEXT', 0, '#'), '', true);
+            $question->graderinfo =  $this->text_field($this->cleaninput($answer));
             $question->feedback = '';
+            $question->responseformat = 'editor';
+            $question->responsefieldlines = 15;
+            $question->attachments = 0;
             $question->fraction = 0;
 
             $questions[] = $question;
         }
     }
 
-    //----------------------------------------
-    // Process True / False Questions
-    //----------------------------------------
-    function process_tf($xml, &$questions) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_TRUEFALSE"])) {
-            $tfquestions = $xml["POOL"]["#"]["QUESTION_TRUEFALSE"];
-        }
-        else {
+    /**
+     * Process True / False Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_tf($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false)) {
+            $tfquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false);
+        } else {
             return;
         }
 
-        for ($i = 0; $i < sizeof ($tfquestions); $i++) {
-
-            $question = $this->defaultquestion();
+        foreach ($tfquestions as $thisquestion) {
 
-            $question->qtype = TRUEFALSE;
-            $question->single = 1; // Only one answer is allowed
+            $question = $this->process_common($thisquestion);
 
-            $thisquestion = $tfquestions[$i];
+            $question->qtype = 'truefalse';
+            $question->single = 1; // Only one answer is allowed.
 
-            // determine if the question is already escaped html
-            $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), array(), false);
 
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]),ENT_QUOTES,'UTF-8');
-            }
-            // put name in question object
-            $question->name = shorten_text($question->questiontext, 254);
+            $correct_answer = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'),
+                    '', true);
 
-            $choices = $thisquestion["#"]["ANSWER"];
-
-            $correct_answer = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
-
-            // first choice is true, second is false.
-            $id = $choices[0]["@"]["id"];
-
-            if (strcmp($id, $correct_answer) == 0) {  // true is correct
+            // First choice is true, second is false.
+            $id = $this->getpath($choices[0], array('@', 'id'), '', true);
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            if (strcmp($id,  $correct_answer) == 0) {  // True is correct.
                 $question->answer = 1;
-                $question->feedbacktrue = trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]);
-                $question->feedbackfalse = trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]);
-            } else {  // false is correct
+                $question->feedbacktrue = $this->text_field($this->cleaninput($correctfeedback));
+                $question->feedbackfalse = $this->text_field($this->cleaninput($incorrectfeedback));
+            } else {  // False is correct.
                 $question->answer = 0;
-                $question->feedbacktrue = trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]);
-                $question->feedbackfalse = trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]);
+                $question->feedbacktrue = $this->text_field($this->cleaninput($incorrectfeedback));
+                $question->feedbackfalse = $this->text_field($this->cleaninput($correctfeedback));
             }
             $question->correctanswer = $question->answer;
             $questions[] = $question;
-          }
+        }
     }
 
-    //----------------------------------------
-    // Process Multiple Choice Questions
-    //----------------------------------------
-    function process_mc($xml, &$questions) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_MULTIPLECHOICE"])) {
-            $mcquestions = $xml["POOL"]["#"]["QUESTION_MULTIPLECHOICE"];
-        }
-        else {
+    /**
+     * Process Multiple Choice Questions with single answer
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_mc($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false)) {
+            $mcquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false);
+        } else {
             return;
         }
 
-        for ($i = 0; $i < sizeof ($mcquestions); $i++) {
-
-            $question = $this->defaultquestion();
-
-            $question->qtype = MULTICHOICE;
-            $question->single = 1; // Only one answer is allowed
-
-            $thisquestion = $mcquestions[$i];
-
-            // determine if the question is already escaped html
-            $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
-
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]),ENT_QUOTES,'UTF-8');
-            }
-
-            // put name of question in question object, careful of length
-            $question->name = shorten_text($question->questiontext, 254);
-
-            $choices = $thisquestion["#"]["ANSWER"];
-            for ($j = 0; $j < sizeof ($choices); $j++) {
-
-                $choice = trim($choices[$j]["#"]["TEXT"][0]["#"]);
-                // put this choice in the question object.
-                if ($ishtml) {
-                    $question->answer[$j] = html_entity_decode($choice,ENT_QUOTES,'UTF-8');
-                }
-                $question->answer[$j] = $question->answer[$j];
-
-                $id = $choices[$j]["@"]["id"];
-                $correct_answer_id = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"][0]["@"]["answer_id"];
-                // if choice is the answer, give 100%, otherwise give 0%
-                if (strcmp ($id, $correct_answer_id) == 0) {
-                    $question->fraction[$j] = 1;
-                    if ($ishtml) {
-                        $question->feedback[$j] = html_entity_decode(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]),ENT_QUOTES,'UTF-8');
-                    }
-                    $question->feedback[$j] = $question->feedback[$j];
+        foreach ($mcquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback));
+            $question->partiallycorrectfeedback = $this->text_field('');
+            $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback));
+
+            $question->qtype = 'multichoice';
+            $question->single = 1; // Only one answer is allowed.
+
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            $correct_answer_id = $this->getpath($thisquestion,
+                        array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'),
+                        '', true);
+            foreach ($choices as $choice) {
+                $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true);
+                // Put this choice in the question object.
+                $question->answer[] =  $this->text_field($this->cleaninput($choicetext));
+
+                $choice_id = $this->getpath($choice, array('@', 'id'), '', true);
+                // If choice is the right answer, give 100% mark, otherwise give 0%.
+                if (strcmp ($choice_id, $correct_answer_id) == 0) {
+                    $question->fraction[] = 1;
                 } else {
-                    $question->fraction[$j] = 0;
-                    if ($ishtml) {
-                        $question->feedback[$j] = html_entity_decode(trim(@$thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]),ENT_QUOTES,'UTF-8');
-                    }
-                    $question->feedback[$j] = $question->feedback[$j];
+                    $question->fraction[] = 0;
                 }
+                // There is never feedback specific to each choice.
+                $question->feedback[] =  $this->text_field('');
             }
             $questions[] = $question;
         }
     }
 
-    //----------------------------------------
-    // Process Multiple Choice Questions With Multiple Answers
-    //----------------------------------------
-    function process_ma($xml, &$questions) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_MULTIPLEANSWER"])) {
-            $maquestions = $xml["POOL"]["#"]["QUESTION_MULTIPLEANSWER"];
-        }
-        else {
+    /**
+     * Process Multiple Choice Questions With Multiple Answers
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_ma($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false)) {
+            $maquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false);
+        } else {
             return;
         }
 
-        for ($i = 0; $i < sizeof ($maquestions); $i++) {
-
-            $question = $this->defaultquestion();
-
-            $question->qtype = MULTICHOICE;
+        foreach ($maquestions as $thisquestion) {
+            $question = $this->process_common($thisquestion);
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback));
+            // As there is no partially correct feedback we use incorrect one.
+            $question->partiallycorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback));
+            $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback));
+
+            $question->qtype = 'multichoice';
             $question->defaultmark = 1;
-            $question->single = 0; // More than one answers allowed
-            $question->image = ""; // No images with this format
-
-            $thisquestion = $maquestions[$i];
-
-            // determine if the question is already escaped html
-            $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
-
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]),ENT_QUOTES,'UTF-8');
+            $question->single = 0; // More than one answers allowed.
+
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            $correct_answer_ids = array();
+            foreach ($this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false) as $correctanswer) {
+                if ($correctanswer) {
+                    $correct_answer_ids[] = $this->getpath($correctanswer,
+                            array('@', 'answer_id'),
+                            '', true);
+                }
             }
-            // put name of question in question object
-            $question->name = shorten_text($question->questiontext, 254);
+            $fraction = 1/count($correct_answer_ids);
 
-            $choices = $thisquestion["#"]["ANSWER"];
-            $correctanswers = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"];
+            foreach ($choices as $choice) {
+                $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true);
+                // Put this choice in the question object.
+                $question->answer[] =  $this->text_field($this->cleaninput($choicetext));
 
-            for ($j = 0; $j < sizeof ($choices); $j++) {
+                $choice_id = $this->getpath($choice, array('@', 'id'), '', true);
 
-                $choice = trim($choices[$j]["#"]["TEXT"][0]["#"]);
-                // put this choice in the question object.
-                $question->answer[$j] = $choice;
+                $iscorrect = in_array($choice_id, $correct_answer_ids);
 
-                $correctanswercount = sizeof($correctanswers);
-                $id = $choices[$j]["@"]["id"];
-                $iscorrect = 0;
-                for ($k = 0; $k < $correctanswercount; $k++) {
-
-                    $correct_answer_id = trim($correctanswers[$k]["@"]["answer_id"]);
-                    if (strcmp ($id, $correct_answer_id) == 0) {
-                        $iscorrect = 1;
-                    }
-
-                }
                 if ($iscorrect) {
-                    $question->fraction[$j] = floor(100000/$correctanswercount)/100000; // strange behavior if we have more than 5 decimal places
-                    $question->feedback[$j] = trim($thisquestion["#"]["GRADABLE"][$j]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]);
+                    $question->fraction[] = $fraction;
                 } else {
-                    $question->fraction[$j] = 0;
-                    $question->feedback[$j] = trim($thisquestion["#"]["GRADABLE"][$j]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]);
+                    $question->fraction[] = 0;
                 }
+                // There is never feedback specific to each choice.
+                $question->feedback[] =  $this->text_field('');
             }
-
             $questions[] = $question;
         }
     }
 
-    //----------------------------------------
-    // Process Fill in the Blank Questions
-    //----------------------------------------
-    function process_fib($xml, &$questions) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_FILLINBLANK"])) {
-            $fibquestions = $xml["POOL"]["#"]["QUESTION_FILLINBLANK"];
-        }
-        else {
+    /**
+     * Process Fill in the Blank Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_fib($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false)) {
+            $fibquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false);
+        } else {
             return;
         }
 
-        for ($i = 0; $i < sizeof ($fibquestions); $i++) {
-            $question = $this->defaultquestion();
-
-            $question->qtype = SHORTANSWER;
-            $question->usecase = 0; // Ignore case
-
-            $thisquestion = $fibquestions[$i];
-
-            // determine if the question is already escaped html
-            $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
-
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]),ENT_QUOTES,'UTF-8');
-            }
-            // put name of question in question object
-            $question->name = shorten_text($question->questiontext, 254);
-
-            $answer = trim($thisquestion["#"]["ANSWER"][0]["#"]["TEXT"][0]["#"]);
-
-            $question->answer[] = $answer;
-            $question->fraction[] = 1;
-            $question->feedback = array();
-
-            if (is_array( $thisquestion['#']['GRADABLE'][0]['#'] )) {
-                $question->feedback[0] = trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_CORRECT"][0]["#"]);
-            }
-            else {
-                $question->feedback[0] = '';
-            }
-            if (is_array( $thisquestion["#"]["GRADABLE"][0]["#"] )) {
-                $question->feedback[1] = trim($thisquestion["#"]["GRADABLE"][0]["#"]["FEEDBACK_WHEN_INCORRECT"][0]["#"]);
-            }
-            else {
-                $question->feedback[1] = '';
+        foreach ($fibquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $question->qtype = 'shortanswer';
+            $question->usecase = 0; // Ignore case.
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $answers = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            foreach ($answers as $answer) {
+                $question->answer[] = $this->getpath($answer,
+                        array('#', 'TEXT', 0, '#'), '', true);
+                $question->fraction[] = 1;
+                $question->feedback[] = $this->text_field($this->cleaninput($correctfeedback));
             }
+            $question->answer[] = '*';
+            $question->fraction[] = 0;
+            $question->feedback[] = $this->text_field($this->cleaninput($incorrectfeedback));
 
             $questions[] = $question;
         }
     }
 
-    //----------------------------------------
-    // Process Matching Questions
-    //----------------------------------------
-    function process_matching($xml, &$questions) {
-
-        if (isset($xml["POOL"]["#"]["QUESTION_MATCH"])) {
-            $matchquestions = $xml["POOL"]["#"]["QUESTION_MATCH"];
-        }
-        else {
+    /**
+     * Process Matching Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_matching($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MATCH'), false, false)) {
+            $matchquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MATCH'), false, false);
+        } else {
             return;
         }
-
-        for ($i = 0; $i < sizeof ($matchquestions); $i++) {
-
-            $question = $this->defaultquestion();
-
-            $question->qtype = MATCH;
-
-            $thisquestion = $matchquestions[$i];
-
-            // determine if the question is already escaped html
-            $ishtml = $thisquestion["#"]["BODY"][0]["#"]["FLAGS"][0]["#"]["ISHTML"][0]["@"]["value"];
-
-            // put questiontext in question object
-            if ($ishtml) {
-                $question->questiontext = html_entity_decode(trim($thisquestion["#"]["BODY"][0]["#"]["TEXT"][0]["#"]),ENT_QUOTES,'UTF-8');
+        // Blackboard questions can't be imported in core Moodle without a loss in data,
+        // as core match question don't allow HTML in subanswers. The contributed ddmatch
+        // question type support HTML in subanswers.
+        // The ddmatch question type is not part of core, so we need to check if it is defined.
+        $ddmatch_is_installed = question_bank::is_qtype_installed('ddmatch');
+
+        foreach ($matchquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+            if ($ddmatch_is_installed) {
+                $question->qtype = 'ddmatch';
+            } else {
+                $question->qtype = 'match';
             }
-            // put name of question in question object
-            $question->name = shorten_text($question->questiontext, 254);
-
-            $choices = $thisquestion["#"]["CHOICE"];
-            for ($j = 0; $j < sizeof ($choices); $j++) {
-
-                $subquestion = NULL;
-
-                $choice = $choices[$j]["#"]["TEXT"][0]["#"];
-                $choice_id = $choices[$j]["@"]["id"];
-
-                $question->subanswers[] = trim($choice);
-
-                $correctanswers = $thisquestion["#"]["GRADABLE"][0]["#"]["CORRECTANSWER"];
-                for ($k = 0; $k < sizeof ($correctanswers); $k++) {
-
-                    if (strcmp($choice_id, $correctanswers[$k]["@"]["choice_id"]) == 0) {
-
-                        $answer_id = $correctanswers[$k]["@"]["answer_id"];
 
-                        $answers = $thisquestion["#"]["ANSWER"];
-                        for ($m = 0; $m < sizeof ($answers); $m++) {
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback));
+            // As there is no partially correct feedback we use incorrect one.
+            $question->partiallycorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback));
+            $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback));
+
+            $choices = $this->getpath($thisquestion,
+                    array('#', 'CHOICE'), false, false); // Blackboard "choices" are Moodle subanswers.
+            $answers = $this->getpath($thisquestion,
+                    array('#', 'ANSWER'), false, false); // Blackboard "answers" are Moodle subquestions.
+            $correctanswers = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false); // Mapping between choices and answers.
+            $mappings = array();
+            foreach ($correctanswers as $correctanswer) {
+                if ($correctanswer) {
+                    $correct_choice_id = $this->getpath($correctanswer,
+                                array('@', 'choice_id'), '', true);
+                    $correct_answer_id = $this->getpath($correctanswer,
+                            array('@', 'answer_id'),
+                            '', true);
+                    $mappings[$correct_answer_id] = $correct_choice_id;
+                }
+            }
 
-                            $answer = $answers[$m];
-                            $current_ans_id = $answer["@"]["id"];
-                            if (strcmp ($current_ans_id, $answer_id) == 0) {
+            foreach ($choices as $choice) {
+                if ($ddmatch_is_installed) {
+                    $choicetext = $this->text_field($this->cleaninput($this->getpath($choice,
+                            array('#', 'TEXT', 0, '#'), '', true)));
+                } else {
+                    $choicetext = trim(strip_tags($this->getpath($choice,
+                            array('#', 'TEXT', 0, '#'), '', true)));
+                }
 
-                                $answer = $answer["#"]["TEXT"][0]["#"];
-                                $question->subquestions[] = trim($answer);
+                if ($choicetext != '') { // Only import non empty subanswers.
+                    $subquestion = '';
+                    $choice_id = $this->getpath($choice,
+                            array('@', 'id'), '', true);
+                    $fiber = array_search($choice_id, $mappings);
+                    $fiber = array_keys ($mappings, $choice_id);
+                    foreach ($fiber as $correct_answer_id) {
+                        // We have found a correspondance for this choice so we need to take the associated answer.
+                        foreach ($answers as $answer) {
+                            $current_ans_id = $this->getpath($answer,
+                                    array('@', 'id'), '', true);
+                            if (strcmp ($current_ans_id, $correct_answer_id) == 0) {
+                                $subquestion = $this->getpath($answer,
+                                        array('#', 'TEXT', 0, '#'), '', true);
                                 break;
                             }
                         }
-                        break;
+                        $question->subquestions[] = $this->text_field($this->cleaninput($subquestion));
+                        $question->subanswers[] = $choicetext;
+                    }
+
+                    if ($subquestion == '') { // Then in this case, $choice is a distractor.
+                        $question->subquestions[] = $this->text_field('');
+                        $question->subanswers[] = $choicetext;
                     }
                 }
             }
 
-            $questions[] = $question;
+            // Verify that this matching question has enough subquestions and subanswers.
+            $subquestioncount = 0;
+            $subanswercount = 0;
+            $subanswers = $question->subanswers;
+            foreach ($question->subquestions as $key => $subquestion) {
+                $subquestion = $subquestion['text'];
+                $subanswer = $subanswers[$key];
+                if ($subquestion != '') {
+                    $subquestioncount++;
+                }
+                $subanswercount++;
+            }
+            if ($subquestioncount < 2 || $subanswercount < 3) {
+                    $this->error(get_string('notenoughtsubans', 'qformat_blackboard', $question->questiontext));
+            } else {
+                $questions[] = $question;
+            }
 
         }
     }
diff --git a/question/format/blackboard/lang/en/qformat_blackboard.php b/question/format/blackboard/lang/en/qformat_blackboard.php
index 6f68e21..f5fa957 100644
--- a/question/format/blackboard/lang/en/qformat_blackboard.php
+++ b/question/format/blackboard/lang/en/qformat_blackboard.php
@@ -17,11 +17,13 @@
 /**
  * Strings for component 'qformat_blackboard', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    qformat
- * @subpackage blackboard
+ * @package    qformat_blackboard
  * @copyright  2010 Helen Foster
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['defaultname'] = 'Imported question {$a}';
+$string['importnotext'] = 'Missing question text in XML file';
+$string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
 $string['pluginname'] = 'Blackboard';
 $string['pluginname_help'] = 'Blackboard format enables questions saved in the Blackboard version 5 "POOL" type export format to be imported.';
diff --git a/question/format/blackboard/tests/blackboardformat_test.php b/question/format/blackboard/tests/blackboardformat_test.php
new file mode 100644
index 0000000..222b6b3
--- /dev/null
+++ b/question/format/blackboard/tests/blackboardformat_test.php
@@ -0,0 +1,469 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the Moodle Blackboard format.
+ *
+ * @package    qformat_blackboard
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/blackboard/format.php');
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the blackboard question import format.
+ *
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_blackboard_test extends question_testcase {
+
+    public function make_test_xml() {
+        $xml = "<?xml version='1.0' encoding='utf-8'?>
+<POOL>
+    <TITLE value='exam 3 2008-9'/>
+    <QUESTIONLIST>
+        <QUESTION id='q1' class='QUESTION_TRUEFALSE' points='1'/>
+        <QUESTION id='q7' class='QUESTION_MULTIPLECHOICE' points='1'/>
+        <QUESTION id='q8' class='QUESTION_MULTIPLEANSWER' points='1'/>
+        <QUESTION id='q39-44' class='QUESTION_MATCH' points='2'/>
+        <QUESTION id='q9' class='QUESTION_ESSAY' points='1'/>
+        <QUESTION id='q27' class='QUESTION_FILLINBLANK' points='1'/>
+    </QUESTIONLIST>
+    <QUESTION_TRUEFALSE id='q1'>
+        <BODY>
+            <TEXT><![CDATA[<span style=\"font-size:12pt\">42 is the Absolute Answer to everything.</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q1_a1'>
+            <TEXT>False</TEXT>
+        </ANSWER>
+        <ANSWER id='q1_a2'>
+            <TEXT>True</TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q1_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[42 is the Ultimate Answer.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_TRUEFALSE>
+    <QUESTION_MULTIPLECHOICE id='q7'>
+        <BODY>
+            <TEXT><![CDATA[<span style=\"font-size:12pt\">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q7_a1' position='1'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a2' position='2'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a3' position='3'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q7_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow is between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
+            </GRADABLE>
+    </QUESTION_MULTIPLECHOICE>
+    <QUESTION_MULTIPLEANSWER id='q8'>
+        <BODY>
+            <TEXT><![CDATA[<span style=\"font-size:12pt\">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q8_a1' position='1'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a2' position='2'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a3' position='3'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">off-beige</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a4' position='4'>
+        <TEXT><![CDATA[<span style=\"font-size:12pt\">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q8_a1'/>
+            <CORRECTANSWER answer_id='q8_a3'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT>
+                <![CDATA[Only yellow and off-beige are between orange and green in the spectrum.]]>
+            </FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_MULTIPLEANSWER>
+    <QUESTION_MATCH id='q39-44'>
+        <BODY>
+            <TEXT><![CDATA[<i>Classify the animals.</i>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q39-44_a1' position='1'>
+            <TEXT><![CDATA[frog]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a2' position='2'>
+            <TEXT><![CDATA[cat]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a3' position='3'>
+            <TEXT><![CDATA[newt]]></TEXT>
+        </ANSWER>
+        <CHOICE id='q39-44_c1' position='1'>
+            <TEXT><![CDATA[mammal]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c2' position='2'>
+            <TEXT><![CDATA[insect]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c3' position='3'>
+            <TEXT><![CDATA[amphibian]]></TEXT>
+        </CHOICE>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q39-44_a1' choice_id='q39-44_c3'/>
+            <CORRECTANSWER answer_id='q39-44_a2' choice_id='q39-44_c1'/>
+            <CORRECTANSWER answer_id='q39-44_a3' choice_id='q39-44_c3'/>
+        </GRADABLE>
+    </QUESTION_MATCH>
+    <QUESTION_ESSAY id='q9'>
+        <BODY>
+            <TEXT><![CDATA[How are you?]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q9_a1'>
+            <TEXT><![CDATA[Blackboard answer for essay questions will be imported as informations for graders.]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_ESSAY>
+    <QUESTION_FILLINBLANK id='q27'>
+        <BODY>
+            <TEXT><![CDATA[<span style=\"font-size:12pt\">Name an amphibian: __________.</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q27_a1' position='1'>
+            <TEXT>frog</TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_FILLINBLANK></POOL>";
+        return $xml;
+    }
+    public function test_import_match() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_matching($xmldata, $questions);
+        $q = $questions[0];
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'match';
+        $expectedq->name = 'Classify the animals.';
+        $expectedq->questiontext = '<i>Classify the animals.</i>';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->subquestions = array(
+            array('text' => 'cat', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'frog', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'newt', 'format' => FORMAT_HTML, 'files' => array()));
+        $expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian');
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_single() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_mc($xmldata, $questions);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 1;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => 'Only yellow is between orange and green in the spectrum.',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+        $expectedq->fraction = array(0, 1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_multi() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_ma($xmldata, $questions);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 0;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array(
+                'text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML,
+                'files' => array());
+        $expectedq->partiallycorrectfeedback = array(
+                'text' => 'Only yellow and off-beige are between orange and green in the spectrum.',
+                'format' => FORMAT_HTML,
+                'files' => array());
+        $expectedq->incorrectfeedback = array(
+                'text' => 'Only yellow and off-beige are between orange and green in the spectrum.',
+                'format' => FORMAT_HTML,
+                'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">off-beige</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                3 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+        $expectedq->fraction = array(0.5, 0, 0.5, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                3 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_truefalse() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_tf($xmldata, $questions);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'truefalse';
+        $expectedq->name = '42 is the Absolute Answer to everything.';
+        $expectedq->questiontext = '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->correctanswer = 0;
+        $expectedq->feedbacktrue = array(
+                'text' => '42 is the Ultimate Answer.',
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $expectedq->feedbackfalse = array(
+                'text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_fill_in_the_blank() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_fib($xmldata, $questions);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'shortanswer';
+        $expectedq->name = 'Name an amphibian: __________.';
+        $expectedq->questiontext = '<span style="font-size:12pt">Name an amphibian: __________.</span>';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->usecase = 0;
+        $expectedq->answer = array('frog', '*');
+        $expectedq->fraction = array(1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_essay() {
+
+        $xmldata = xmlize($this->make_test_xml());
+        $questions = array();
+
+        $importer = new qformat_blackboard();
+        $importer->process_essay($xmldata, $questions);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'essay';
+        $expectedq->name = 'How are you?';
+        $expectedq->questiontext = 'How are you?';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->responseformat = 'editor';
+        $expectedq->responsefieldlines = 15;
+        $expectedq->attachments = 0;
+        $expectedq->graderinfo = array(
+                'text' => 'Blackboard answer for essay questions will be imported as informations for graders.',
+                'format' => FORMAT_HTML,
+                'files' => array());
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+}
diff --git a/question/format/blackboard/tests/fixtures/sample_blackboard.dat b/question/format/blackboard/tests/fixtures/sample_blackboard.dat
new file mode 100644
index 0000000..88088c3
--- /dev/null
+++ b/question/format/blackboard/tests/fixtures/sample_blackboard.dat
@@ -0,0 +1,142 @@
+<?xml version='1.0' encoding='utf-8'?>
+<POOL>
+    <TITLE value='exam 3 2008-9'/>
+    <QUESTIONLIST>
+        <QUESTION id='q1' class='QUESTION_TRUEFALSE' points='1'/>
+        <QUESTION id='q7' class='QUESTION_MULTIPLECHOICE' points='1'/>
+        <QUESTION id='q8' class='QUESTION_MULTIPLEANSWER' points='1'/>
+        <QUESTION id='q39-44' class='QUESTION_MATCH' points='1'/>
+        <QUESTION id='q9' class='QUESTION_ESSAY' points='1'/>
+        <QUESTION id='q27' class='QUESTION_FILLINBLANK' points='1'/>
+    </QUESTIONLIST>
+    <QUESTION_TRUEFALSE id='q1'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q1_a1'>
+            <TEXT>False</TEXT>
+        </ANSWER>
+        <ANSWER id='q1_a2'>
+            <TEXT>True</TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q1_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[42 is the Ultimate Answer.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_TRUEFALSE>
+    <QUESTION_MULTIPLECHOICE id='q7'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q7_a1' position='1'>
+        <TEXT><![CDATA[<span style="font-size:12pt">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a2' position='2'>
+        <TEXT><![CDATA[<span style="font-size:12pt">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a3' position='3'>
+        <TEXT><![CDATA[<span style="font-size:12pt">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q7_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow is between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_MULTIPLECHOICE>
+    <QUESTION_MULTIPLEANSWER id='q8'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q8_a1' position='1'>
+        <TEXT><![CDATA[<span style="font-size:12pt">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a2' position='2'>
+        <TEXT><![CDATA[<span style="font-size:12pt">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a3' position='3'>
+        <TEXT><![CDATA[<span style="font-size:12pt">off-beige</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a4' position='4'>
+        <TEXT><![CDATA[<span style="font-size:12pt">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q8_a1'/>
+            <CORRECTANSWER answer_id='q8_a3'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow and off-beige are between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_MULTIPLEANSWER>
+    <QUESTION_MATCH id='q39-44'>
+        <BODY>
+            <TEXT><![CDATA[<i>Classify the animals.</i>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q39-44_a1' position='1'>
+            <TEXT><![CDATA[frog]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a2' position='2'>
+            <TEXT><![CDATA[cat]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a3' position='3'>
+            <TEXT><![CDATA[newt]]></TEXT>
+        </ANSWER>
+        <CHOICE id='q39-44_c1' position='1'>
+            <TEXT><![CDATA[mammal]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c2' position='2'>
+            <TEXT><![CDATA[insect]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c3' position='3'>
+            <TEXT><![CDATA[amphibian]]></TEXT>
+        </CHOICE>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q39-44_a1' choice_id='q39-44_c3'/>
+            <CORRECTANSWER answer_id='q39-44_a2' choice_id='q39-44_c1'/>
+            <CORRECTANSWER answer_id='q39-44_a3' choice_id='q39-44_c3'/>
+        </GRADABLE>
+    </QUESTION_MATCH>
+    <QUESTION_ESSAY id='q9'>
+        <BODY>
+            <TEXT><![CDATA[How are you?]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q9_a1'>
+            <TEXT><![CDATA[Blackboard answer for essay questions will be imported as informations for graders.]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_ESSAY>
+    <QUESTION_FILLINBLANK id='q27'>
+        <BODY>
+            <TEXT><![CDATA[Name an amphibian: __________.]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q27_a1' position='1'>
+            <TEXT>frog</TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_FILLINBLANK>
+</POOL>
diff --git a/question/format/blackboard/version.php b/question/format/blackboard/version.php
index f2334f3..53948ab 100644
--- a/question/format/blackboard/version.php
+++ b/question/format/blackboard/version.php
@@ -17,8 +17,7 @@
 /**
  * Version information for the calculated question type.
  *
- * @package    qformat
- * @subpackage blackboard
+ * @package    qformat_blackboard
  * @copyright  2011 The Open University
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-- 
1.7.9.5


From 3d7f23c5e92d809d50d19fdd0ea7c321ab89b98c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Mon, 13 Aug 2012 22:31:36 +0200
Subject: [PATCH 431/903] MDL-34864 improve enrol_category sync performance

---
 enrol/category/locallib.php |   15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/enrol/category/locallib.php b/enrol/category/locallib.php
index 6a7671b..2f4c0c1 100644
--- a/enrol/category/locallib.php
+++ b/enrol/category/locallib.php
@@ -265,6 +265,7 @@ function enrol_category_sync_full() {
 
     // first of all add necessary enrol instances to all courses
     $parentcat = $DB->sql_concat("cat.path", "'/%'");
+    $parentcctx = $DB->sql_concat("cctx.path", "'/%'");
     // need whole course records to be used by add_instance(), use inner view (ci) to
     // get distinct records only.
     // TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec
@@ -293,12 +294,11 @@ function enrol_category_sync_full() {
     $sql = "SELECT e.*
               FROM {enrol} e
               JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
-         LEFT JOIN (SELECT DISTINCT cctx.path
-                      FROM {course_categories} cc
+         LEFT JOIN ({course_categories} cc
                       JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
                       JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
-                   ) cat ON (ctx.path LIKE $parentcat)
-             WHERE e.enrol = 'category' AND cat.path IS NULL";
+                   ) ON (ctx.path LIKE $parentcctx)
+             WHERE e.enrol = 'category' AND cc.id IS NULL";
 
     $rs = $DB->get_recordset_sql($sql, $params);
     foreach($rs as $instance) {
@@ -333,12 +333,11 @@ function enrol_category_sync_full() {
               FROM {enrol} e
               JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
               JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
-         LEFT JOIN (SELECT DISTINCT cctx.path, ra.userid
-                      FROM {course_categories} cc
+         LEFT JOIN ({course_categories} cc
                       JOIN {context} cctx ON (cctx.instanceid = cc.id AND cctx.contextlevel = :catlevel)
                       JOIN {role_assignments} ra ON (ra.contextid = cctx.id AND ra.roleid $roleids)
-                   ) cat ON (ctx.path LIKE $parentcat AND cat.userid = ue.userid)
-             WHERE e.enrol = 'category' AND cat.userid IS NULL";
+                   ) ON (ctx.path LIKE $parentcctx AND ra.userid = ue.userid)
+             WHERE e.enrol = 'category' AND cc.id IS NULL";
     $rs = $DB->get_recordset_sql($sql, $params);
     foreach($rs as $instance) {
         $userid = $instance->userid;
-- 
1.7.9.5


From a2043a3168db1c8220d3e4da6f73fa238557f475 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 14 Aug 2012 21:57:50 +0200
Subject: [PATCH 432/903] MDL-34864 add verbose option to CLI enrol_category
 sync

---
 enrol/category/cli/sync.php |   30 ++++++++++++++++++++++++++++--
 enrol/category/locallib.php |   28 +++++++++++++++++++++++++---
 2 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/enrol/category/cli/sync.php b/enrol/category/cli/sync.php
index 47b1e37..56a4b82 100644
--- a/enrol/category/cli/sync.php
+++ b/enrol/category/cli/sync.php
@@ -36,9 +36,35 @@ define('CLI_SCRIPT', true);
 
 require(dirname(dirname(dirname(dirname(__FILE__)))).'/config.php');
 require_once("$CFG->dirroot/enrol/category/locallib.php");
+require_once("$CFG->libdir/clilib.php");
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help'));
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+if ($options['help']) {
+    $help =
+        "Execute course category enrolment sync.
+
+Options:
+-v, --verbose         Print verbose progess information
+-h, --help            Print out this help
+
+Example:
+\$ sudo -u www-data /usr/bin/php enrol/category/cli/sync.php
+";
+    echo $help;
+    die;
+}
+
 
 if (!enrol_is_enabled('category')) {
-     die('enrol_category plugin is disabled, sync is disabled');
+    cli_error('enrol_category plugin is disabled, synchronisation stopped');
 }
 
-enrol_category_sync_full();
+$verbose = !empty($options['verbose']);
+return enrol_category_sync_full($verbose);
diff --git a/enrol/category/locallib.php b/enrol/category/locallib.php
index 2f4c0c1..4cd7c5c 100644
--- a/enrol/category/locallib.php
+++ b/enrol/category/locallib.php
@@ -233,12 +233,12 @@ function enrol_category_sync_course($course) {
     }
 }
 
-function enrol_category_sync_full() {
+function enrol_category_sync_full($verbose = false) {
     global $DB;
 
 
     if (!enrol_is_enabled('category')) {
-        return;
+        return 2;
     }
 
     // we may need a lot of time here
@@ -251,12 +251,22 @@ function enrol_category_sync_full() {
     // any interesting roles worth synchronising?
     if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
         // yay, nothing to do, so let's remove all leftovers
+        if ($verbose) {
+            mtrace("No roles with 'enrol/category:synchronised' capability found.");
+        }
         if ($instances = $DB->get_records('enrol', array('enrol'=>'category'))) {
             foreach ($instances as $instance) {
+                if ($verbose) {
+                    mtrace("  deleting category enrol instance from course {$instance->courseid}");
+                }
                 $plugin->delete_instance($instance);
             }
         }
-        return;
+        return 0;
+    }
+    $rolenames = role_fix_names($roles, null, ROLENAME_SHORT, true);
+    if ($verbose) {
+        mtrace('Synchronising category enrolments for roles: '.implode(', ', $rolenames).'...');
     }
 
     list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
@@ -325,6 +335,9 @@ function enrol_category_sync_full() {
         unset($instance->userid);
         unset($instance->estart);
         $plugin->enrol_user($instance, $userid, null, $estart);
+        if ($verbose) {
+            mtrace("  enrolling: user $userid ==> course $instance->courseid");
+        }
     }
     $rs->close();
 
@@ -343,6 +356,15 @@ function enrol_category_sync_full() {
         $userid = $instance->userid;
         unset($instance->userid);
         $plugin->unenrol_user($instance, $userid);
+        if ($verbose) {
+            mtrace("  unenrolling: user $userid ==> course $instance->courseid");
+        }
     }
     $rs->close();
+
+    if ($verbose) {
+        mtrace('...user enrolment synchronisation finished.');
+    }
+
+    return 0;
 }
-- 
1.7.9.5


From 259aecb26bd8168abe92b72030c96d4f3bb869ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 14 Aug 2012 22:16:36 +0200
Subject: [PATCH 433/903] MDL-34864 improve enrol_category phpdocs

---
 enrol/category/cli/sync.php               |    8 +--
 enrol/category/db/access.php              |    4 +-
 enrol/category/db/events.php              |    6 +-
 enrol/category/db/install.php             |    4 +-
 enrol/category/lang/en/enrol_category.php |    6 +-
 enrol/category/lib.php                    |   25 ++++----
 enrol/category/locallib.php               |   92 ++++++++++++++++++-----------
 enrol/category/settings.php               |    7 +--
 8 files changed, 81 insertions(+), 71 deletions(-)

diff --git a/enrol/category/cli/sync.php b/enrol/category/cli/sync.php
index 56a4b82..7db80b8 100644
--- a/enrol/category/cli/sync.php
+++ b/enrol/category/cli/sync.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -19,15 +18,14 @@
  * CLI sync for full category enrol synchronisation.
  *
  * Sample execution:
- * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/category/cli/sync.php
+ * $ sudo -u www-data /usr/bin/php /var/www/moodle/enrol/category/cli/sync.php
  *
  * Notes:
  *   - it is required to use the web server account when executing PHP CLI scripts
  *   - you need to change the "www-data" to match the apache user account
  *   - use "su" if "sudo" not available
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -63,7 +61,7 @@ Example:
 
 
 if (!enrol_is_enabled('category')) {
-    cli_error('enrol_category plugin is disabled, synchronisation stopped');
+    cli_error('enrol_category plugin is disabled, synchronisation stopped', 2);
 }
 
 $verbose = !empty($options['verbose']);
diff --git a/enrol/category/db/access.php b/enrol/category/db/access.php
index 1a9ead0..7feea4d 100644
--- a/enrol/category/db/access.php
+++ b/enrol/category/db/access.php
@@ -25,9 +25,9 @@
 defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
-    // marks roles that have category role assignments synchronised to course enrolments
+    // Marks roles that have category role assignments synchronised to course enrolments
     // overrides below system context are ignored (for performance reasons).
-    // by default his is not allowed in new installs, admins have to explicitly allow category enrolments
+    // By default his is not allowed in new installs, admins have to explicitly allow category enrolments.
     'enrol/category:synchronised' => array(
         'captype' => 'write',
         'contextlevel' => CONTEXT_SYSTEM,
diff --git a/enrol/category/db/events.php b/enrol/category/db/events.php
index 66194df..3a67866 100644
--- a/enrol/category/db/events.php
+++ b/enrol/category/db/events.php
@@ -17,10 +17,10 @@
 /**
  * Category enrolment plugin event handler definition.
  *
- * @package enrol_category
- * @category event
+ * @package   enrol_category
+ * @category  event
  * @copyright 2010 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
diff --git a/enrol/category/db/install.php b/enrol/category/db/install.php
index 0de987f..834aa67 100644
--- a/enrol/category/db/install.php
+++ b/enrol/category/db/install.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -18,8 +17,7 @@
 /**
  * category enrolment plugin installation.
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/enrol/category/lang/en/enrol_category.php b/enrol/category/lang/en/enrol_category.php
index 5a8bee3..417b28d 100644
--- a/enrol/category/lang/en/enrol_category.php
+++ b/enrol/category/lang/en/enrol_category.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,10 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Strings for component 'enrol_category', language 'en', branch 'MOODLE_20_STABLE'
+ * Strings for component 'enrol_category', language 'en'.
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda  {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/enrol/category/lib.php b/enrol/category/lib.php
index ba60ba0..e6525e3 100644
--- a/enrol/category/lib.php
+++ b/enrol/category/lib.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -18,25 +17,25 @@
 /**
  * Category enrolment plugin.
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
+
 /**
  * category enrolment plugin implementation.
- * @author Petr Skoda
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author  Petr Skoda
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class enrol_category_plugin extends enrol_plugin {
 
    /**
      * Is it possible to delete enrol instance via standard UI?
      *
-     * @param object $instance
+     * @param stdClass $instance
      * @return bool
      */
     public function instance_deleteable($instance) {
@@ -45,7 +44,7 @@ class enrol_category_plugin extends enrol_plugin {
         if (!enrol_is_enabled('category')) {
             return true;
         }
-        // allow delete only when no synced users here
+        // Allow delete only when no synced users here.
         return !$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id));
     }
 
@@ -55,8 +54,8 @@ class enrol_category_plugin extends enrol_plugin {
      * @return moodle_url page url
      */
     public function get_newinstance_link($courseid) {
-        // instances are added automatically as necessary
-        return NULL;
+        // Instances are added automatically as necessary.
+        return null;
     }
 
     /**
@@ -78,8 +77,8 @@ class enrol_category_plugin extends enrol_plugin {
      * Called after updating/inserting course.
      *
      * @param bool $inserted true if course just inserted
-     * @param object $course
-     * @param object $data form data
+     * @param stdClass $course
+     * @param stdClass $data form data
      * @return void
      */
     public function course_updated($inserted, $course, $data) {
@@ -89,10 +88,8 @@ class enrol_category_plugin extends enrol_plugin {
             return;
         }
 
-        // sync category enrols
+        // Sync category enrols.
         require_once("$CFG->dirroot/enrol/category/locallib.php");
         enrol_category_sync_course($course);
     }
 }
-
-
diff --git a/enrol/category/locallib.php b/enrol/category/locallib.php
index 4cd7c5c..2c16f766 100644
--- a/enrol/category/locallib.php
+++ b/enrol/category/locallib.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -18,14 +17,14 @@
 /**
  * Local stuff for category enrolment plugin.
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
+
 /**
  * Event handler for category enrolment plugin.
  *
@@ -33,6 +32,12 @@ defined('MOODLE_INTERNAL') || die();
  * it may fail sometimes, so we always do a full sync in cron too.
  */
 class enrol_category_handler {
+    /**
+     * Triggered when user is assigned a new role.
+     * @static
+     * @param stdClass $ra
+     * @return bool
+     */
     public static function role_assigned($ra) {
         global $DB;
 
@@ -40,20 +45,20 @@ class enrol_category_handler {
             return true;
         }
 
-        //only category level roles are interesting
+        // Only category level roles are interesting.
         $parentcontext = get_context_instance_by_id($ra->contextid);
         if ($parentcontext->contextlevel != CONTEXT_COURSECAT) {
             return true;
         }
 
-        // make sure the role is to be actually synchronised
-        // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync)
-        $syscontext = get_context_instance(CONTEXT_SYSTEM);
+        // Make sure the role is to be actually synchronised,
+        // please note we are ignoring overrides of the synchronised capability (for performance reasons in full sync).
+        $syscontext = context_system::instance();
         if (!$DB->record_exists('role_capabilities', array('contextid'=>$syscontext->id, 'roleid'=>$ra->roleid, 'capability'=>'enrol/category:synchronised', 'permission'=>CAP_ALLOW))) {
             return true;
         }
 
-        // add necessary enrol instances
+        // Add necessary enrol instances.
         $plugin = enrol_get_plugin('category');
         $sql = "SELECT c.*
                   FROM {course} c
@@ -67,7 +72,7 @@ class enrol_category_handler {
         }
         $rs->close();
 
-        // now look for missing enrols
+        // Now look for missing enrolments.
         $sql = "SELECT e.*
                   FROM {course} c
                   JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :courselevel AND ctx.path LIKE :match)
@@ -84,6 +89,12 @@ class enrol_category_handler {
         return true;
     }
 
+    /**
+     * Triggered when user role is unassigned.
+     * @static
+     * @param stdClass $ra
+     * @return bool
+     */
     public static function role_unassigned($ra) {
         global $DB;
 
@@ -91,14 +102,14 @@ class enrol_category_handler {
             return true;
         }
 
-        // only category level roles are interesting
+        // Only category level roles are interesting.
         $parentcontext = get_context_instance_by_id($ra->contextid);
         if ($parentcontext->contextlevel != CONTEXT_COURSECAT) {
             return true;
         }
 
-        // now this is going to be a bit slow, take all enrolments in child courses and verify each separately
-        $syscontext = get_context_instance(CONTEXT_SYSTEM);
+        // Now this is going to be a bit slow, take all enrolments in child courses and verify each separately.
+        $syscontext = context_system::instance();
         if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
             return true;
         }
@@ -117,9 +128,9 @@ class enrol_category_handler {
         $params['userid'] = $ra->userid;
 
         foreach ($rs as $instance) {
-            $coursecontext = get_context_instance(CONTEXT_COURSE, $instance->courseid);
+            $coursecontext = context_course::instance($instance->courseid);
             $contextids = get_parent_contexts($coursecontext);
-            array_pop($contextids); // remove system context, we are interested in categories only
+            array_pop($contextids); // Remove system context, we are interested in categories only.
 
             list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');
             $params = array_merge($params, $contextparams);
@@ -128,7 +139,7 @@ class enrol_category_handler {
                       FROM {role_assignments} ra
                      WHERE ra.userid = :userid AND ra.contextid $contextids AND ra.roleid $roleids";
             if (!$DB->record_exists_sql($sql, $params)) {
-                // user does not have any interesting role in any parent context, let's unenrol
+                // User does not have any interesting role in any parent context, let's unenrol.
                 $plugin->unenrol_user($instance, $ra->userid);
             }
         }
@@ -140,7 +151,7 @@ class enrol_category_handler {
 
 /**
  * Sync all category enrolments in one course
- * @param int $courseid course id
+ * @param stdClass $course
  * @return void
  */
 function enrol_category_sync_course($course) {
@@ -152,11 +163,11 @@ function enrol_category_sync_course($course) {
 
     $plugin = enrol_get_plugin('category');
 
-    $syscontext = get_context_instance(CONTEXT_SYSTEM);
+    $syscontext = context_system::instance();
     $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
 
     if (!$roles) {
-        //nothing to sync, so remove the instance completely if exists
+        // Nothing to sync, so remove the instance completely if exists.
         if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
             foreach ($instances as $instance) {
                 $plugin->delete_instance($instance);
@@ -165,10 +176,10 @@ function enrol_category_sync_course($course) {
         return;
     }
 
-    // first find out if any parent category context contains interesting role assignments
-    $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
+    // First find out if any parent category context contains interesting role assignments.
+    $coursecontext = context_course::instance($course->id);
     $contextids = get_parent_contexts($coursecontext);
-    array_pop($contextids); // remove system context, we are interested in categories only
+    array_pop($contextids); // Remove system context, we are interested in categories only.
 
     list($roleids, $params) = $DB->get_in_or_equal(array_keys($roles), SQL_PARAMS_NAMED, 'r');
     list($contextids, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'c');
@@ -180,7 +191,7 @@ function enrol_category_sync_course($course) {
              WHERE roleid $roleids AND contextid $contextids";
     if (!$DB->record_exists_sql($sql, $params)) {
         if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
-            // should be max one instance, but anyway
+            // Should be max one instance, but anyway.
             foreach ($instances as $instance) {
                 $plugin->delete_instance($instance);
             }
@@ -188,7 +199,7 @@ function enrol_category_sync_course($course) {
         return;
     }
 
-    // make sure the enrol instance exists - there should be always only one instance
+    // Make sure the enrol instance exists - there should be always only one instance.
     $delinstances = array();
     if ($instances = $DB->get_records('enrol', array('courseid'=>$course->id, 'enrol'=>'category'))) {
         $instance = array_shift($instances);
@@ -198,7 +209,7 @@ function enrol_category_sync_course($course) {
         $instance = $DB->get_record('enrol', array('id'=>$i));
     }
 
-    // add new enrolments
+    // Add new enrolments.
     $sql = "SELECT ra.userid, ra.estart
               FROM (SELECT xra.userid, MIN(xra.timemodified) AS estart
                       FROM {role_assignments} xra
@@ -214,7 +225,7 @@ function enrol_category_sync_course($course) {
     }
     $rs->close();
 
-    // remove unwanted enrolments
+    // Remove unwanted enrolments.
     $sql = "SELECT DISTINCT ue.userid
               FROM {user_enrolments} ue
          LEFT JOIN {role_assignments} ra ON (ra.roleid $roleids AND ra.contextid $contextids AND ra.userid = ue.userid)
@@ -226,13 +237,24 @@ function enrol_category_sync_course($course) {
     $rs->close();
 
     if ($delinstances) {
-        // we have to do this as the last step in order to prevent temporary unenrolment
+        // We have to do this as the last step in order to prevent temporary unenrolment.
         foreach ($delinstances as $delinstance) {
             $plugin->delete_instance($delinstance);
         }
     }
 }
 
+/**
+ * Synchronise courses in all categories.
+ *
+ * It gets out-of-sync if:
+ * - you move course to different category
+ * - reorder categories
+ * - disable enrol_category and enable it again
+ *
+ * @param bool $verbose
+ * @return int exit code - 0 is ok, 1 means error, 2 if plugin disabled
+ */
 function enrol_category_sync_full($verbose = false) {
     global $DB;
 
@@ -241,14 +263,14 @@ function enrol_category_sync_full($verbose = false) {
         return 2;
     }
 
-    // we may need a lot of time here
+    // We may need a lot of time here.
     @set_time_limit(0);
 
     $plugin = enrol_get_plugin('category');
 
-    $syscontext = get_context_instance(CONTEXT_SYSTEM);
+    $syscontext = context_system::instance();
 
-    // any interesting roles worth synchronising?
+    // Any interesting roles worth synchronising?
     if (!$roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext)) {
         // yay, nothing to do, so let's remove all leftovers
         if ($verbose) {
@@ -273,10 +295,10 @@ function enrol_category_sync_full($verbose = false) {
     $params['courselevel'] = CONTEXT_COURSE;
     $params['catlevel'] = CONTEXT_COURSECAT;
 
-    // first of all add necessary enrol instances to all courses
+    // First of all add necessary enrol instances to all courses.
     $parentcat = $DB->sql_concat("cat.path", "'/%'");
     $parentcctx = $DB->sql_concat("cctx.path", "'/%'");
-    // need whole course records to be used by add_instance(), use inner view (ci) to
+    // Need whole course records to be used by add_instance(), use inner view (ci) to
     // get distinct records only.
     // TODO: Moodle 2.1. Improve enrol API to accept courseid / courserec
     $sql = "SELECT c.*
@@ -299,8 +321,8 @@ function enrol_category_sync_full($verbose = false) {
     }
     $rs->close();
 
-    // now look for courses that do not have any interesting roles in parent contexts,
-    // but still have the instance and delete them
+    // Now look for courses that do not have any interesting roles in parent contexts,
+    // but still have the instance and delete them.
     $sql = "SELECT e.*
               FROM {enrol} e
               JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
@@ -316,7 +338,7 @@ function enrol_category_sync_full($verbose = false) {
     }
     $rs->close();
 
-    // add missing enrolments
+    // Add missing enrolments.
     $sql = "SELECT e.*, cat.userid, cat.estart
               FROM {enrol} e
               JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
@@ -341,7 +363,7 @@ function enrol_category_sync_full($verbose = false) {
     }
     $rs->close();
 
-    // remove stale enrolments
+    // Remove stale enrolments.
     $sql = "SELECT e.*, ue.userid
               FROM {enrol} e
               JOIN {context} ctx ON (ctx.instanceid = e.courseid AND ctx.contextlevel = :courselevel)
diff --git a/enrol/category/settings.php b/enrol/category/settings.php
index a854267..484c23b 100644
--- a/enrol/category/settings.php
+++ b/enrol/category/settings.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,10 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * category enrolment plugin settings and presets.
+ * Category enrolment plugin settings and presets.
  *
- * @package    enrol
- * @subpackage category
+ * @package    enrol_category
  * @copyright  2010 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -35,4 +33,3 @@ if ($ADMIN->fulltree) {
     //--- enrol instance defaults ----------------------------------------------------------------------------
 
 }
-
-- 
1.7.9.5


From 3c50224079d07efc04d20423a8d9cc0029e0049b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 15 Aug 2012 11:43:27 +0200
Subject: [PATCH 434/903] MDL-34864 add enrol_category unit tests for sync

---
 enrol/category/tests/sync_test.php |  365 ++++++++++++++++++++++++++++++++++++
 1 file changed, 365 insertions(+)
 create mode 100644 enrol/category/tests/sync_test.php

diff --git a/enrol/category/tests/sync_test.php b/enrol/category/tests/sync_test.php
new file mode 100644
index 0000000..3649764
--- /dev/null
+++ b/enrol/category/tests/sync_test.php
@@ -0,0 +1,365 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Category enrolment sync functional test.
+ *
+ * @package    enrol_category
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot.'/enrol/category/locallib.php');
+
+class enrol_category_testcase extends advanced_testcase {
+
+    protected function enable_plugin() {
+        $enabled = enrol_get_plugins(true);
+        $enabled['category'] = true;
+        $enabled = array_keys($enabled);
+        set_config('enrol_plugins_enabled', implode(',', $enabled));
+    }
+
+    protected function disable_plugin() {
+        $enabled = enrol_get_plugins(true);
+        unset($enabled['category']);
+        $enabled = array_keys($enabled);
+        set_config('enrol_plugins_enabled', implode(',', $enabled));
+    }
+
+    protected function enable_role_sync($roleid) {
+        global $DB;
+
+        $syscontext = context_system::instance();
+
+        if ($rc = $DB->record_exists('role_capabilities', array('capability'=>'enrol/category:synchronised', 'roleid'=>$roleid, 'contextid'=>$syscontext->id))) {
+            if ($rc->permission != CAP_ALLOW) {
+                $rc->permission = CAP_ALLOW;
+                $DB->update_record('role_capabilities', $rc);
+            }
+        } else {
+            $rc = new stdClass();
+            $rc->capability = 'enrol/category:synchronised';
+            $rc->roleid = $roleid;
+            $rc->contextid = $syscontext->id;
+            $rc->permission = CAP_ALLOW;
+            $rc->timemodified = time();
+            $rc->modifierid = 0;
+            $DB->insert_record('role_capabilities', $rc);
+        }
+    }
+
+    protected function disable_role_sync($roleid) {
+        global $DB;
+
+        $syscontext = context_system::instance();
+
+        $DB->delete_records('role_capabilities', array('capability'=>'enrol/category:synchronised', 'roleid'=>$roleid, 'contextid'=>$syscontext->id));
+    }
+
+    /**
+     * Test utility methods used in syn test, fail here means something
+     * in core accesslib was changed, but it is possible that only this test
+     * is affected, nto the plugin itself...
+     */
+    public function test_utils() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        $syscontext = context_system::instance();
+
+        $this->assertFalse(enrol_is_enabled('category'));
+        $this->enable_plugin();
+        $this->assertTrue(enrol_is_enabled('category'));
+
+        $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+        $this->assertEmpty($roles);
+
+        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+        $this->assertNotEmpty($studentrole);
+
+        $this->enable_role_sync($studentrole->id);
+        $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+        $this->assertEquals(1, count($roles));
+        $this->assertEquals($studentrole, reset($roles));
+
+        $this->disable_role_sync($studentrole->id);
+        $roles = get_roles_with_capability('enrol/category:synchronised', CAP_ALLOW, $syscontext);
+        $this->assertEmpty($roles);
+    }
+
+    public function test_handler_sync() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        // Setup a few courses and categories.
+
+        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+        $this->assertNotEmpty($studentrole);
+        $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+        $this->assertNotEmpty($teacherrole);
+        $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+        $this->assertNotEmpty($managerrole);
+
+        $cat1 = $this->getDataGenerator()->create_category();
+        $cat2 = $this->getDataGenerator()->create_category();
+        $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+        $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+        $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+        $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+        $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $user4 = $this->getDataGenerator()->create_user();
+
+        $this->enable_role_sync($studentrole->id);
+        $this->enable_role_sync($teacherrole->id);
+        $this->enable_plugin();
+
+        $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+        // Test assign event.
+
+        role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+        role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+        role_assign($managerrole->id, $user2->id, context_coursecat::instance($cat3->id));
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+        role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+        $this->assertEquals(4, $DB->count_records('user_enrolments', array()));
+
+        // Test role unassigned event.
+
+        role_unassign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id)->id);
+        $this->assertFalse(is_enrolled(context_course::instance($course1->id), $user4->id));
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+        // Make sure handlers are disabled when plugin disabled.
+
+        $this->disable_plugin();
+        role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+        role_assign($studentrole->id, $user3->id, context_coursecat::instance($cat1->id));
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+    }
+
+    public function test_sync_course() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        // Setup a few courses and categories.
+
+        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+        $this->assertNotEmpty($studentrole);
+        $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+        $this->assertNotEmpty($teacherrole);
+        $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+        $this->assertNotEmpty($managerrole);
+
+        $cat1 = $this->getDataGenerator()->create_category();
+        $cat2 = $this->getDataGenerator()->create_category();
+        $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+        $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+        $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+        $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+        $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $user4 = $this->getDataGenerator()->create_user();
+
+        $this->enable_role_sync($studentrole->id);
+        $this->enable_role_sync($teacherrole->id);
+        $this->enable_plugin();
+
+        $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+        role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+
+        $this->disable_plugin(); // Stops the event handlers.
+        role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+        $this->enable_plugin();
+        enrol_category_sync_course($course2);
+        $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+        $this->assertFalse(is_enrolled(context_course::instance($course3->id), $user1->id));
+        $this->assertFalse(is_enrolled(context_course::instance($course4->id), $user1->id));
+        $this->assertEquals(1, $DB->count_records('user_enrolments', array()));
+
+        enrol_category_sync_course($course2);
+        enrol_category_sync_course($course3);
+        enrol_category_sync_course($course4);
+        $this->assertFalse(is_enrolled(context_course::instance($course1->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+
+        $this->disable_plugin(); // Stops the event handlers.
+        role_assign($studentrole->id, $user2->id, context_coursecat::instance($cat1->id));
+        role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+        role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+        $this->enable_plugin();
+        enrol_category_sync_course($course2);
+        $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user1->id));
+        $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user2->id));
+        $this->assertFalse(is_enrolled(context_course::instance($course2->id), $user4->id));
+        enrol_category_sync_course($course1);
+        enrol_category_sync_course($course3);
+        enrol_category_sync_course($course4);
+        $this->assertEquals(2, $DB->count_records('user_enrolments', array()));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user2->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+
+        $this->disable_role_sync($studentrole->id);
+        enrol_category_sync_course($course1);
+        enrol_category_sync_course($course2);
+        enrol_category_sync_course($course3);
+        enrol_category_sync_course($course4);
+        $this->assertEquals(1, $DB->count_records('user_enrolments', array()));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+
+        $this->assertEquals(1, $DB->count_records('enrol', array('enrol'=>'category')));
+        $this->disable_role_sync($teacherrole->id);
+        enrol_category_sync_course($course1);
+        enrol_category_sync_course($course2);
+        enrol_category_sync_course($course3);
+        enrol_category_sync_course($course4);
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+        $this->assertEquals(0, $DB->count_records('enrol', array('enrol'=>'category')));
+    }
+
+    public function test_sync_full() {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        // Setup a few courses and categories.
+
+        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
+        $this->assertNotEmpty($studentrole);
+        $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
+        $this->assertNotEmpty($teacherrole);
+        $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
+        $this->assertNotEmpty($managerrole);
+
+        $cat1 = $this->getDataGenerator()->create_category();
+        $cat2 = $this->getDataGenerator()->create_category();
+        $cat3 = $this->getDataGenerator()->create_category(array('parent'=>$cat2->id));
+
+        $course1 = $this->getDataGenerator()->create_course(array('category'=>$cat1->id));
+        $course2 = $this->getDataGenerator()->create_course(array('category'=>$cat2->id));
+        $course3 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+        $course4 = $this->getDataGenerator()->create_course(array('category'=>$cat3->id));
+
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $user4 = $this->getDataGenerator()->create_user();
+
+        $this->enable_role_sync($studentrole->id);
+        $this->enable_role_sync($teacherrole->id);
+        $this->enable_plugin();
+
+        $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+        role_assign($managerrole->id, $user1->id, context_coursecat::instance($cat1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course1->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course2->id));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+
+        $result = enrol_category_sync_full();
+        $this->assertSame(0, $result);
+
+        $this->disable_plugin();
+        role_assign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id));
+        $this->enable_plugin();
+        $result = enrol_category_sync_full();
+        $this->assertSame(0, $result);
+        $this->assertEquals(3, $DB->count_records('user_enrolments', array()));
+        $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user1->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user1->id));
+
+        $this->disable_plugin();
+        role_unassign($studentrole->id, $user1->id, context_coursecat::instance($cat2->id)->id);
+        role_assign($studentrole->id, $user2->id, context_coursecat::instance($cat1->id));
+        role_assign($teacherrole->id, $user4->id, context_coursecat::instance($cat1->id));
+        role_assign($teacherrole->id, $user3->id, context_coursecat::instance($cat2->id));
+        role_assign($managerrole->id, $user3->id, context_course::instance($course3->id));
+        $this->enable_plugin();
+        $result = enrol_category_sync_full();
+        $this->assertSame(0, $result);
+        $this->assertEquals(5, $DB->count_records('user_enrolments', array()));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user2->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course1->id), $user4->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course2->id), $user3->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course3->id), $user3->id));
+        $this->assertTrue(is_enrolled(context_course::instance($course4->id), $user3->id));
+
+        // Cleanup everything.
+
+        $this->assertNotEmpty($DB->count_records('role_assignments', array()));
+        $this->assertNotEmpty($DB->count_records('user_enrolments', array()));
+
+        $this->disable_plugin();
+        role_unassign_all(array('roleid'=>$studentrole->id));
+        role_unassign_all(array('roleid'=>$managerrole->id));
+        role_unassign_all(array('roleid'=>$teacherrole->id));
+
+        $result = enrol_category_sync_full();
+        $this->assertSame(2, $result);
+        $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+        $this->assertNotEmpty($DB->count_records('user_enrolments', array()));
+        $this->disable_role_sync($studentrole->id);
+        $this->disable_role_sync($teacherrole->id);
+
+        $this->enable_plugin();
+        $result = enrol_category_sync_full();
+        $this->assertSame(0, $result);
+        $this->assertEquals(0, $DB->count_records('role_assignments', array()));
+        $this->assertEquals(0, $DB->count_records('user_enrolments', array()));
+        $this->assertEquals(0, $DB->count_records('enrol', array('enrol'=>'category')));
+    }
+}
-- 
1.7.9.5


From 245197ee2db61601c138b944f8d29e563f0b0e6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 18 Aug 2012 11:39:03 +0200
Subject: [PATCH 435/903] MDL-34864 bump up enrol category sync version

---
 enrol/category/version.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/enrol/category/version.php b/enrol/category/version.php
index 371a7f0..23c33cf 100644
--- a/enrol/category/version.php
+++ b/enrol/category/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012061700;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2012061700;        // Requires this Moodle version
+$plugin->version   = 2012081800;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2012062501;        // Requires this Moodle version
 $plugin->component = 'enrol_category';  // Full name of the plugin (used for diagnostics)
-$plugin->cron      = 60;
\ No newline at end of file
+$plugin->cron      = 60;
-- 
1.7.9.5


From 9fe39511e22445d41341614e72d4143a14193033 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sun, 19 Aug 2012 00:31:36 +0000
Subject: [PATCH 436/903] Automatically generated installer lang files

---
 install/lang/es_mx/langconfig.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/es_mx/langconfig.php b/install/lang/es_mx/langconfig.php
index 1dfd27c..f7c639b 100644
--- a/install/lang/es_mx/langconfig.php
+++ b/install/lang/es_mx/langconfig.php
@@ -30,6 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['parentlanguage'] = 'es';
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Español - Mexico';
-- 
1.7.9.5


From c74b1ee8d98aabfa9a44d3a4f32882ea2c46c1d7 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 19 Aug 2012 01:34:15 +0100
Subject: [PATCH 437/903] MDL-34957 theme_base: made small change to
 custommenu CSS in style/core.css to fix vertical
 arrow overlap in menu item

---
 theme/base/style/core.css |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index a91000e..9661206 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -508,7 +508,7 @@ body.tag .managelink {padding: 5px;}
 #custommenu .yui3-menu-horizontal .yui3-menu-label,
 #custommenu .yui3-menu-horizontal .yui3-menu-content {background-image:none;background-position:right center;background-repeat:no-repeat;}
 #custommenu .yui3-menu-label,
-#custommenu .yui3-menu .yui3-menu .yui3-menu-label {background-image:url([[pix:theme|vertical-menu-submenu-indicator]]);}
+#custommenu .yui3-menu .yui3-menu .yui3-menu-label {background-image:url([[pix:theme|vertical-menu-submenu-indicator]]); padding-right: 20px;}
 #custommenu .yui3-menu .yui3-menu .yui3-menu-label-menuvisible {background-image:url([[pix:theme|horizontal-menu-submenu-indicator]]);}
 
 /**
-- 
1.7.9.5


From 123f7f534eec52327813cf2166c408b09d692eb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 19 Aug 2012 10:17:12 +0200
Subject: [PATCH 438/903] MDL-34873 fix multiple E_STRICT tag related problems

---
 blocks/tags/block_tags.php |    1 +
 tag/edit.php               |    3 ++-
 tag/lib.php                |    6 ++++--
 tag/locallib.php           |    3 ++-
 4 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/blocks/tags/block_tags.php b/blocks/tags/block_tags.php
index 7ce4a4a..6183a9b 100644
--- a/blocks/tags/block_tags.php
+++ b/blocks/tags/block_tags.php
@@ -40,6 +40,7 @@ class block_tags extends block_base {
         global $CFG, $COURSE, $SITE, $USER, $SCRIPT, $OUTPUT;
 
         if (empty($CFG->usetags)) {
+            $this->content = new stdClass();
             $this->content->text = '';
             if ($this->page->user_is_editing()) {
                 $this->content->text = get_string('disabledtags', 'block_tags');
diff --git a/tag/edit.php b/tag/edit.php
index b71c72f..ee17bc0 100644
--- a/tag/edit.php
+++ b/tag/edit.php
@@ -111,7 +111,8 @@ if ($tagnew = $tagform->get_data()) {
         unset($tagnew->rawname);
 
     } else {  // They might be trying to change the rawname, make sure it's a change that doesn't affect name
-        $tagnew->name = array_shift(tag_normalize($tagnew->rawname, TAG_CASE_LOWER));
+        $norm = tag_normalize($tagnew->rawname, TAG_CASE_LOWER);
+        $tagnew->name = array_shift($norm);
 
         if ($tag->name != $tagnew->name) {  // The name has changed, let's make sure it's not another existing tag
             if (tag_get_id($tagnew->name)) {   // Something exists already, so flag an error
diff --git a/tag/lib.php b/tag/lib.php
index cdbe37f..8e6b397 100644
--- a/tag/lib.php
+++ b/tag/lib.php
@@ -558,7 +558,8 @@ function tag_get_related_tags_csv($related_tags, $html=TAG_RETURN_HTML) {
 function tag_rename($tagid, $newrawname) {
     global $DB;
 
-    if (! $newrawname_clean = array_shift(tag_normalize($newrawname, TAG_CASE_ORIGINAL)) ) {
+    $norm = tag_normalize($newrawname, TAG_CASE_ORIGINAL);
+    if (! $newrawname_clean = array_shift($norm) ) {
         return false;
     }
 
@@ -1020,7 +1021,8 @@ function tag_cron() {
 function tag_find_tags($text, $ordered=true, $limitfrom='', $limitnum='') {
     global $DB;
 
-    $text = array_shift(tag_normalize($text, TAG_CASE_LOWER));
+    $norm = tag_normalize($text, TAG_CASE_LOWER);
+    $text = array_shift($norm);
 
     if ($ordered) {
         $query = "SELECT tg.id, tg.name, tg.rawname, COUNT(ti.id) AS count
diff --git a/tag/locallib.php b/tag/locallib.php
index fb7f9a9..589b6dc 100644
--- a/tag/locallib.php
+++ b/tag/locallib.php
@@ -261,7 +261,8 @@ function tag_print_search_results($query,  $page, $perpage, $return=false) {
 
     global $CFG, $USER, $OUTPUT;
 
-    $query = array_shift(tag_normalize($query, TAG_CASE_ORIGINAL));
+    $norm = tag_normalize($query, TAG_CASE_ORIGINAL);
+    $query = array_shift($norm);
 
     $count = sizeof(tag_find_tags($query, false));
     $tags = array();
-- 
1.7.9.5


From cf1cb686624c80f987540a51be2bcc57da20c930 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 19 Aug 2012 13:11:15 +0200
Subject: [PATCH 439/903] MDL-34901 fix user login times handling

---
 auth/email/auth.php  |    4 +++-
 auth/ldap/auth.php   |    4 +++-
 auth/manual/auth.php |    4 +++-
 lib/moodlelib.php    |   21 +++++++++++++++------
 4 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/auth/email/auth.php b/auth/email/auth.php
index 0051aaf..e50c09e 100644
--- a/auth/email/auth.php
+++ b/auth/email/auth.php
@@ -132,7 +132,9 @@ class auth_plugin_email extends auth_plugin_base {
 
             } else if ($user->secret == $confirmsecret) {   // They have provided the secret key to get in
                 $DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
-                $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else {
diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php
index bc90ebc..88bb10d 100644
--- a/auth/ldap/auth.php
+++ b/auth/ldap/auth.php
@@ -546,7 +546,9 @@ class auth_plugin_ldap extends auth_plugin_base {
                     return AUTH_CONFIRM_FAIL;
                 }
                 $DB->set_field('user', 'confirmed', 1, array('id'=>$user->id));
-                $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else {
diff --git a/auth/manual/auth.php b/auth/manual/auth.php
index e3df78a..29cb59a 100644
--- a/auth/manual/auth.php
+++ b/auth/manual/auth.php
@@ -170,7 +170,9 @@ class auth_plugin_manual extends auth_plugin_base {
                 return AUTH_CONFIRM_ALREADY;
             } else {
                 $DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
-                $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else  {
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index f229b6b..104da29 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -3283,11 +3283,24 @@ function get_user_key($script, $userid, $instance=null, $iprestriction=null, $va
 function update_user_login_times() {
     global $USER, $DB;
 
+    $now = time();
+
     $user = new stdClass();
+    $user->id = $USER->id;
+
+    // Make sure all users that logged in have some firstaccess.
+    if ($USER->firstaccess == 0) {
+        $USER->firstaccess = $user->firstaccess = $now;
+    }
+
+    // Store the previous current as lastlogin.
     $USER->lastlogin = $user->lastlogin = $USER->currentlogin;
-    $USER->currentlogin = $user->lastaccess = $user->currentlogin = time();
 
-    $user->id = $USER->id;
+    $USER->currentlogin = $user->currentlogin = $now;
+
+    // Function user_accesstime_log() may not update immediately, better do it here.
+    $USER->lastaccess = $user->lastaccess = $now;
+    $USER->lastip = $user->lastip = getremoteaddr();
 
     $DB->update_record('user', $user);
     return true;
@@ -4074,10 +4087,6 @@ function authenticate_user_login($username, $password) {
                 $DB->set_field('user', 'auth', $auth, array('username'=>$username));
                 $user->auth = $auth;
             }
-            if (empty($user->firstaccess)) { //prevent firstaccess from remaining 0 for manual account that never required confirmation
-                $DB->set_field('user','firstaccess', $user->timemodified, array('id' => $user->id));
-                $user->firstaccess = $user->timemodified;
-            }
 
             update_internal_user_password($user, $password); // just in case salt or encoding were changed (magic quotes too one day)
 
-- 
1.7.9.5


From 1ff3389a54c3af5eba4d99560010b5df62a30c0c Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Wed, 15 Aug 2012 15:33:22 +0200
Subject: [PATCH 440/903] MDL-34808 qformat examview Add phpunit tests to
 examview import format

---
 question/format/examview/format.php                |  103 +++--
 .../format/examview/lang/en/qformat_examview.php   |    3 +-
 .../format/examview/tests/examviewformat_test.php  |  465 ++++++++++++++++++++
 question/format/examview/version.php               |    3 +-
 4 files changed, 531 insertions(+), 43 deletions(-)
 create mode 100644 question/format/examview/tests/examviewformat_test.php

diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index f1acd34..7cea482 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -17,8 +17,7 @@
 /**
  * Examview question importer.
  *
- * @package    qformat
- * @subpackage examview
+ * @package    qformat_examview
  * @copyright  2005 Howard Miller
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -35,7 +34,7 @@ require_once($CFG->libdir . '/xmlize.php');
  * @copyright  2005 Howard Miller
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class qformat_examview extends qformat_default {
+class qformat_examview extends qformat_based_on_xml {
 
     public $qtypes = array(
         'tf' => TRUEFALSE,
@@ -49,8 +48,8 @@ class qformat_examview extends qformat_default {
         'es' => ESSAY,
         'ca' => 99,
         'ot' => 99,
-        'sa' => SHORTANSWER
-        );
+        'sa' => SHORTANSWER,
+    );
 
     public $matching_questions = array();
 
@@ -63,6 +62,28 @@ class qformat_examview extends qformat_default {
     }
 
     /**
+     * Some softwares put entities in exported files.
+     * This method try to clean up known problems.
+     * @param string str string to correct
+     * @return string the corrected string
+     */
+    public function cleaninput($str) {
+
+        $html_code_list = array(
+            "&#039;" => "'",
+            "&#8217;" => "'",
+            "&#8220;" => "\"",
+            "&#8221;" => "\"",
+            "&#8211;" => "-",
+            "&#8212;" => "-",
+        );
+        $str = strtr($str, $html_code_list);
+        // Use textlib entities_to_utf8 function to convert only numerical entities.
+        $str = textlib::entities_to_utf8( $str, false);
+        return $str;
+    }
+
+    /**
      * unxmlise reconstructs part of the xml data structure in order
      * to identify the actual data therein
      * @param array $xml section of the xml data structure
@@ -87,13 +108,6 @@ class qformat_examview extends qformat_default {
         $text = strip_tags($text);
         return $text;
     }
-    protected function text_field($text) {
-        return array(
-            'text' => htmlspecialchars(trim($text), ENT_NOQUOTES),
-            'format' => FORMAT_HTML,
-            'files' => array(),
-        );
-    }
 
     protected function add_blank_combined_feedback($question) {
         $question->correctfeedback['text'] = '';
@@ -108,7 +122,7 @@ class qformat_examview extends qformat_default {
         return $question;
     }
 
-    protected function parse_matching_groups($matching_groups) {
+    public function parse_matching_groups($matching_groups) {
         if (empty($matching_groups)) {
             return;
         }
@@ -136,8 +150,7 @@ class qformat_examview extends qformat_default {
         $phrase = trim($this->unxmlise($qrec['text']['0']['#']));
         $answer = trim($this->unxmlise($qrec['answer']['0']['#']));
         $answer = strip_tags( $answer );
-        $match_group->subquestions[] = $phrase;
-        $match_group->subanswers[] = $match_group->subchoices[$answer];
+        $match_group->mappings[$phrase] = $match_group->subchoices[$answer];
         $this->matching_questions[$groupname] = $match_group;
         return null;
     }
@@ -146,6 +159,7 @@ class qformat_examview extends qformat_default {
         if (empty($this->matching_questions)) {
             return;
         }
+
         foreach ($this->matching_questions as $match_group) {
             $question = $this->defaultquestion();
             $htmltext = s($match_group->questiontext);
@@ -157,12 +171,17 @@ class qformat_examview extends qformat_default {
             $question = $this->add_blank_combined_feedback($question);
             $question->subquestions = array();
             $question->subanswers = array();
-            foreach ($match_group->subquestions as $key => $value) {
-                $htmltext = s($value);
-                $question->subquestions[] = $this->text_field($htmltext);
-
-                $htmltext = s($match_group->subanswers[$key]);
-                $question->subanswers[] = $htmltext;
+            foreach ($match_group->subchoices as $subchoice) {
+                $fiber = array_keys ($match_group->mappings, $subchoice);
+                $subquestion = '';
+                foreach ($fiber as $subquestion) {
+                    $question->subquestions[] = $this->text_field($subquestion);
+                    $question->subanswers[] = $subchoice;
+                }
+                if ($subquestion == '') { // Then in this case, $subchoice is a distractor.
+                    $question->subquestions[] = $this->text_field('');
+                    $question->subanswers[] = $subchoice;
+                }
             }
             $questions[] = $question;
         }
@@ -172,7 +191,7 @@ class qformat_examview extends qformat_default {
         return str_replace('&#x2019;', "'", $text);
     }
 
-    protected function readquestions($lines) {
+    public function readquestions($lines) {
         // Parses an array of lines into an array of questions,
         // where each item is a question object as defined by
         // readquestion().
@@ -209,9 +228,11 @@ class qformat_examview extends qformat_default {
             $question->qtype = null;
         }
         $question->single = 1;
+
         // Only one answer is allowed.
         $htmltext = $this->unxmlise($qrec['#']['text'][0]['#']);
-        $question->questiontext = $htmltext;
+
+        $question->questiontext = $this->cleaninput($htmltext);
         $question->questiontextformat = FORMAT_HTML;
         $question->questiontextfiles = array();
         $question->name = shorten_text( $question->questiontext, 250 );
@@ -251,11 +272,11 @@ class qformat_examview extends qformat_default {
         $question->answer = $choices[$answer];
         $question->correctanswer = $question->answer;
         if ($question->answer == 1) {
-            $question->feedbacktrue = $this->text_field('Correct');
-            $question->feedbackfalse = $this->text_field('Incorrect');
+            $question->feedbacktrue = $this->text_field(get_string('correct', 'question'));
+            $question->feedbackfalse = $this->text_field(get_string('incorrect', 'question'));
         } else {
-            $question->feedbacktrue = $this->text_field('Incorrect');
-            $question->feedbackfalse = $this->text_field('Correct');
+            $question->feedbacktrue = $this->text_field(get_string('incorrect', 'question'));
+            $question->feedbackfalse = $this->text_field(get_string('correct', 'question'));
         }
         return $question;
     }
@@ -268,13 +289,13 @@ class qformat_examview extends qformat_default {
         foreach ($choices as $key => $value) {
             if (strpos(trim($key), 'choice-') !== false) {
 
-                $question->answer[$key] = $this->text_field(s($this->unxmlise($value[0]['#'])));
+                $question->answer[] = $this->text_field(s($this->unxmlise($value[0]['#'])));
                 if (strcmp($key, $answer) == 0) {
-                    $question->fraction[$key] = 1;
-                    $question->feedback[$key] = $this->text_field('Correct');
+                    $question->fraction[] = 1;
+                    $question->feedback[] = $this->text_field(get_string('correct', 'question'));
                 } else {
-                    $question->fraction[$key] = 0;
-                    $question->feedback[$key] = $this->text_field('Incorrect');
+                    $question->fraction[] = 0;
+                    $question->feedback[] = $this->text_field(get_string('incorrect', 'question'));
                 }
             }
         }
@@ -290,11 +311,15 @@ class qformat_examview extends qformat_default {
         foreach ($answers as $key => $value) {
             $value = trim($value);
             if (strlen($value) > 0) {
-                $question->answer[$key] = $value;
-                $question->fraction[$key] = 1;
-                $question->feedback[$key] = $this->text_field("Correct");
+                $question->answer[] = $value;
+                $question->fraction[] = 1;
+                $question->feedback[] = $this->text_field(get_string('correct', 'question'));
             }
         }
+        $question->answer[] = '*';
+        $question->fraction[] = 0;
+        $question->feedback[] = $this->text_field(get_string('incorrect', 'question'));
+
         return $question;
     }
 
@@ -318,10 +343,10 @@ class qformat_examview extends qformat_default {
             $value = trim($value);
             if (is_numeric($value)) {
                 $errormargin = 0;
-                $question->answer[$key] = $value;
-                $question->fraction[$key] = 1;
-                $question->feedback[$key] = $this->text_field("Correct");
-                $question->tolerance[$key] = $errormargin;
+                $question->answer[] = $value;
+                $question->fraction[] = 1;
+                $question->feedback[] = $this->text_field(get_string('correct', 'question'));
+                $question->tolerance[] = $errormargin;
             }
         }
         return $question;
diff --git a/question/format/examview/lang/en/qformat_examview.php b/question/format/examview/lang/en/qformat_examview.php
index 970778f..ce51ff1 100644
--- a/question/format/examview/lang/en/qformat_examview.php
+++ b/question/format/examview/lang/en/qformat_examview.php
@@ -17,8 +17,7 @@
 /**
  * Strings for component 'qformat_examview', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    qformat
- * @subpackage examview
+ * @package    qformat_examview
  * @copyright  2010 Helen Foster
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/question/format/examview/tests/examviewformat_test.php b/question/format/examview/tests/examviewformat_test.php
new file mode 100644
index 0000000..6434ba8
--- /dev/null
+++ b/question/format/examview/tests/examviewformat_test.php
@@ -0,0 +1,465 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the Moodle Examview format.
+ *
+ * @package    qformat_examview
+ * @copyright  2012 jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/examview/format.php');
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the examview question import format.
+ *
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_examview_test extends question_testcase {
+
+    public function make_test_xml() {
+        $xml = "<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<examview type='test' platform='Windows' app-version='4.0.2'>
+    <header>
+        <title>Moodle Example</title>
+        <version>A</version>
+    </header>
+    <font-table>
+        <font-entry number='1'>
+            <charset>ansi</charset>
+            <name>Times New Roman</name>
+            <pitch>variable</pitch>
+            <family>roman</family>
+        </font-entry>
+    </font-table>
+    <preferences>
+        <show>
+            <show-answer value='yes'/>
+            <show-difficulty value='yes'/>
+            <show-reference value='yes'/>
+            <show-text-objective value='yes'/>
+            <show-state-objective value='yes'/>
+            <show-topic value='yes'/>
+            <show-keywords value='yes'/>
+            <show-misc value='yes'/>
+            <show-notes value='yes'/>
+            <show-rationale value='yes'/>
+        </show>
+        <leave-answer-space>
+            <tf value='yes'/>
+            <mtf value='yes'/>
+            <mc value='yes'/>
+            <yn value='yes'/>
+            <nr value='no'/>
+            <co value='no'/>
+            <ma value='yes'/>
+            <sa value='no'/>
+            <pr value='no'/>
+            <es value='no'/>
+            <ca value='no'/>
+            <ot value='no'/>
+        </leave-answer-space>
+        <question-type-order value='tf,mtf,mc,yn,nr,co,ma,sa,pr,es,ca,ot'/>
+        <section-page-break value='no'/>
+        <bi-display-mode value='mc'/>
+        <tf-show-choices value='no'/>
+        <mc-conserve-paper value='no'/>
+        <mc-choice-sequence value='abcde'/>
+        <show-answer-lines value='no'/>
+        <question-numbering value='continuous'/>
+        <answer-style template='a.' style='none'/>
+        <number-style template='1.' style='none'/>
+        <max-question-id value='9'/>
+        <max-narrative-id value='0'/>
+        <max-group-id value='1'/>
+        <default-font target='title'>
+            <number>1</number>
+            <size>13</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='sectiontitle'>
+            <number>1</number>
+            <size>11</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='questionnumber'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='answerchoice'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='newquestiondefault'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+    </preferences>
+    <test-header page='first'><para tabs='R10440'><b>Name: ________________________  Class: ___________________  Date: __________    ID: <field field-type='version'/></b></para></test-header>
+    <test-header page='subsequent'><para tabs='R10440'><b>Name: ________________________    ID: <field field-type='version'/></b></para></test-header>
+    <test-footer page='first'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <test-footer page='subsequent'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <instruction type='tf'><b>True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.</i></instruction>
+    <instruction type='mtf'><b>Modified True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.  If false, change the identified word or phrase to make the sentence or statement true.</i></instruction>
+    <instruction type='mc'><b>Multiple Choice</b><font size='10'>
+</font><i>Identify the letter of the choice that best completes the statement or answers the question.</i></instruction>
+    <instruction type='yn'><b>Yes/No</b><font size='10'>
+</font><i>Indicate whether you agree with the sentence or statement.</i></instruction>
+    <instruction type='nr'><b>Numeric Response</b></instruction>
+    <instruction type='co'><b>Completion</b><font size='10'>
+</font><i>Complete each sentence or statement.</i></instruction>
+    <instruction type='ma'><b>Matching</b></instruction>
+    <instruction type='sa'><b>Short Answer</b></instruction>
+    <instruction type='pr'><b>Problem</b></instruction>
+    <instruction type='es'><b>Essay</b></instruction>
+    <instruction type='ca'><b>Case</b></instruction>
+    <instruction type='ot'><b>Other</b></instruction>
+    <question type='tf' question-id='1' bank-id='0'>
+        <text>42 is the Absolute Answer to everything.</text>
+        <rationale>42 is the Ultimate Answer.</rationale>
+        <answer>F</answer>
+    </question>
+    <question type='mc' question-id='2' bank-id='0'>
+        <text><font size='10'>What's between orange and green in the spectrum?</font></text>
+        <choices columns='2'>
+            <choice-a><font size='10'>red</font></choice-a>
+            <choice-b><font size='10'>yellow</font></choice-b>
+            <choice-c><font size='10'>blue</font></choice-c>
+        </choices>
+        <answer>B</answer>
+    </question>
+    <question type='nr' question-id='3' bank-id='0'>
+        <text>This is a numeric response question.  How much is 12 * 2?</text>
+        <answer>24</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <matching-group group-id='1' bank-id='0' name='Matching 1'>
+        <text>Classify the animals.</text>
+        <choices columns='2'>
+            <choice-a>insect</choice-a>
+            <choice-b>amphibian</choice-b>
+            <choice-c>mammal</choice-c>
+        </choices>
+    </matching-group>
+    <question type='ma' question-id='6' bank-id='0' group='Matching 1'>
+        <text>cat</text>
+        <answer>C</answer>
+    </question>
+    <question type='ma' question-id='7' bank-id='0' group='Matching 1'>
+        <text>frog</text>
+        <answer>B</answer>
+    </question>
+    <question type='ma' question-id='8' bank-id='0' group='Matching 1'>
+        <text>newt</text>
+        <answer>B</answer>
+    </question>
+    <question type='sa' question-id='5' bank-id='0'>
+        <text>Name an amphibian: __________.</text>
+        <answer>frog</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <question type='es' question-id='4' bank-id='0'>
+        <text>How are you?</text>
+        <answer>Examview answer for essay questions will be imported as informations for graders.</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+</examview>";
+        return array(0=>$xml);
+    }
+
+    public function test_import_truefalse() {
+
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'truefalse';
+        $expectedq->name = '42 is the Absolute Answer to everything.';
+        $expectedq->questiontext = "42 is the Absolute Answer to everything.";
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->correctanswer = 0;
+        $expectedq->feedbacktrue = array(
+                'text' => get_string('incorrect', 'question'),
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $expectedq->feedbackfalse = array(
+                'text' => get_string('correct', 'question'),
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+    public function test_import_multichoice_single() {
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[1];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 1;
+        $expectedq->name = "What's between orange and green in the spectrum?";
+        $expectedq->questiontext = "What's between orange and green in the spectrum?";
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => 'red',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => 'yellow',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => 'blue',
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+        $expectedq->fraction = array(0, 1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => get_string('incorrect', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => get_string('correct', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                2 => array(
+                    'text' => get_string('incorrect', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_numerical() {
+
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[2];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'numerical';
+        $expectedq->name = 'This is a numeric response question.  How much is 12 * 2?';
+        $expectedq->questiontext = 'This is a numeric response question.  How much is 12 * 2?';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array('24');
+        $expectedq->fraction = array(1);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => get_string('correct', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+
+
+    public function test_import_fill_in_the_blank() {
+
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[3];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'shortanswer';
+        $expectedq->name = 'Name an amphibian: __________.';
+        $expectedq->questiontext = 'Name an amphibian: __________.';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->usecase = 0;
+        $expectedq->answer = array('frog', '*');
+        $expectedq->fraction = array(1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => get_string('correct', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                ),
+                1 => array(
+                    'text' => get_string('incorrect', 'question'),
+                    'format' => FORMAT_HTML,
+                    'files' => array(),
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_essay() {
+
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[4];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'essay';
+        $expectedq->name = 'How are you?';
+        $expectedq->questiontext = 'How are you?';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->responseformat = 'editor';
+        $expectedq->responsefieldlines = 15;
+        $expectedq->attachments = 0;
+        $expectedq->graderinfo = array(
+                'text' => 'Examview answer for essay questions will be imported as informations for graders.',
+                'format' => FORMAT_HTML,
+                'files' => array());
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    // Due to the way matching questions are parsed,
+    // the test for matching questions is somewhat different.
+    // First we test the parse_matching_groups method alone.
+    // Then we test the whole process wich involve parse_matching_groups,
+    // parse_ma and process_matches methods.
+    public function test_parse_matching_groups() {
+        $lines = $this->make_test_xml();
+
+        $importer = new qformat_examview();
+        $text = implode($lines, ' ');
+
+        $xml = xmlize($text, 0);
+        $importer->parse_matching_groups($xml['examview']['#']['matching-group']);
+        $matching = $importer->matching_questions;
+        $group = new stdClass();
+        $group->questiontext = 'Classify the animals.';
+        $group->subchoices = array('A' => 'insect', 'B' => 'amphibian', 'C' =>'mammal');
+            $group->subquestions = array();
+            $group->subanswers = array();
+        $expectedmatching = array( 'Matching 1' => $group);
+
+        $this->assertEquals($matching, $expectedmatching);
+    }
+
+    public function test_import_match() {
+
+        $xml = $this->make_test_xml();
+        $questions = array();
+
+        $importer = new qformat_examview();
+        $questions = $importer->readquestions($xml);
+        $q = $questions[5];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'match';
+        $expectedq->name = 'Classify the animals.';
+        $expectedq->questiontext = 'Classify the animals.';
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_MOODLE;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->subquestions = array(
+            array('text' => '', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'frog', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'newt', 'format' => FORMAT_HTML, 'files' => array()),
+            array('text' => 'cat', 'format' => FORMAT_HTML, 'files' => array()));
+        $expectedq->subanswers = array('insect', 'amphibian', 'amphibian', 'mammal');
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+}
diff --git a/question/format/examview/version.php b/question/format/examview/version.php
index e32474d..d6686e1 100644
--- a/question/format/examview/version.php
+++ b/question/format/examview/version.php
@@ -17,8 +17,7 @@
 /**
  * Version information for the calculated question type.
  *
- * @package    qformat
- * @subpackage examview
+ * @package    qformat_examview
  * @copyright  2011 The Open University
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-- 
1.7.9.5


From 778947cd6560ba15306635d7dc86bf6acb06537e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 19 Aug 2012 18:20:59 +0200
Subject: [PATCH 441/903] MDL-34868 update deprecated Google maps API V2 key
 info

---
 lang/en/admin.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 6b571c4..16e8396 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -218,7 +218,7 @@ $string['configfullnamedisplay'] = 'This defines how names are shown when they a
 $string['configgdversion'] = 'Indicate the version of GD that is installed.  The version shown by default is the one that has been auto-detected.  Don\'t change this unless you really know what you\'re doing.';
 $string['configgeoipfile'] = 'Location of GeoIP City binary data file. This file is not part of Moodle distribution and must be obtained separately from <a href="http://www.maxmind.com/">MaxMind</a>. You can either buy a commercial version or use the free version.<br />Simply download <a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" >http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz</a> and extract it into "{$a}" directory on your server.';
 $string['configgetremoteaddrconf'] = 'If your server is behind a reverse proxy, you can use this setting to specify which HTTP headers can be trusted to contain the remote IP address. The headers are read in order, using the first one that is available.';
-$string['configgooglemapkey'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="http://code.google.com/apis/maps/signup.html" >http://code.google.com/apis/maps/signup.html</a>.<br />Your web site URL is: {$a}';
+$string['configgooglemapkey'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="https://developers.google.com/maps/documentation/javascript/v2/introduction#Obtaining_Key">https://developers.google.com/maps/documentation/javascript/v2/introduction#Obtaining_Key</a>.<br />Your web site URL is: {$a}';
 $string['configgradebookroles'] = 'This setting allows you to control who appears on the gradebook.  Users need to have at least one of these roles in a course to be shown in the gradebook for that course.';
 $string['configgradeexport'] = 'Choose which gradebook export formats are your primary methods for exporting grades.  Chosen plugins will then set and use a "last exported" field for every grade.  For example, this might result in exported records being identified as being "new" or "updated".  If you are not sure about this then leave everything unchecked.';
 $string['confighiddenuserfields'] = 'Select which user information fields you wish to hide from other users other than course teachers/admins. This will increase student privacy. Hold CTRL key to select multiple fields.';
@@ -545,7 +545,7 @@ $string['globalsquoteswarning'] = '<p><strong>Security Warning</strong>: to oper
 $string['globalswarning'] = '<p><strong>SECURITY WARNING!</strong></p><p> To operate properly, Moodle requires <br />that you make certain changes to your current PHP settings.</p><p>You <em>must</em> set <code>register_globals=off</code>.</p><p>This setting is controlled by editing your <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file.</p>';
 $string['groupenrolmentkeypolicy'] = 'Group enrolment key policy';
 $string['groupenrolmentkeypolicy_desc'] = 'Turning this on will make Moodle check group enrolment keys against a valid password policy.';
-$string['googlemapkey'] = 'Google Maps API key';
+$string['googlemapkey'] = 'Google Maps API V2 key';
 $string['gotofirst'] = 'Go to first missing string';
 $string['gradebook'] = 'Gradebook';
 $string['gradebookroles'] = 'Graded roles';
-- 
1.7.9.5


From 7e84ef4fea0620ecc3472ce174ad59f0e1d19c96 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 19 Aug 2012 19:52:35 +0200
Subject: [PATCH 442/903] MDL-34959 add Google Maps API V3 support

---
 admin/settings/location.php |    3 ++-
 iplookup/index.php          |   16 ++++++++++++++--
 iplookup/module.js          |   18 ++++++++++++++++++
 lang/en/admin.php           |    2 ++
 4 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/admin/settings/location.php b/admin/settings/location.php
index 3d3ccb8..9f74d51 100644
--- a/admin/settings/location.php
+++ b/admin/settings/location.php
@@ -14,7 +14,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     $temp->add(new admin_setting_heading('iplookup', new lang_string('iplookup', 'admin'), new lang_string('iplookupinfo', 'admin')));
     $temp->add(new admin_setting_configfile('geoipfile', new lang_string('geoipfile', 'admin'), new lang_string('configgeoipfile', 'admin', $CFG->dataroot.'/geoip/'), $CFG->dataroot.'/geoip/GeoLiteCity.dat'));
-    $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), ''));
+    $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), '', PARAM_RAW, 60));
+    $temp->add(new admin_setting_configtext('googlemapkey3', new lang_string('googlemapkey3', 'admin'), new lang_string('googlemapkey3_help', 'admin'), '', PARAM_RAW, 60));
 
     $temp->add(new admin_setting_configtext('allcountrycodes', new lang_string('allcountrycodes', 'admin'), new lang_string('configallcountrycodes', 'admin'), '', '/^(?:\w+(?:,\w+)*)?$/'));
 
diff --git a/iplookup/index.php b/iplookup/index.php
index afb5383..5eff878 100644
--- a/iplookup/index.php
+++ b/iplookup/index.php
@@ -80,7 +80,7 @@ $PAGE->set_title(get_string('iplookup', 'admin').': '.$title);
 $PAGE->set_heading($title);
 echo $OUTPUT->header();
 
-if (empty($CFG->googlemapkey)) {
+if (empty($CFG->googlemapkey) and empty($CFG->googlemapkey3)) {
     $imgwidth  = 620;
     $imgheight = 310;
     $dotwidth  = 18;
@@ -95,13 +95,25 @@ if (empty($CFG->googlemapkey)) {
     echo '</div>';
     echo '<div id="note">'.$info['note'].'</div>';
 
-} else {
+} else if (empty($CFG->googlemapkey3)) {
     $PAGE->requires->js(new moodle_url("http://maps.google.com/maps?file=api&v=2&key=$CFG->googlemapkey"));
     $module = array('name'=>'core_iplookup', 'fullpath'=>'/iplookup/module.js');
     $PAGE->requires->js_init_call('M.core_iplookup.init', array($info['latitude'], $info['longitude']), true, $module);
 
     echo '<div id="map" style="width: 650px; height: 360px"></div>';
     echo '<div id="note">'.$info['note'].'</div>';
+
+} else {
+    if (strpos($CFG->wwwroot, 'https:') === 0) {
+        $PAGE->requires->js(new moodle_url('https://maps.googleapis.com/maps/api/js', array('key'=>$CFG->googlemapkey3, 'sensor'=>'false')));
+    } else {
+        $PAGE->requires->js(new moodle_url('http://maps.googleapis.com/maps/api/js', array('key'=>$CFG->googlemapkey3, 'sensor'=>'false')));
+    }
+    $module = array('name'=>'core_iplookup', 'fullpath'=>'/iplookup/module.js');
+    $PAGE->requires->js_init_call('M.core_iplookup.init3', array($info['latitude'], $info['longitude'], $ip), true, $module);
+
+    echo '<div id="map" style="width: 650px; height: 360px"></div>';
+    echo '<div id="note">'.$info['note'].'</div>';
 }
 
 echo $OUTPUT->footer();
diff --git a/iplookup/module.js b/iplookup/module.js
index dba71cc..004b7d2 100644
--- a/iplookup/module.js
+++ b/iplookup/module.js
@@ -41,3 +41,21 @@ M.core_iplookup.init = function(Y, latitude, longitude) {
         }, document.body);
     }
 };
+
+M.core_iplookup.init3 = function(Y, latitude, longitude, ip) {
+    var ipLatlng = new google.maps.LatLng(latitude, longitude);
+
+    var mapOptions = {
+        center: ipLatlng,
+        zoom: 6,
+        mapTypeId: google.maps.MapTypeId.ROADMAP
+    };
+
+    var map = new google.maps.Map(document.getElementById("map"), mapOptions);
+
+    var marker = new google.maps.Marker({
+        position: ipLatlng,
+        map: map,
+        title: ip
+    });
+};
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 16e8396..5734cda 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -546,6 +546,8 @@ $string['globalswarning'] = '<p><strong>SECURITY WARNING!</strong></p><p> To ope
 $string['groupenrolmentkeypolicy'] = 'Group enrolment key policy';
 $string['groupenrolmentkeypolicy_desc'] = 'Turning this on will make Moodle check group enrolment keys against a valid password policy.';
 $string['googlemapkey'] = 'Google Maps API V2 key';
+$string['googlemapkey3'] = 'Google Maps API V3 key';
+$string['googlemapkey3_help'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="https://developers.google.com/maps/documentation/javascript/tutorial#api_key" target="_blank">https://developers.google.com/maps/documentation/javascript/tutorial#api_key</a>';
 $string['gotofirst'] = 'Go to first missing string';
 $string['gradebook'] = 'Gradebook';
 $string['gradebookroles'] = 'Graded roles';
-- 
1.7.9.5


From db6842cca31887e5110a267977820fe805da0007 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 19 Aug 2012 17:08:40 +0200
Subject: [PATCH 443/903] MDL-34893 use standard options in Hint_ResultPrinter

This is a very nasty hack!
---
 lib/phpunit/classes/hint_resultprinter.php |   41 ++++++++++++++++++++++++++++
 phpunit.xml.dist                           |    1 -
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/lib/phpunit/classes/hint_resultprinter.php b/lib/phpunit/classes/hint_resultprinter.php
index 9e46811..33ec793 100644
--- a/lib/phpunit/classes/hint_resultprinter.php
+++ b/lib/phpunit/classes/hint_resultprinter.php
@@ -34,6 +34,20 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class Hint_ResultPrinter extends PHPUnit_TextUI_ResultPrinter {
+    public function __construct() {
+        // ARRGH - PHPUnit does not give us commandline arguments or xml config, so let's hack hard!
+        if (defined('DEBUG_BACKTRACE_PROVIDE_OBJECT')) {
+            $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);
+            if (isset($backtrace[2]['object']) and ($backtrace[2]['object'] instanceof PHPUnit_TextUI_Command)) {
+                list($verbose, $colors, $debug) = Hacky_TextUI_Command_reader::get_settings_hackery($backtrace[2]['object']);
+                parent::__construct(null, $verbose, $colors, $debug);
+                return;
+            }
+        }
+        // Fallback if something goes wrong.
+        parent::__construct(null, false, false, false);
+    }
+
     protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect) {
         global $CFG;
 
@@ -83,3 +97,30 @@ class Hint_ResultPrinter extends PHPUnit_TextUI_ResultPrinter {
         $this->write("\nTo re-run:\n $executable $testName $file\n");
     }
 }
+
+
+/**
+ * Class used in bloody hack that works around result printer constructor troubles.
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class Hacky_TextUI_Command_reader extends PHPUnit_TextUI_Command {
+    public static function get_settings_hackery(PHPUnit_TextUI_Command $toread) {
+        $arguments = $toread->arguments;
+        $config = PHPUnit_Util_Configuration::getInstance($arguments['configuration'])->getPHPUnitConfiguration();
+
+        $verbose = isset($config['verbose']) ? $config['verbose'] : false;
+        $verbose = isset($arguments['verbose']) ? $arguments['verbose'] : $verbose;
+
+        $colors = isset($config['colors']) ? $config['colors'] : false;
+        $colors = isset($arguments['colors']) ? $arguments['colors'] : $colors;
+
+        $debug = isset($config['debug']) ? $config['debug'] : false;
+        $debug = isset($arguments['debug']) ? $arguments['debug'] : $debug;
+
+        return array($verbose, $colors, $debug);
+    }
+}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 7b33e94..1e65824 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -14,7 +14,6 @@
         stopOnIncomplete="false"
         stopOnSkipped="false"
         strict="false"
-        verbose="false"
         printerClass="Hint_ResultPrinter"
         >
 
-- 
1.7.9.5


From 39e39bd437f5b34b4cdd3737c86c5f6ef6627f7f Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Fri, 17 Aug 2012 11:28:56 +0800
Subject: [PATCH 444/903] MDL-34406 message: removed an unnecessary string
 creation

---
 message/edit.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/message/edit.php b/message/edit.php
index c0b2cb4..be963fe 100644
--- a/message/edit.php
+++ b/message/edit.php
@@ -180,7 +180,6 @@ $preferences->blocknoncontacts  =  get_user_preferences( 'message_blocknoncontac
 /// Display page header
 $streditmymessage = get_string('editmymessage', 'message');
 $strparticipants  = get_string('participants');
-$userfullname     = fullname($user, true);
 
 $PAGE->set_title("$course->shortname: $streditmymessage");
 if ($course->id != SITEID) {
-- 
1.7.9.5


From 70746c433c0d687163cfc0f1b9af837789e05575 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 20 Aug 2012 10:23:46 +0800
Subject: [PATCH 445/903] MDL-34756 Unit Tests: Move backup helper tests

---
 backup/util/helper/tests/cronhelper_test.php |  442 ++++++++++++++++++++++++++
 lib/tests/backup_test.php                    |  440 -------------------------
 2 files changed, 442 insertions(+), 440 deletions(-)
 create mode 100644 backup/util/helper/tests/cronhelper_test.php
 delete mode 100644 lib/tests/backup_test.php

diff --git a/backup/util/helper/tests/cronhelper_test.php b/backup/util/helper/tests/cronhelper_test.php
new file mode 100644
index 0000000..7afd1be
--- /dev/null
+++ b/backup/util/helper/tests/cronhelper_test.php
@@ -0,0 +1,442 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for backups cron helper.
+ *
+ * @package   core_backup
+ * @category  phpunit
+ * @copyright 2012 Frédéric Massart <fred@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
+
+/**
+ * Unit tests for backup cron helper
+ */
+class backup_cron_helper_testcase extends advanced_testcase {
+
+    /**
+     * Test {@link backup_cron_automated_helper::calculate_next_automated_backup}.
+     */
+    public function test_next_automated_backup() {
+        $this->resetAfterTest();
+        set_config('backup_auto_active', '1', 'backup');
+
+        // Notes
+        // - backup_auto_weekdays starts on Sunday
+        // - Tests cannot be done in the past
+        // - Only the DST on the server side is handled.
+
+        // Every Tue and Fri at 11pm.
+        set_config('backup_auto_weekdays', '0010010', 'backup');
+        set_config('backup_auto_hour', '23', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        // Every Sun and Sat at 12pm.
+        set_config('backup_auto_weekdays', '1000001', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        // Every Sun at 4am.
+        set_config('backup_auto_weekdays', '1000000', 'backup');
+        set_config('backup_auto_hour', '4', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        // Every day but Wed at 8:30pm.
+        set_config('backup_auto_weekdays', '1110111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-20:30', date('w-H:i', $next));
+
+        // Sun, Tue, Thu, Sat at 12pm.
+        set_config('backup_auto_weekdays', '1010101', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        // None.
+        set_config('backup_auto_weekdays', '0000000', 'backup');
+        set_config('backup_auto_hour', '15', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0', $next);
+
+        // Playing with timezones.
+        set_config('backup_auto_weekdays', '1111111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        $timezone = 99;
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        // Viva Australia! (UTC+8).
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+
+        $timezone = -10.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = -5.0; // 5am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 0.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 3.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 8.0; // 6pm for the user (same than the server).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 9.0; // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
+
+        $timezone = 13.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-21:00') : date('w-22:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 1am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // The big apple! (UTC-5 / UTC-4 DST).
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 6pm for the user (server time).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-20:00') : date('w-21:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 11pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('next Monday 18:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-09:00' : '2-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-01:00' : '2-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-21:00' : '1-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-19:00' : '1-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 9pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-17:00' : '6-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-09:00' : '6-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '02', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('next Monday 04:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-09:00' : '1-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 4am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-01:00' : '6-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-21:00' : '5-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-19:00' : '5-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-17:00' : '5-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-09:00' : '5-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+    }
+}
diff --git a/lib/tests/backup_test.php b/lib/tests/backup_test.php
deleted file mode 100644
index 5b44435..0000000
--- a/lib/tests/backup_test.php
+++ /dev/null
@@ -1,440 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Unit tests for backups.
- *
- * @package   core
- * @category  phpunit
- * @copyright 2012 Frédéric Massart <fred@moodle.com>
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-global $CFG;
-require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
-
-/**
- * Unit tests for backup system
- */
-class backup_testcase extends advanced_testcase {
-
-    public function test_next_automated_backup() {
-
-        $this->resetAfterTest();
-        set_config('backup_auto_active', '1', 'backup');
-
-        // Notes
-        // - backup_auto_weekdays starts on Sunday
-        // - Tests cannot be done in the past
-        // - Only the DST on the server side is handled.
-
-        // Every Tue and Fri at 11pm.
-        set_config('backup_auto_weekdays', '0010010', 'backup');
-        set_config('backup_auto_hour', '23', 'backup');
-        set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-23:00', date('w-H:i', $next));
-
-        // Every Sun and Sat at 12pm.
-        set_config('backup_auto_weekdays', '1000001', 'backup');
-        set_config('backup_auto_hour', '0', 'backup');
-        set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        // Every Sun at 4am.
-        set_config('backup_auto_weekdays', '1000000', 'backup');
-        set_config('backup_auto_hour', '4', 'backup');
-        set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-04:00', date('w-H:i', $next));
-
-        // Every day but Wed at 8:30pm.
-        set_config('backup_auto_weekdays', '1110111', 'backup');
-        set_config('backup_auto_hour', '20', 'backup');
-        set_config('backup_auto_minute', '30', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('1-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('5-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-20:30', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 17:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-20:30', date('w-H:i', $next));
-
-        // Sun, Tue, Thu, Sat at 12pm.
-        set_config('backup_auto_weekdays', '1010101', 'backup');
-        set_config('backup_auto_hour', '0', 'backup');
-        set_config('backup_auto_minute', '0', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Monday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Tuesday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Wednesday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('4-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Thursday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Friday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('6-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Saturday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0-00:00', date('w-H:i', $next));
-
-        $now = strtotime('next Sunday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('2-00:00', date('w-H:i', $next));
-
-        // None.
-        set_config('backup_auto_weekdays', '0000000', 'backup');
-        set_config('backup_auto_hour', '15', 'backup');
-        set_config('backup_auto_minute', '30', 'backup');
-        $timezone = 99;
-
-        $now = strtotime('next Sunday 13:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals('0', $next);
-
-        // Playing with timezones.
-        set_config('backup_auto_weekdays', '1111111', 'backup');
-        set_config('backup_auto_hour', '20', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        $timezone = 99;
-        date_default_timezone_set('Australia/Perth');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 99;
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 99;
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('18:00:00');
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        // Viva Australia! (UTC+8).
-        date_default_timezone_set('Australia/Perth');
-        $now = strtotime('18:00:00');
-
-        $timezone = -10.0; // 12am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = -5.0; // 5am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 0.0;  // 10am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 3.0; // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        $timezone = 8.0; // 6pm for the user (same than the server).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
-
-        $timezone = 9.0; // 7pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
-
-        $timezone = 13.0; // 12am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
-
-        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('18:00:00');
-        $dst = date('I');
-
-        $timezone = -10.0; // 7am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -5.0; // 12pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 5pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-21:00') : date('w-22:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 8.0; // 1am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 9.0; // 2am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 13.0; // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // The big apple! (UTC-5 / UTC-4 DST).
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('18:00:00');
-        $dst = date('I');
-
-        $timezone = -10.0; // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -5.0; // 6pm for the user (server time).
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-20:00') : date('w-21:00');
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 11pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 3.0; // 2am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 8.0; // 7am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 9.0; // 8am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 13.0; // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // Some more timezone tests
-        set_config('backup_auto_weekdays', '0100001', 'backup');
-        set_config('backup_auto_hour', '20', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        date_default_timezone_set('Europe/Brussels');
-        $now = strtotime('next Monday 18:00:00');
-        $dst = date('I');
-
-        $timezone = -12.0;  // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '2-09:00' : '2-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -4.0;  // 1pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '2-01:00' : '2-02:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 5pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-21:00' : '1-22:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 2.0;  // 7pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-19:00' : '1-20:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 4.0;  // 9pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-17:00' : '6-18:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 12.0;  // 6am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-09:00' : '6-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        // Some more timezone tests
-        set_config('backup_auto_weekdays', '0100001', 'backup');
-        set_config('backup_auto_hour', '02', 'backup');
-        set_config('backup_auto_minute', '00', 'backup');
-
-        date_default_timezone_set('America/New_York');
-        $now = strtotime('next Monday 04:00:00');
-        $dst = date('I');
-
-        $timezone = -12.0;  // 8pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '1-09:00' : '1-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = -4.0;  // 4am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '6-01:00' : '6-02:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 0.0;  // 8am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-21:00' : '5-22:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 2.0;  // 10am for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-19:00' : '5-20:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 4.0;  // 12pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-17:00' : '5-18:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-        $timezone = 12.0;  // 8pm for the user.
-        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-        $expected = !$dst ? '5-09:00' : '5-10:00';
-        $this->assertEquals($expected, date('w-H:i', $next));
-
-    }
-}
-- 
1.7.9.5


From 9ff0c0bb845afb3743b2df3a24ab923f174062c5 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 16 Aug 2012 11:58:26 +0800
Subject: [PATCH 446/903] MDL-33362 book: Parse links to book modules from 1.9
 backups

---
 .../moodle2/restore_book_activity_task.class.php   |    3 +++
 mod/book/version.php                               |    2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/mod/book/backup/moodle2/restore_book_activity_task.class.php b/mod/book/backup/moodle2/restore_book_activity_task.class.php
index da1b75f..d9ee50e 100644
--- a/mod/book/backup/moodle2/restore_book_activity_task.class.php
+++ b/mod/book/backup/moodle2/restore_book_activity_task.class.php
@@ -82,6 +82,9 @@ class restore_book_activity_task extends restore_activity_task {
         $rules[] = new restore_decode_rule('BOOKVIEWBYB', '/mod/book/view.php?b=$1', 'book');
         $rules[] = new restore_decode_rule('BOOKVIEWBYBCH', '/mod/book/view.php?b=$1&amp;chapterid=$2', array('book', 'book_chapter'));
 
+        // Convert old book links MDL-33362
+        $rules[] = new restore_decode_rule('BOOKSTART', '/mod/book/view.php?id=$1', 'course_module');
+
         return $rules;
     }
 
diff --git a/mod/book/version.php b/mod/book/version.php
index cc4ad8f..84a1638 100644
--- a/mod/book/version.php
+++ b/mod/book/version.php
@@ -25,6 +25,6 @@
 defined('MOODLE_INTERNAL') || die;
 
 $module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version   = 2012061700; // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061701; // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700; // Requires this Moodle version
 $module->cron      = 0;          // Period for cron to check this module (secs)
-- 
1.7.9.5


From ae21b71925165fd21e6f5b24fb0ce082d2cbf143 Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Thu, 16 Aug 2012 14:31:39 +0800
Subject: [PATCH 447/903] MDL-34377: Fix: assignments overview page shows a
 unset due date as Epoch and counts draft
 submissions

---
 mod/assign/index.php |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/mod/assign/index.php b/mod/assign/index.php
index cde25a4..b90c8ac 100644
--- a/mod/assign/index.php
+++ b/mod/assign/index.php
@@ -56,8 +56,13 @@ foreach ($assignments as $assignment) {
     $cm = get_coursemodule_from_instance('assign', $assignment->id, 0, false, MUST_EXIST);
 
     $link = html_writer::link(new moodle_url('/mod/assign/view.php', array('id' => $cm->id)), $assignment->name);
-    $date = userdate($assignment->duedate);
-    $submissions = $DB->count_records('assign_submission', array('assignment'=>$cm->instance));
+    $date = '-';
+    if (!empty($assignment->duedate)) {
+        $date = userdate($assignment->duedate);
+    }
+
+    $params = array('assignment'=>$cm->instance, 'status'=>ASSIGN_SUBMISSION_STATUS_SUBMITTED);
+    $submissions = $DB->count_records('assign_submission', $params);
     $row = array($link, $date, $submissions);
     $table->data[] = $row;
 
-- 
1.7.9.5


From b8cc0200640621e92f9c0cc709c7fd26b29d828c Mon Sep 17 00:00:00 2001
From: Michael de Raadt <michaeld@moodle.com>
Date: Tue, 14 Aug 2012 11:44:20 +0800
Subject: [PATCH 448/903] MDL-34779 settings: Updating lang string
 corrposnding to the fullnamedisplay setting

---
 lang/en/admin.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 6b571c4..0d633b3 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -214,7 +214,7 @@ $string['configforcelogin'] = 'Normally, the front page of the site and the cour
 $string['configforceloginforprofiles'] = 'This setting forces people to login as a real (non-guest) account before viewing any user\'s profile. If you disabled this setting, you may find that some users post advertising (spam) or other inappropriate content in their profiles, which is then visible to the whole world.';
 $string['configfrontpage'] = 'The items selected above will be displayed on the site\'s front page.';
 $string['configfrontpageloggedin'] = 'The items selected above will be displayed on the site\'s front page when a user is logged in.';
-$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is the default "First name + Surname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions).';
+$string['configfullnamedisplay'] = 'This defines how names are shown when they are displayed in full. For most mono-lingual sites the most efficient setting is "First name + Surname", but you may choose to hide surnames altogether, or to leave it up to the current language pack to decide (some languages have different conventions).';
 $string['configgdversion'] = 'Indicate the version of GD that is installed.  The version shown by default is the one that has been auto-detected.  Don\'t change this unless you really know what you\'re doing.';
 $string['configgeoipfile'] = 'Location of GeoIP City binary data file. This file is not part of Moodle distribution and must be obtained separately from <a href="http://www.maxmind.com/">MaxMind</a>. You can either buy a commercial version or use the free version.<br />Simply download <a href="http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz" >http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz</a> and extract it into "{$a}" directory on your server.';
 $string['configgetremoteaddrconf'] = 'If your server is behind a reverse proxy, you can use this setting to specify which HTTP headers can be trusted to contain the remote IP address. The headers are read in order, using the first one that is available.';
-- 
1.7.9.5


From f3ad0ed27d62153a1ee59a00247a5fb2feb5f6f7 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Mon, 20 Aug 2012 09:41:02 +0200
Subject: [PATCH 449/903] MDL-34738 load sample dat file in tests

---
 .../blackboard/tests/blackboardformat_test.php     |  145 +-------------------
 .../tests/fixtures/sample_blackboard.dat           |    2 +-
 2 files changed, 3 insertions(+), 144 deletions(-)

diff --git a/question/format/blackboard/tests/blackboardformat_test.php b/question/format/blackboard/tests/blackboardformat_test.php
index 222b6b3..d67e526 100644
--- a/question/format/blackboard/tests/blackboardformat_test.php
+++ b/question/format/blackboard/tests/blackboardformat_test.php
@@ -41,151 +41,10 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
 class qformat_blackboard_test extends question_testcase {
 
     public function make_test_xml() {
-        $xml = "<?xml version='1.0' encoding='utf-8'?>
-<POOL>
-    <TITLE value='exam 3 2008-9'/>
-    <QUESTIONLIST>
-        <QUESTION id='q1' class='QUESTION_TRUEFALSE' points='1'/>
-        <QUESTION id='q7' class='QUESTION_MULTIPLECHOICE' points='1'/>
-        <QUESTION id='q8' class='QUESTION_MULTIPLEANSWER' points='1'/>
-        <QUESTION id='q39-44' class='QUESTION_MATCH' points='2'/>
-        <QUESTION id='q9' class='QUESTION_ESSAY' points='1'/>
-        <QUESTION id='q27' class='QUESTION_FILLINBLANK' points='1'/>
-    </QUESTIONLIST>
-    <QUESTION_TRUEFALSE id='q1'>
-        <BODY>
-            <TEXT><![CDATA[<span style=\"font-size:12pt\">42 is the Absolute Answer to everything.</span>]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q1_a1'>
-            <TEXT>False</TEXT>
-        </ANSWER>
-        <ANSWER id='q1_a2'>
-            <TEXT>True</TEXT>
-        </ANSWER>
-        <GRADABLE>
-            <CORRECTANSWER answer_id='q1_a2'/>
-            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
-            <FEEDBACK_WHEN_INCORRECT><![CDATA[42 is the Ultimate Answer.]]></FEEDBACK_WHEN_INCORRECT>
-        </GRADABLE>
-    </QUESTION_TRUEFALSE>
-    <QUESTION_MULTIPLECHOICE id='q7'>
-        <BODY>
-            <TEXT><![CDATA[<span style=\"font-size:12pt\">What's between orange and green in the spectrum?</span>]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q7_a1' position='1'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">red</span>]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q7_a2' position='2'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">yellow</span>]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q7_a3' position='3'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">blue</span>]]></TEXT>
-        </ANSWER>
-        <GRADABLE>
-            <CORRECTANSWER answer_id='q7_a2'/>
-            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
-            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow is between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
-            </GRADABLE>
-    </QUESTION_MULTIPLECHOICE>
-    <QUESTION_MULTIPLEANSWER id='q8'>
-        <BODY>
-            <TEXT><![CDATA[<span style=\"font-size:12pt\">What's between orange and green in the spectrum?</span>]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q8_a1' position='1'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">yellow</span>]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q8_a2' position='2'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">red</span>]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q8_a3' position='3'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">off-beige</span>]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q8_a4' position='4'>
-        <TEXT><![CDATA[<span style=\"font-size:12pt\">blue</span>]]></TEXT>
-        </ANSWER>
-        <GRADABLE>
-            <CORRECTANSWER answer_id='q8_a1'/>
-            <CORRECTANSWER answer_id='q8_a3'/>
-            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
-            <FEEDBACK_WHEN_INCORRECT>
-                <![CDATA[Only yellow and off-beige are between orange and green in the spectrum.]]>
-            </FEEDBACK_WHEN_INCORRECT>
-        </GRADABLE>
-    </QUESTION_MULTIPLEANSWER>
-    <QUESTION_MATCH id='q39-44'>
-        <BODY>
-            <TEXT><![CDATA[<i>Classify the animals.</i>]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q39-44_a1' position='1'>
-            <TEXT><![CDATA[frog]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q39-44_a2' position='2'>
-            <TEXT><![CDATA[cat]]></TEXT>
-        </ANSWER>
-        <ANSWER id='q39-44_a3' position='3'>
-            <TEXT><![CDATA[newt]]></TEXT>
-        </ANSWER>
-        <CHOICE id='q39-44_c1' position='1'>
-            <TEXT><![CDATA[mammal]]></TEXT>
-        </CHOICE>
-        <CHOICE id='q39-44_c2' position='2'>
-            <TEXT><![CDATA[insect]]></TEXT>
-        </CHOICE>
-        <CHOICE id='q39-44_c3' position='3'>
-            <TEXT><![CDATA[amphibian]]></TEXT>
-        </CHOICE>
-        <GRADABLE>
-            <CORRECTANSWER answer_id='q39-44_a1' choice_id='q39-44_c3'/>
-            <CORRECTANSWER answer_id='q39-44_a2' choice_id='q39-44_c1'/>
-            <CORRECTANSWER answer_id='q39-44_a3' choice_id='q39-44_c3'/>
-        </GRADABLE>
-    </QUESTION_MATCH>
-    <QUESTION_ESSAY id='q9'>
-        <BODY>
-            <TEXT><![CDATA[How are you?]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q9_a1'>
-            <TEXT><![CDATA[Blackboard answer for essay questions will be imported as informations for graders.]]></TEXT>
-        </ANSWER>
-        <GRADABLE>
-        </GRADABLE>
-    </QUESTION_ESSAY>
-    <QUESTION_FILLINBLANK id='q27'>
-        <BODY>
-            <TEXT><![CDATA[<span style=\"font-size:12pt\">Name an amphibian: __________.</span>]]></TEXT>
-            <FLAGS>
-                <ISHTML value='true'/>
-                <ISNEWLINELITERAL value='false'/>
-            </FLAGS>
-        </BODY>
-        <ANSWER id='q27_a1' position='1'>
-            <TEXT>frog</TEXT>
-        </ANSWER>
-        <GRADABLE>
-        </GRADABLE>
-    </QUESTION_FILLINBLANK></POOL>";
+        $xml = file_get_contents(__DIR__ . '/fixtures/sample_blackboard.dat');
         return $xml;
     }
+
     public function test_import_match() {
 
         $xmldata = xmlize($this->make_test_xml());
diff --git a/question/format/blackboard/tests/fixtures/sample_blackboard.dat b/question/format/blackboard/tests/fixtures/sample_blackboard.dat
index 88088c3..93bb583 100644
--- a/question/format/blackboard/tests/fixtures/sample_blackboard.dat
+++ b/question/format/blackboard/tests/fixtures/sample_blackboard.dat
@@ -127,7 +127,7 @@
     </QUESTION_ESSAY>
     <QUESTION_FILLINBLANK id='q27'>
         <BODY>
-            <TEXT><![CDATA[Name an amphibian: __________.]]></TEXT>
+            <TEXT><![CDATA[<span style="font-size:12pt">Name an amphibian: __________.</span>]]></TEXT>
             <FLAGS>
                 <ISHTML value='true'/>
                 <ISNEWLINELITERAL value='false'/>
-- 
1.7.9.5


From 2e941f33565291852c64f99321be5dfcba8ec1a3 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Mon, 20 Aug 2012 10:44:34 +0200
Subject: [PATCH 450/903] MDL-34808 load sample xml file from fixtures in
 tests

---
 .../format/examview/tests/examviewformat_test.php  |  162 +-------------------
 .../examview/tests/fixtures/examview_sample.xml    |  161 +++++++++++++++++++
 2 files changed, 162 insertions(+), 161 deletions(-)
 create mode 100644 question/format/examview/tests/fixtures/examview_sample.xml

diff --git a/question/format/examview/tests/examviewformat_test.php b/question/format/examview/tests/examviewformat_test.php
index 6434ba8..601650f 100644
--- a/question/format/examview/tests/examviewformat_test.php
+++ b/question/format/examview/tests/examviewformat_test.php
@@ -41,167 +41,7 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
 class qformat_examview_test extends question_testcase {
 
     public function make_test_xml() {
-        $xml = "<?xml version='1.0' encoding='utf-8' standalone='yes'?>
-<examview type='test' platform='Windows' app-version='4.0.2'>
-    <header>
-        <title>Moodle Example</title>
-        <version>A</version>
-    </header>
-    <font-table>
-        <font-entry number='1'>
-            <charset>ansi</charset>
-            <name>Times New Roman</name>
-            <pitch>variable</pitch>
-            <family>roman</family>
-        </font-entry>
-    </font-table>
-    <preferences>
-        <show>
-            <show-answer value='yes'/>
-            <show-difficulty value='yes'/>
-            <show-reference value='yes'/>
-            <show-text-objective value='yes'/>
-            <show-state-objective value='yes'/>
-            <show-topic value='yes'/>
-            <show-keywords value='yes'/>
-            <show-misc value='yes'/>
-            <show-notes value='yes'/>
-            <show-rationale value='yes'/>
-        </show>
-        <leave-answer-space>
-            <tf value='yes'/>
-            <mtf value='yes'/>
-            <mc value='yes'/>
-            <yn value='yes'/>
-            <nr value='no'/>
-            <co value='no'/>
-            <ma value='yes'/>
-            <sa value='no'/>
-            <pr value='no'/>
-            <es value='no'/>
-            <ca value='no'/>
-            <ot value='no'/>
-        </leave-answer-space>
-        <question-type-order value='tf,mtf,mc,yn,nr,co,ma,sa,pr,es,ca,ot'/>
-        <section-page-break value='no'/>
-        <bi-display-mode value='mc'/>
-        <tf-show-choices value='no'/>
-        <mc-conserve-paper value='no'/>
-        <mc-choice-sequence value='abcde'/>
-        <show-answer-lines value='no'/>
-        <question-numbering value='continuous'/>
-        <answer-style template='a.' style='none'/>
-        <number-style template='1.' style='none'/>
-        <max-question-id value='9'/>
-        <max-narrative-id value='0'/>
-        <max-group-id value='1'/>
-        <default-font target='title'>
-            <number>1</number>
-            <size>13</size>
-            <style>bold</style>
-            <text-rgb>#000000</text-rgb>
-        </default-font>
-        <default-font target='sectiontitle'>
-            <number>1</number>
-            <size>11</size>
-            <style>bold</style>
-            <text-rgb>#000000</text-rgb>
-        </default-font>
-        <default-font target='questionnumber'>
-            <number>1</number>
-            <size>11</size>
-            <text-rgb>#000000</text-rgb>
-        </default-font>
-        <default-font target='answerchoice'>
-            <number>1</number>
-            <size>11</size>
-            <text-rgb>#000000</text-rgb>
-        </default-font>
-        <default-font target='newquestiondefault'>
-            <number>1</number>
-            <size>11</size>
-            <text-rgb>#000000</text-rgb>
-        </default-font>
-    </preferences>
-    <test-header page='first'><para tabs='R10440'><b>Name: ________________________  Class: ___________________  Date: __________    ID: <field field-type='version'/></b></para></test-header>
-    <test-header page='subsequent'><para tabs='R10440'><b>Name: ________________________    ID: <field field-type='version'/></b></para></test-header>
-    <test-footer page='first'><para justify='center'><field field-type='pageNumber'/>
-</para></test-footer>
-    <test-footer page='subsequent'><para justify='center'><field field-type='pageNumber'/>
-</para></test-footer>
-    <instruction type='tf'><b>True/False</b><font size='10'>
-</font><i>Indicate whether the sentence or statement is true or false.</i></instruction>
-    <instruction type='mtf'><b>Modified True/False</b><font size='10'>
-</font><i>Indicate whether the sentence or statement is true or false.  If false, change the identified word or phrase to make the sentence or statement true.</i></instruction>
-    <instruction type='mc'><b>Multiple Choice</b><font size='10'>
-</font><i>Identify the letter of the choice that best completes the statement or answers the question.</i></instruction>
-    <instruction type='yn'><b>Yes/No</b><font size='10'>
-</font><i>Indicate whether you agree with the sentence or statement.</i></instruction>
-    <instruction type='nr'><b>Numeric Response</b></instruction>
-    <instruction type='co'><b>Completion</b><font size='10'>
-</font><i>Complete each sentence or statement.</i></instruction>
-    <instruction type='ma'><b>Matching</b></instruction>
-    <instruction type='sa'><b>Short Answer</b></instruction>
-    <instruction type='pr'><b>Problem</b></instruction>
-    <instruction type='es'><b>Essay</b></instruction>
-    <instruction type='ca'><b>Case</b></instruction>
-    <instruction type='ot'><b>Other</b></instruction>
-    <question type='tf' question-id='1' bank-id='0'>
-        <text>42 is the Absolute Answer to everything.</text>
-        <rationale>42 is the Ultimate Answer.</rationale>
-        <answer>F</answer>
-    </question>
-    <question type='mc' question-id='2' bank-id='0'>
-        <text><font size='10'>What's between orange and green in the spectrum?</font></text>
-        <choices columns='2'>
-            <choice-a><font size='10'>red</font></choice-a>
-            <choice-b><font size='10'>yellow</font></choice-b>
-            <choice-c><font size='10'>blue</font></choice-c>
-        </choices>
-        <answer>B</answer>
-    </question>
-    <question type='nr' question-id='3' bank-id='0'>
-        <text>This is a numeric response question.  How much is 12 * 2?</text>
-        <answer>24</answer>
-        <info>
-            <answer-space>-1</answer-space>
-        </info>
-    </question>
-    <matching-group group-id='1' bank-id='0' name='Matching 1'>
-        <text>Classify the animals.</text>
-        <choices columns='2'>
-            <choice-a>insect</choice-a>
-            <choice-b>amphibian</choice-b>
-            <choice-c>mammal</choice-c>
-        </choices>
-    </matching-group>
-    <question type='ma' question-id='6' bank-id='0' group='Matching 1'>
-        <text>cat</text>
-        <answer>C</answer>
-    </question>
-    <question type='ma' question-id='7' bank-id='0' group='Matching 1'>
-        <text>frog</text>
-        <answer>B</answer>
-    </question>
-    <question type='ma' question-id='8' bank-id='0' group='Matching 1'>
-        <text>newt</text>
-        <answer>B</answer>
-    </question>
-    <question type='sa' question-id='5' bank-id='0'>
-        <text>Name an amphibian: __________.</text>
-        <answer>frog</answer>
-        <info>
-            <answer-space>-1</answer-space>
-        </info>
-    </question>
-    <question type='es' question-id='4' bank-id='0'>
-        <text>How are you?</text>
-        <answer>Examview answer for essay questions will be imported as informations for graders.</answer>
-        <info>
-            <answer-space>-1</answer-space>
-        </info>
-    </question>
-</examview>";
+        $xml = $xml = file_get_contents(__DIR__ . '/fixtures/examview_sample.xml');
         return array(0=>$xml);
     }
 
diff --git a/question/format/examview/tests/fixtures/examview_sample.xml b/question/format/examview/tests/fixtures/examview_sample.xml
new file mode 100644
index 0000000..7627e46
--- /dev/null
+++ b/question/format/examview/tests/fixtures/examview_sample.xml
@@ -0,0 +1,161 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<examview type='test' platform='Windows' app-version='4.0.2'>
+    <header>
+        <title>Moodle Example</title>
+        <version>A</version>
+    </header>
+    <font-table>
+        <font-entry number='1'>
+            <charset>ansi</charset>
+            <name>Times New Roman</name>
+            <pitch>variable</pitch>
+            <family>roman</family>
+        </font-entry>
+    </font-table>
+    <preferences>
+        <show>
+            <show-answer value='yes'/>
+            <show-difficulty value='yes'/>
+            <show-reference value='yes'/>
+            <show-text-objective value='yes'/>
+            <show-state-objective value='yes'/>
+            <show-topic value='yes'/>
+            <show-keywords value='yes'/>
+            <show-misc value='yes'/>
+            <show-notes value='yes'/>
+            <show-rationale value='yes'/>
+        </show>
+        <leave-answer-space>
+            <tf value='yes'/>
+            <mtf value='yes'/>
+            <mc value='yes'/>
+            <yn value='yes'/>
+            <nr value='no'/>
+            <co value='no'/>
+            <ma value='yes'/>
+            <sa value='no'/>
+            <pr value='no'/>
+            <es value='no'/>
+            <ca value='no'/>
+            <ot value='no'/>
+        </leave-answer-space>
+        <question-type-order value='tf,mtf,mc,yn,nr,co,ma,sa,pr,es,ca,ot'/>
+        <section-page-break value='no'/>
+        <bi-display-mode value='mc'/>
+        <tf-show-choices value='no'/>
+        <mc-conserve-paper value='no'/>
+        <mc-choice-sequence value='abcde'/>
+        <show-answer-lines value='no'/>
+        <question-numbering value='continuous'/>
+        <answer-style template='a.' style='none'/>
+        <number-style template='1.' style='none'/>
+        <max-question-id value='9'/>
+        <max-narrative-id value='0'/>
+        <max-group-id value='1'/>
+        <default-font target='title'>
+            <number>1</number>
+            <size>13</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='sectiontitle'>
+            <number>1</number>
+            <size>11</size>
+            <style>bold</style>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='questionnumber'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='answerchoice'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+        <default-font target='newquestiondefault'>
+            <number>1</number>
+            <size>11</size>
+            <text-rgb>#000000</text-rgb>
+        </default-font>
+    </preferences>
+    <test-header page='first'><para tabs='R10440'><b>Name: ________________________  Class: ___________________  Date: __________    ID: <field field-type='version'/></b></para></test-header>
+    <test-header page='subsequent'><para tabs='R10440'><b>Name: ________________________    ID: <field field-type='version'/></b></para></test-header>
+    <test-footer page='first'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <test-footer page='subsequent'><para justify='center'><field field-type='pageNumber'/>
+</para></test-footer>
+    <instruction type='tf'><b>True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.</i></instruction>
+    <instruction type='mtf'><b>Modified True/False</b><font size='10'>
+</font><i>Indicate whether the sentence or statement is true or false.  If false, change the identified word or phrase to make the sentence or statement true.</i></instruction>
+    <instruction type='mc'><b>Multiple Choice</b><font size='10'>
+</font><i>Identify the letter of the choice that best completes the statement or answers the question.</i></instruction>
+    <instruction type='yn'><b>Yes/No</b><font size='10'>
+</font><i>Indicate whether you agree with the sentence or statement.</i></instruction>
+    <instruction type='nr'><b>Numeric Response</b></instruction>
+    <instruction type='co'><b>Completion</b><font size='10'>
+</font><i>Complete each sentence or statement.</i></instruction>
+    <instruction type='ma'><b>Matching</b></instruction>
+    <instruction type='sa'><b>Short Answer</b></instruction>
+    <instruction type='pr'><b>Problem</b></instruction>
+    <instruction type='es'><b>Essay</b></instruction>
+    <instruction type='ca'><b>Case</b></instruction>
+    <instruction type='ot'><b>Other</b></instruction>
+    <question type='tf' question-id='1' bank-id='0'>
+        <text>42 is the Absolute Answer to everything.</text>
+        <rationale>42 is the Ultimate Answer.</rationale>
+        <answer>F</answer>
+    </question>
+    <question type='mc' question-id='2' bank-id='0'>
+        <text><font size='10'>What's between orange and green in the spectrum?</font></text>
+        <choices columns='2'>
+            <choice-a><font size='10'>red</font></choice-a>
+            <choice-b><font size='10'>yellow</font></choice-b>
+            <choice-c><font size='10'>blue</font></choice-c>
+        </choices>
+        <answer>B</answer>
+    </question>
+    <question type='nr' question-id='3' bank-id='0'>
+        <text>This is a numeric response question.  How much is 12 * 2?</text>
+        <answer>24</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <matching-group group-id='1' bank-id='0' name='Matching 1'>
+        <text>Classify the animals.</text>
+        <choices columns='2'>
+            <choice-a>insect</choice-a>
+            <choice-b>amphibian</choice-b>
+            <choice-c>mammal</choice-c>
+        </choices>
+    </matching-group>
+    <question type='ma' question-id='6' bank-id='0' group='Matching 1'>
+        <text>cat</text>
+        <answer>C</answer>
+    </question>
+    <question type='ma' question-id='7' bank-id='0' group='Matching 1'>
+        <text>frog</text>
+        <answer>B</answer>
+    </question>
+    <question type='ma' question-id='8' bank-id='0' group='Matching 1'>
+        <text>newt</text>
+        <answer>B</answer>
+    </question>
+    <question type='sa' question-id='5' bank-id='0'>
+        <text>Name an amphibian: __________.</text>
+        <answer>frog</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+    <question type='es' question-id='4' bank-id='0'>
+        <text>How are you?</text>
+        <answer>Examview answer for essay questions will be imported as informations for graders.</answer>
+        <info>
+            <answer-space>-1</answer-space>
+        </info>
+    </question>
+</examview>
\ No newline at end of file
-- 
1.7.9.5


From c6d7689621d7f28e552d3fcb499557ec3e3ddaf6 Mon Sep 17 00:00:00 2001
From: Nathan Mares <nathan@catalyst-au.net>
Date: Tue, 17 Jul 2012 19:37:06 +1000
Subject: [PATCH 451/903] MDL-34372: Fix query in backup_cron_helper so it
 works on Postgres 8.3

Amended by stronk7@moodle.org to use uppercase SQL keywords.
---
 backup/util/helper/backup_cron_helper.class.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index 9715a5d..4df4360 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -255,7 +255,7 @@ abstract class backup_cron_automated_helper {
             self::BACKUP_STATUS_SKIPPED => 0,
         );
 
-        $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
+        $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
 
         foreach ($statuses as $status) {
             if (empty($status->statuscount)) {
-- 
1.7.9.5


From 3f7df55d1ca2cefb251a8482c1eed27bd6d85ab8 Mon Sep 17 00:00:00 2001
From: Jason Ilicic <jason.ilicic@netspot.com.au>
Date: Wed, 25 Jul 2012 10:20:16 +0930
Subject: [PATCH 452/903] MDL-34529: Fixed ordering of course sections when
 performing import/restore by adding the sort
 parameter.

---
 backup/util/dbops/backup_plan_dbops.class.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/backup/util/dbops/backup_plan_dbops.class.php b/backup/util/dbops/backup_plan_dbops.class.php
index 2ce9434..30714ed 100644
--- a/backup/util/dbops/backup_plan_dbops.class.php
+++ b/backup/util/dbops/backup_plan_dbops.class.php
@@ -112,7 +112,7 @@ abstract class backup_plan_dbops extends backup_dbops {
 
         // Get all sections belonging to requested course
         $sectionsarr = array();
-        $sections = $DB->get_records('course_sections', array('course' => $courseid));
+        $sections = $DB->get_records('course_sections', array('course' => $courseid), 'section');
         foreach ($sections as $section) {
             $sectionsarr[] = $section->id;
         }
-- 
1.7.9.5


From 2d0a11ee947523b16a4ddb480c50d52fbeb4d637 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Mon, 20 Aug 2012 17:09:40 -0400
Subject: [PATCH 453/903] MDL-34985 gradebook Fixing issue where default
 parent in Full View Add Category could be
 inconsistent.

Turns out the correct default was already computed, but was not being applied to the setting.
---
 grade/edit/tree/category_form.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/grade/edit/tree/category_form.php b/grade/edit/tree/category_form.php
index 5a1d8f7..c155565 100644
--- a/grade/edit/tree/category_form.php
+++ b/grade/edit/tree/category_form.php
@@ -225,7 +225,7 @@ class edit_category_form extends moodleform {
         $mform->addElement('header', 'headerparent', get_string('parentcategory', 'grades'));
 
         $options = array();
-        $default = '';
+        $default = -1;
         $categories = grade_category::fetch_all(array('courseid'=>$COURSE->id));
 
         foreach ($categories as $cat) {
@@ -238,6 +238,7 @@ class edit_category_form extends moodleform {
 
         if (count($categories) > 1) {
             $mform->addElement('select', 'parentcategory', get_string('parentcategory', 'grades'), $options);
+            $mform->setDefault('parentcategory', $default);
             $mform->addElement('static', 'currentparentaggregation', get_string('currentparentaggregation', 'grades'));
         }
 
-- 
1.7.9.5


From b747690361c744f4e40b371bf59a24c5394ec3b3 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 21 Aug 2012 09:55:50 +0800
Subject: [PATCH 454/903] MDL-34738 qformat_blackboard - increment version
 number

---
 question/format/blackboard/version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/format/blackboard/version.php b/question/format/blackboard/version.php
index 53948ab..67e6e42 100644
--- a/question/format/blackboard/version.php
+++ b/question/format/blackboard/version.php
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component = 'qformat_blackboard';
-$plugin->version   = 2012061700;
+$plugin->version   = 2012061701;
 
 $plugin->requires  = 2012061700;
 
-- 
1.7.9.5


From a415852d2bea6e04583fbc974ccaeb26814f80f9 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 20 Aug 2012 16:35:28 +0800
Subject: [PATCH 455/903] MDL-31496 mod_data Replacing inline styles for CSS
 classes in textarea elements

---
 mod/data/field/checkbox/mod.html       |    2 +-
 mod/data/field/menu/mod.html           |    2 +-
 mod/data/field/multimenu/mod.html      |    2 +-
 mod/data/field/picture/field.class.php |    4 ++--
 mod/data/field/radiobutton/mod.html    |    2 +-
 mod/data/lib.php                       |    2 +-
 mod/data/styles.css                    |   11 +++++++++++
 7 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/mod/data/field/checkbox/mod.html b/mod/data/field/checkbox/mod.html
index 6d8bef3..a881292 100644
--- a/mod/data/field/checkbox/mod.html
+++ b/mod/data/field/checkbox/mod.html
@@ -9,6 +9,6 @@
     </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
-        <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+        <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
     </tr>
 </table>
diff --git a/mod/data/field/menu/mod.html b/mod/data/field/menu/mod.html
index 58fa709..f92fb13 100644
--- a/mod/data/field/menu/mod.html
+++ b/mod/data/field/menu/mod.html
@@ -9,6 +9,6 @@
     </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
-        <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+        <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
     </tr>
 </table>
diff --git a/mod/data/field/multimenu/mod.html b/mod/data/field/multimenu/mod.html
index 6d8bef3..a881292 100644
--- a/mod/data/field/multimenu/mod.html
+++ b/mod/data/field/multimenu/mod.html
@@ -9,6 +9,6 @@
     </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
-        <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+        <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
     </tr>
 </table>
diff --git a/mod/data/field/picture/field.class.php b/mod/data/field/picture/field.class.php
index 67d80f8..f569f53 100644
--- a/mod/data/field/picture/field.class.php
+++ b/mod/data/field/picture/field.class.php
@@ -152,13 +152,13 @@ class data_field_picture extends data_field_base {
         if ($template == 'listtemplate') {
             $src = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_data/content/'.$content->id.'/'.'thumb_'.$content->content);
             // no need to add width/height, because the thumb is resized properly
-            $str = '<a href="view.php?d='.$this->field->dataid.'&amp;rid='.$recordid.'"><img src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" style="border:0px" /></a>';
+            $str = '<a href="view.php?d='.$this->field->dataid.'&amp;rid='.$recordid.'"><img src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" class="list_picture"/></a>';
 
         } else {
             $src = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.$this->context->id.'/mod_data/content/'.$content->id.'/'.$content->content);
             $width  = $this->field->param1 ? ' width="'.s($this->field->param1).'" ':' ';
             $height = $this->field->param2 ? ' height="'.s($this->field->param2).'" ':' ';
-            $str = '<a href="'.$src.'"><img '.$width.$height.' src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" style="border:0px" /></a>';
+            $str = '<a href="'.$src.'"><img '.$width.$height.' src="'.$src.'" alt="'.s($alt).'" title="'.s($title).'" class="list_picture"/></a>';
         }
 
         return $str;
diff --git a/mod/data/field/radiobutton/mod.html b/mod/data/field/radiobutton/mod.html
index 6d8bef3..a881292 100644
--- a/mod/data/field/radiobutton/mod.html
+++ b/mod/data/field/radiobutton/mod.html
@@ -9,6 +9,6 @@
     </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
-        <td class="c1"><textarea style="width:300px; height:150px;" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
+        <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
     </tr>
 </table>
diff --git a/mod/data/lib.php b/mod/data/lib.php
index 7b139af..edc8e7a 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -244,7 +244,7 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
 
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<label class="accesshide" for="field_'.$this->field->id.'">'.$this->field->description.'</label>';
-        $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
+        $str .= '<input class="basefieldinput" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
         $str .= '</div>';
 
         return $str;
diff --git a/mod/data/styles.css b/mod/data/styles.css
index 4f68465..c2ce0dc 100644
--- a/mod/data/styles.css
+++ b/mod/data/styles.css
@@ -7,6 +7,13 @@
 .path-mod-data-field .c0,
 #page-mod-data-view #sortsearch .c0 {text-align: right;}
 #page-mod-data-view .approve img.icon {width:34px;height:34px;}
+#page-mod-data-view img.list_picture {
+    border:0px;
+}
+
+#page-mod-data-edit .basefieldinput {
+    width:300px;
+}
 
 /** Styles for preset.php **/
 #page-mod-data-preset .presetmapping table {text-align: left;margin-left: auto;margin-right: auto;}
@@ -20,6 +27,10 @@
 .path-mod-data-field .sortdefault select {margin-left: 1em;}
 .path-mod-data-field .fieldname,
 .path-mod-data-field .fielddescription {width:300px;}
+.path-mod-data-field textarea.optionstextarea {
+    width:300px;
+    height:150px;
+}
 
 /** UI Usability Hacks **/
 #page-mod-data-export #notice span {padding:0 10px;}
-- 
1.7.9.5


From 108dd3376c1862e09d9182fcb13e28f43be7a406 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 20 Aug 2012 17:16:15 +0800
Subject: [PATCH 456/903] MDL-31496 mod_data Replacing inline styles for CSS
 classes in search containers

---
 mod/data/lib.php    |   26 ++++++++++----------------
 mod/data/styles.css |   10 ++++++++++
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/mod/data/lib.php b/mod/data/lib.php
index edc8e7a..fc26f78 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -1480,14 +1480,16 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     $pagesizes = array(2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,10=>10,15=>15,
                        20=>20,30=>30,40=>40,50=>50,100=>100,200=>200,300=>300,400=>400,500=>500,1000=>1000);
     echo html_writer::select($pagesizes, 'perpage', $perpage, false, array('id'=>'pref_perpage'));
-    echo '<div id="reg_search" style="display: ';
+
     if ($advanced) {
-        echo 'none';
-    }
-    else {
-        echo 'inline';
+        $regsearchclass = 'search_none';
+        $advancedsearchclass = 'search_inline';
+    } else {
+        $regsearchclass = 'search_inline';
+        $advancedsearchclass = 'search_none';
     }
-    echo ';" >&nbsp;&nbsp;&nbsp;<label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
+    echo '<div id="reg_search" class="' . $regsearchclass . '" >&nbsp;&nbsp;&nbsp;';
+    echo '<label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
     echo '&nbsp;&nbsp;&nbsp;<label for="pref_sortby">'.get_string('sortby').'</label> ';
     // foreach field, print the option
     echo '<select name="sort" id="pref_sortby">';
@@ -1547,15 +1549,7 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     echo '&nbsp;<input type="submit" value="'.get_string('savesettings','data').'" />';
 
     echo '<br />';
-    echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
-
-    if ($advanced) {
-        echo 'inline';
-    }
-    else {
-        echo 'none';
-    }
-    echo ';margin-left:auto;margin-right:auto;" >';
+    echo '<div class="' . $advancedsearchclass . '" id="data_adv_form">';
     echo '<table class="boxaligncenter">';
 
     // print ASC or DESC
@@ -1620,7 +1614,7 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
     echo format_text($newtext, FORMAT_HTML, $options);
     echo '</td></tr>';
 
-    echo '<tr><td colspan="4" style="text-align: center;"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="submit" name="resetadv" value="'.get_string('resetsettings','data').'" /></td></tr>';
+    echo '<tr><td colspan="4"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="submit" name="resetadv" value="'.get_string('resetsettings','data').'" /></td></tr>';
     echo '</table>';
     echo '</div>';
     echo '</div>';
diff --git a/mod/data/styles.css b/mod/data/styles.css
index c2ce0dc..b9636ac 100644
--- a/mod/data/styles.css
+++ b/mod/data/styles.css
@@ -10,6 +10,16 @@
 #page-mod-data-view img.list_picture {
     border:0px;
 }
+#page-mod-data-view div.search_none {
+    display: none;
+}
+#page-mod-data-view div.search_inline {
+    display: inline;
+}
+#page-mod-data-view div#data_adv_form {
+    margin-left:auto;
+    margin-right:auto;
+}
 
 #page-mod-data-edit .basefieldinput {
     width:300px;
-- 
1.7.9.5


From d1e338c98bb02313990ab0e8a25e58bf5c7cc2c0 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 20 Aug 2012 17:17:24 +0800
Subject: [PATCH 457/903] MDL-31496 mod_data Replacing inline styles for CSS
 classes in text inputs

---
 mod/data/field/picture/mod.html  |    8 ++++----
 mod/data/field/textarea/mod.html |    4 ++--
 mod/data/styles.css              |    6 ++++++
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/mod/data/field/picture/mod.html b/mod/data/field/picture/mod.html
index 4b32474..2ea0778 100644
--- a/mod/data/field/picture/mod.html
+++ b/mod/data/field/picture/mod.html
@@ -16,27 +16,27 @@
         <td class="c0"><label for="param1">
             <?php echo get_string('fieldwidthsingleview', 'data');?></label></td>
         <td class="c1">
-            <input style="width:70px;" type="text" name="param1" id="param1" value="<?php if (!empty($this->field->param1)) p($this->field->param1); ?>" />
+            <input class="picturefieldsize" type="text" name="param1" id="param1" value="<?php if (!empty($this->field->param1)) p($this->field->param1); ?>" />
         </td>
     </tr>
     <tr>
         <td class="c0"><label for="param2">
             <?php echo get_string('fieldheightsingleview', 'data');?></label></td>
         <td class="c1">
-            <input style="width:70px;" type="text" name="param2" id="param2" value="<?php if (!empty($this->field->param2)) p($this->field->param2); ?>" />
+            <input class="picturefieldsize" type="text" name="param2" id="param2" value="<?php if (!empty($this->field->param2)) p($this->field->param2); ?>" />
         </td>
     </tr>
     <tr>
         <td class="c0"><label for="param4">
             <?php echo get_string('fieldwidthlistview', 'data');?></label></td>
-        <td class="c1"><input style="width:70px;" type="text" name="param4" id="param4" value="<?php if (!empty($this->field->param4)) p($this->field->param4); ?>" />
+        <td class="c1"><input class="picturefieldsize" type="text" name="param4" id="param4" value="<?php if (!empty($this->field->param4)) p($this->field->param4); ?>" />
         </td>
     </tr>
     <tr>
         <td class="c0"><label for="param5">
             <?php echo get_string('fieldheightlistview', 'data');?></label></td>
         <td class="c1">
-            <input style="width:70px;" type="text" name="param5" id="param5" value="<?php if (!empty($this->field->param5)) p($this->field->param5); ?>" />
+            <input class="picturefieldsize" type="text" name="param5" id="param5" value="<?php if (!empty($this->field->param5)) p($this->field->param5); ?>" />
         </td>
     </tr>
     <tr>
diff --git a/mod/data/field/textarea/mod.html b/mod/data/field/textarea/mod.html
index fb68424..e75365a 100644
--- a/mod/data/field/textarea/mod.html
+++ b/mod/data/field/textarea/mod.html
@@ -14,7 +14,7 @@
         <td class="c0"><label for="param2">
             <?php echo get_string('fieldwidth', 'data'); ?></label></td>
         <td class="c1">
-            <input style="width:50px;" type="text" name="param2" id="param2" value=
+            <input class="textareafieldsize" type="text" name="param2" id="param2" value=
             <?php
                 if (empty($this->field->param2)) {
                     echo('"60"');
@@ -28,7 +28,7 @@
         <td class="c0"><label for="param3">
             <?php echo get_string('fieldheight', 'data'); ?></label></td>
         <td class="c1">
-            <input style="width:50px;" type="text" name="param3" id="param3" value=
+            <input class="textareafieldsize" type="text" name="param3" id="param3" value=
             <?php
                 if (empty($this->field->param3)) {
                     echo('"35"');
diff --git a/mod/data/styles.css b/mod/data/styles.css
index b9636ac..ba002fd 100644
--- a/mod/data/styles.css
+++ b/mod/data/styles.css
@@ -41,6 +41,12 @@
     width:300px;
     height:150px;
 }
+.path-mod-data-field input.textareafieldsize {
+    width:50px;
+}
+.path-mod-data-field input.picturefieldsize {
+    width:70px;
+}
 
 /** UI Usability Hacks **/
 #page-mod-data-export #notice span {padding:0 10px;}
-- 
1.7.9.5


From b16b42e9e259dc9900af6ade4bf089a15f1799fe Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 20 Aug 2012 17:24:34 +0800
Subject: [PATCH 458/903] MDL-31496 mod_data Replacing inline styles for CSS
 classes in templates and browse view

---
 mod/data/field/latlong/field.class.php |    9 +++++----
 mod/data/styles.css                    |    7 ++++++-
 mod/data/templates.php                 |   14 +++++++-------
 3 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/mod/data/field/latlong/field.class.php b/mod/data/field/latlong/field.class.php
index a6f6889..e941699 100644
--- a/mod/data/field/latlong/field.class.php
+++ b/mod/data/field/latlong/field.class.php
@@ -130,7 +130,6 @@ class data_field_latlong extends data_field_base {
             } else {
                 $compasslong = sprintf('%01.4f', $long) . '°E';
             }
-            $str = '<form style="display:inline;">';
 
             // Now let's create the jump-to-services link
             $servicesshown = explode(',', $this->field->param1);
@@ -148,10 +147,11 @@ class data_field_latlong extends data_field_base {
             );
 
             if(sizeof($servicesshown)==1 && $servicesshown[0]) {
-                $str .= " <a href='"
+                $str = " <a href='"
                           . str_replace(array_keys($urlreplacements), array_values($urlreplacements), $this->linkoutservices[$servicesshown[0]])
                           ."' title='$servicesshown[0]'>$compasslat, $compasslong</a>";
             } elseif (sizeof($servicesshown)>1) {
+                $str = '<form id="latlongfieldbrowse">';
                 $str .= "$compasslat, $compasslong\n";
                 $str .= "<label class='accesshide' for='jumpto'>". get_string('jumpto') ."</label>";
                 $str .= "<select id='jumpto' name='jumpto'>";
@@ -164,10 +164,11 @@ class data_field_latlong extends data_field_base {
                 // NB! If you are editing this, make sure you don't break the javascript reference "previousSibling"
                 //   which allows the "Go" button to refer to the drop-down selector.
                 $str .= "\n</select><input type='button' value='" . get_string('go') . "' onclick='if(previousSibling.value){self.location=previousSibling.value}'/>";
+                $str .= '</form>';
             } else {
-                $str.= "$compasslat, $compasslong";
+                $str = "$compasslat, $compasslong";
             }
-            $str.= '</form>';
+
             return $str;
         }
         return false;
diff --git a/mod/data/styles.css b/mod/data/styles.css
index ba002fd..600c79d 100644
--- a/mod/data/styles.css
+++ b/mod/data/styles.css
@@ -13,7 +13,8 @@
 #page-mod-data-view div.search_none {
     display: none;
 }
-#page-mod-data-view div.search_inline {
+#page-mod-data-view div.search_inline,
+#page-mod-data-view form#latlongfieldbrowse {
     display: inline;
 }
 #page-mod-data-view div#data_adv_form {
@@ -57,6 +58,10 @@
 .mod-data-default-template .template-token {text-align:left;}
 .mod-data-default-template .controls {text-align:center;}
 .mod-data-default-template searchcontrols {text-align:right;}
+#page-mod-data-templates td.save_template,
+#page-mod-data-templates .template_heading {
+     text-align:center;
+}
 
 .dir-rtl .mod-data-default-template .template-field {text-align:left;}
 .dir-rtl .mod-data-default-template .template-token {text-align:right;}
diff --git a/mod/data/templates.php b/mod/data/templates.php
index 404f28d..953fc89 100644
--- a/mod/data/templates.php
+++ b/mod/data/templates.php
@@ -141,7 +141,7 @@ if (($mytemplate = data_submitted()) && confirm_sesskey()) {
         }
     }
 } else {
-    echo '<div class="littleintro" style="text-align:center">'.get_string('header'.$mode,'data').'</div>';
+    echo '<div class="template_heading">'.get_string('header'.$mode,'data').'</div>';
 }
 
 /// If everything is empty then generate some defaults
@@ -198,7 +198,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</td>';
     echo '<td>';
-    echo '<div style="text-align:center"><label for="edit-listtemplateheader">'.get_string('header','data').'</label></div>';
+    echo '<div class="template_heading"><label for="edit-listtemplateheader">'.get_string('header','data').'</label></div>';
 
     $field = 'listtemplateheader';
     $editor->use_editor($field, $options);
@@ -290,9 +290,9 @@ echo '</td>';
 
 echo '<td valign="top">';
 if ($mode == 'listtemplate'){
-    echo '<div style="text-align:center"><label for="edit-template">'.get_string('multientry','data').'</label></div>';
+    echo '<div class="template_heading"><label for="edit-template">'.get_string('multientry','data').'</label></div>';
 } else {
-    echo '<div style="text-align:center"><label for="edit-template">'.get_string($mode,'data').'</label></div>';
+    echo '<div class="template_heading"><label for="edit-template">'.get_string($mode,'data').'</label></div>';
 }
 
 $field = 'template';
@@ -305,7 +305,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</td>';
     echo '<td>';
-    echo '<div style="text-align:center"><label for="edit-listtemplatefooter">'.get_string('footer','data').'</label></div>';
+    echo '<div class="template_heading"><label for="edit-listtemplatefooter">'.get_string('footer','data').'</label></div>';
 
     $field = 'listtemplatefooter';
     $editor->use_editor($field, $options);
@@ -316,7 +316,7 @@ if ($mode == 'listtemplate'){
     echo '<tr>';
     echo '<td>&nbsp;</td>';
     echo '<td>';
-    echo '<div style="text-align:center"><label for="edit-rsstitletemplate">'.get_string('rsstitletemplate','data').'</label></div>';
+    echo '<div class="template_heading"><label for="edit-rsstitletemplate">'.get_string('rsstitletemplate','data').'</label></div>';
 
     $field = 'rsstitletemplate';
     $editor->use_editor($field, $options);
@@ -325,7 +325,7 @@ if ($mode == 'listtemplate'){
     echo '</tr>';
 }
 
-echo '<tr><td style="text-align:center" colspan="2">';
+echo '<tr><td class="save_template" colspan="2">';
 echo '<input type="submit" value="'.get_string('savetemplate','data').'" />&nbsp;';
 
 echo '</td></tr></table>';
-- 
1.7.9.5


From 8c74ab8623ee264b3013de88cea39be8de31ae02 Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Fri, 17 Aug 2012 12:34:16 +0800
Subject: [PATCH 459/903] MDL-34887: Add hyperlinks to names in the
 Assignment's grading table

---
 mod/assign/gradingtable.php |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index be0eb3d..fb5e4ff 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -287,13 +287,15 @@ class assign_grading_table extends table_sql implements renderable {
     }
 
     /**
-     * Format a user record for display (don't link to profile)
+     * Format a user record for display (link to profile)
      *
      * @param stdClass $row
      * @return string
      */
     function col_fullname($row) {
-        return fullname($row);
+        $courseid = $this->assignment->get_course()->id;
+        $link= new moodle_url('/user/view.php', array('id' =>$row->id, 'course'=>$courseid));
+        return $this->output->action_link($link, fullname($row));
     }
 
     /**
-- 
1.7.9.5


From 8172f3b2d328d27c0ebe99ef4d2f71d193e5fcf1 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 21 Aug 2012 11:05:58 +0800
Subject: [PATCH 460/903] MDL-34808 qformat_examview - increment version

---
 question/format/examview/version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/format/examview/version.php b/question/format/examview/version.php
index d6686e1..af82376 100644
--- a/question/format/examview/version.php
+++ b/question/format/examview/version.php
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component = 'qformat_examview';
-$plugin->version   = 2012061700;
+$plugin->version   = 2012061701;
 
 $plugin->requires  = 2012061700;
 
-- 
1.7.9.5


From 35870a76db474b0e0aa53d862b2a327f4bef5d95 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Tue, 21 Aug 2012 00:24:55 -0400
Subject: [PATCH 461/903] MDL-34363 gradebook Adding check to prevent
 incorrect override when a blank feedback is
 submitted.

---
 grade/report/grader/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/report/grader/lib.php b/grade/report/grader/lib.php
index ea8f076..3dbac53 100644
--- a/grade/report/grader/lib.php
+++ b/grade/report/grader/lib.php
@@ -225,7 +225,7 @@ class grade_report_grader extends grade_report {
                 $changedgrades = true;
 
             } else if ($datatype === 'feedback') {
-                if ($oldvalue->feedback === $postedvalue) {
+                if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
                     continue;
                 }
             }
-- 
1.7.9.5


From 192372056678abf70139166510e75b51e84abcf0 Mon Sep 17 00:00:00 2001
From: Juho Viitasalo <juho.viitasalo@uef.fi>
Date: Fri, 9 Mar 2012 13:33:09 +0200
Subject: [PATCH 462/903] Changed two notification to output correctly

---
 user/profile.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/user/profile.php b/user/profile.php
index 9dafdd9..b5cb4eb 100644
--- a/user/profile.php
+++ b/user/profile.php
@@ -61,7 +61,7 @@ $user = $DB->get_record('user', array('id' => $userid));
 if ($user->deleted) {
     $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
     echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('userdeleted'));
+    echo $OUTPUT->notification(get_string('userdeleted'));
     echo $OUTPUT->footer();
     die;
 }
@@ -82,7 +82,7 @@ if (!$currentuser &&
     $PAGE->set_url('/user/profile.php', array('id'=>$userid));
     $PAGE->navbar->add($struser);
     echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('usernotavailable', 'error'));
+    echo $OUTPUT->notification(get_string('usernotavailable', 'error'));
     echo $OUTPUT->footer();
     exit;
 }
-- 
1.7.9.5


From d7b7aff00480a0a65f744d48d8f9f025c9319e6c Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 21 Aug 2012 12:05:52 +0100
Subject: [PATCH 463/903] MDL-34733 quiz 'secure' mode: finish review link
 broken in previews

Here, we use a nasty hack to fix the problem on stable branches without
an API change.
---
 mod/quiz/renderer.php |   14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php
index 820e711..2d448b3 100644
--- a/mod/quiz/renderer.php
+++ b/mod/quiz/renderer.php
@@ -229,7 +229,19 @@ class mod_quiz_renderer extends plugin_renderer_base {
      * @param $url contains a url for the review link
      */
     public function finish_review_link($url) {
-        if ($this->page->pagelayout == 'popup') {
+
+        // This is an ugly hack to fix MDL-34733 without changing the renderer API.
+        global $attemptobj;
+        if (!empty($attemptobj)) {
+            // I think that every page in standard Moodle that ends up calling
+            // this method will actually end up coming down this branch.
+            $inpopup = $attemptobj->get_access_manager(time())->attempt_must_be_in_popup();
+        } else {
+            // Else fall back to old (not very good) heuristic.
+            $inpopup = $this->page->pagelayout == 'popup';
+        }
+
+        if ($inpopup) {
             // In a 'secure' popup window.
             $this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button',
                     array($url), quiz_get_js_module());
-- 
1.7.9.5


From fa0ed51c0afd17a47c64470b987fa7b1e6135574 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 21 Aug 2012 17:58:29 +0100
Subject: [PATCH 464/903] MDL-35000 quiz: Complete activity report broken by
 bad require.

Fix the stupid error that caused this. Also, make all the other
require_once calls in the file consistent.
---
 mod/quiz/lib.php |   21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 397869d..993ca98 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -373,7 +373,7 @@ function quiz_has_grades($quiz) {
  */
 function quiz_user_outline($course, $user, $mod, $quiz) {
     global $DB, $CFG;
-    require_once("$CFG->libdir/gradelib.php");
+    require_once($CFG->libdir . '/gradelib.php');
     $grades = grade_get_grades($course->id, 'mod', 'quiz', $quiz->id, $user->id);
 
     if (empty($grades->items[0]->grades)) {
@@ -411,7 +411,7 @@ function quiz_user_outline($course, $user, $mod, $quiz) {
 function quiz_user_complete($course, $user, $mod, $quiz) {
     global $DB, $CFG, $OUTPUT;
     require_once($CFG->libdir . '/gradelib.php');
-    require_once($CFG->libdir . '/mod/quiz/locallib.php');
+    require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 
     $grades = grade_get_grades($course->id, 'mod', 'quiz', $quiz->id, $user->id);
     if (!empty($grades->items[0]->grades)) {
@@ -603,7 +603,7 @@ function quiz_format_question_grade($quiz, $grade) {
  */
 function quiz_update_grades($quiz, $userid = 0, $nullifnone = true) {
     global $CFG, $DB;
-    require_once($CFG->libdir.'/gradelib.php');
+    require_once($CFG->libdir . '/gradelib.php');
 
     if ($quiz->grade == 0) {
         quiz_grade_item_update($quiz);
@@ -661,7 +661,7 @@ function quiz_upgrade_grades() {
 function quiz_grade_item_update($quiz, $grades = null) {
     global $CFG, $OUTPUT;
     require_once($CFG->dirroot . '/mod/quiz/locallib.php');
-    require_once($CFG->libdir.'/gradelib.php');
+    require_once($CFG->libdir . '/gradelib.php');
 
     if (array_key_exists('cmidnumber', $quiz)) { // May not be always present.
         $params = array('itemname' => $quiz->name, 'idnumber' => $quiz->cmidnumber);
@@ -792,7 +792,7 @@ function quiz_refresh_events($courseid = 0) {
 function quiz_get_recent_mod_activity(&$activities, &$index, $timestart,
         $courseid, $cmid, $userid = 0, $groupid = 0) {
     global $CFG, $COURSE, $USER, $DB;
-    require_once('locallib.php');
+    require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 
     if ($COURSE->id == $courseid) {
         $course = $COURSE;
@@ -1308,15 +1308,13 @@ function quiz_reset_gradebook($courseid, $type='') {
  */
 function quiz_reset_userdata($data) {
     global $CFG, $DB;
-    require_once($CFG->libdir.'/questionlib.php');
+    require_once($CFG->libdir . '/questionlib.php');
 
     $componentstr = get_string('modulenameplural', 'quiz');
     $status = array();
 
     // Delete attempts.
     if (!empty($data->reset_quiz_attempts)) {
-        require_once($CFG->libdir . '/questionlib.php');
-
         question_engine::delete_questions_usage_by_activities(new qubaid_join(
                 '{quiz_attempts} quiza JOIN {quiz} quiz ON quiza.quiz = quiz.id',
                 'quiza.uniqueid', 'quiz.course = :quizcourseid',
@@ -1364,8 +1362,7 @@ function quiz_reset_userdata($data) {
  */
 function quiz_check_file_access($attemptuniqueid, $questionid, $context = null) {
     global $USER, $DB, $CFG;
-    require_once(dirname(__FILE__).'/attemptlib.php');
-    require_once(dirname(__FILE__).'/locallib.php');
+    require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 
     $attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $attemptuniqueid));
     $attemptobj = quiz_attempt::create($attempt->id);
@@ -1570,7 +1567,7 @@ function quiz_supports($feature) {
  */
 function quiz_get_extra_capabilities() {
     global $CFG;
-    require_once($CFG->libdir.'/questionlib.php');
+    require_once($CFG->libdir . '/questionlib.php');
     $caps = question_get_all_capabilities();
     $caps[] = 'moodle/site:accessallgroups';
     return $caps;
@@ -1599,7 +1596,7 @@ function quiz_extend_navigation($quiznode, $course, $module, $cm) {
     }
 
     if (has_any_capability(array('mod/quiz:viewreports', 'mod/quiz:grade'), $context)) {
-        require_once($CFG->dirroot.'/mod/quiz/report/reportlib.php');
+        require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
         $reportlist = quiz_report_list($context);
 
         $url = new moodle_url('/mod/quiz/report.php',
-- 
1.7.9.5


From 2b062ed6a637aa5b753f080f2f40af0b150550cb Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 22 Aug 2012 09:01:54 +1200
Subject: [PATCH 465/903] MDL-34994 mod_choice: fix restore of user responses
 - use correct optionid

---
 .../backup/moodle2/restore_choice_stepslib.php     |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mod/choice/backup/moodle2/restore_choice_stepslib.php b/mod/choice/backup/moodle2/restore_choice_stepslib.php
index 75a56f8..337eb7f 100644
--- a/mod/choice/backup/moodle2/restore_choice_stepslib.php
+++ b/mod/choice/backup/moodle2/restore_choice_stepslib.php
@@ -80,10 +80,9 @@ class restore_choice_activity_structure_step extends restore_activity_structure_
         global $DB;
 
         $data = (object)$data;
-        $oldid = $data->id;
 
         $data->choiceid = $this->get_new_parentid('choice');
-        $data->optionid = $this->get_mappingid('choice_option', $oldid);
+        $data->optionid = $this->get_mappingid('choice_option', $data->optionid);
         $data->userid = $this->get_mappingid('user', $data->userid);
         $data->timemodified = $this->apply_date_offset($data->timemodified);
 
-- 
1.7.9.5


From bae745aa57cfd67502604db98c77c5690298cf19 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 22 Aug 2012 01:48:45 +0200
Subject: [PATCH 466/903] MDL-34866 whitespace fix

---
 admin/settings/courses.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/admin/settings/courses.php b/admin/settings/courses.php
index 01b37a2..f07107c 100644
--- a/admin/settings/courses.php
+++ b/admin/settings/courses.php
@@ -50,8 +50,8 @@ if ($hassiteconfig
     $choices = array();
     $choices[COURSE_DISPLAY_SINGLEPAGE] = new lang_string('coursedisplay_single');
     $choices[COURSE_DISPLAY_MULTIPAGE] = new lang_string('coursedisplay_multi');
-    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));        
-    
+    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));
+
     $temp->add(new admin_setting_heading('groups', new lang_string('groups', 'group'), ''));
     $choices = array();
     $choices[NOGROUPS] = new lang_string('groupsnone', 'group');
-- 
1.7.9.5


From a4241511ed3c186aa3866a26b43a13e5406a0247 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 22 Aug 2012 10:00:37 +0800
Subject: [PATCH 467/903] MDL-34870 enrol_cohort - don't need to do useless
 work

---
 enrol/cohort/lib.php |    9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/enrol/cohort/lib.php b/enrol/cohort/lib.php
index 49d8fcb..cfa352c 100644
--- a/enrol/cohort/lib.php
+++ b/enrol/cohort/lib.php
@@ -121,14 +121,7 @@ class enrol_cohort_plugin extends enrol_plugin {
      * @return void
      */
     public function course_updated($inserted, $course, $data) {
-        global $CFG;
-
-        if (!$inserted) {
-            // Let's not sync cohorts anytime a course is updated...
-        } else {
-            // cohorts are never inserted automatically
-        }
-
+        // It turns out there is no need for cohorts to deal with this hook, see MDL-34870.
     }
 
     /**
-- 
1.7.9.5


From f813d9929686a2c3d1adec80fb23d74dd62e925d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 22 Aug 2012 08:08:24 +0200
Subject: [PATCH 468/903] MDL-34864 fix role names regression

---
 enrol/category/locallib.php |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/enrol/category/locallib.php b/enrol/category/locallib.php
index 2c16f766..c9687fa 100644
--- a/enrol/category/locallib.php
+++ b/enrol/category/locallib.php
@@ -286,7 +286,10 @@ function enrol_category_sync_full($verbose = false) {
         }
         return 0;
     }
-    $rolenames = role_fix_names($roles, null, ROLENAME_SHORT, true);
+    $rolenames = array();
+    foreach($roles as $role) {
+        $rolenames[$role->id] = $role->shortname;
+    }
     if ($verbose) {
         mtrace('Synchronising category enrolments for roles: '.implode(', ', $rolenames).'...');
     }
-- 
1.7.9.5


From 996e735693ab62ed1b12090687c3e33f2936c683 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 22 Aug 2012 09:47:44 +0200
Subject: [PATCH 469/903] MDL-35010 availability: fix sometimes missing
 fieldset

---
 course/editsection_form.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/editsection_form.php b/course/editsection_form.php
index 9f33f83..73723af 100644
--- a/course/editsection_form.php
+++ b/course/editsection_form.php
@@ -38,6 +38,7 @@ class editsection_form extends moodleform {
         $course = $this->_customdata['course'];
 
         if (!empty($CFG->enableavailability)) {
+            $mform->addElement('header', '', get_string('availabilityconditions', 'condition'));
             // Grouping conditions - only if grouping is enabled at site level
             if (!empty($CFG->enablegroupmembersonly)) {
                 $options = array();
@@ -49,7 +50,6 @@ class editsection_form extends moodleform {
                                 $grouping->name, true, array('context' => $context));
                     }
                 }
-                $mform->addElement('header', '', get_string('availabilityconditions', 'condition'));
                 $mform->addElement('select', 'groupingid', get_string('groupingsection', 'group'), $options);
                 $mform->addHelpButton('groupingid', 'groupingsection', 'group');
             }
-- 
1.7.9.5


From 29beeefc70b720ac6cac57a8a0919193d44950f0 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 22 Aug 2012 16:37:36 +0800
Subject: [PATCH 470/903] Revert "MDL-34444 course: show section availability
 info"

Turns out this change was just wrong, we shouldn't be allowing linking
to unaavilable sections. Just show the availability information on the
'index page'

This reverts commit 87a31bb5d8fedd4447cf99cef13c5dd367c3ea3e.
---
 course/view.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/view.php b/course/view.php
index 028a3f4..ad495dd 100644
--- a/course/view.php
+++ b/course/view.php
@@ -105,7 +105,7 @@
         $coursesections = $modinfo->get_section_info($section, MUST_EXIST);
 
         // Check user is allowed to see it.
-        if (!$coursesections->uservisible && !empty($section->availableinfo)) {
+        if (!$coursesections->uservisible) {
             // Note: We actually already know they don't have this capability
             // or uservisible would have been true; this is just to get the
             // correct error message shown.
-- 
1.7.9.5


From ccce6a7e3343f999b89a86a5c83d97866c4e973d Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 22 Aug 2012 16:38:15 +0800
Subject: [PATCH 471/903] MDL-34444 course - don't show to 'unavaibile'
 sections title

Instead we just show the availability info in the index page,
this makes the navigation etc much simpler.
---
 course/format/renderer.php |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index 165aea6..c51506c 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -291,9 +291,11 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o .= html_writer::tag('div', '', array('class' => 'right side'));
         $o .= html_writer::start_tag('div', array('class' => 'content'));
 
-        $title = html_writer::tag('a', get_section_name($course, $section),
-                array('href' => course_get_url($course, $section->section), 'class' => $linkclasses));
-        $o .= $this->output->heading($title, 3, 'section-title');
+        if ($section->uservisible) {
+            $title = html_writer::tag('a', get_section_name($course, $section),
+                    array('href' => course_get_url($course, $section->section), 'class' => $linkclasses));
+            $o .= $this->output->heading($title, 3, 'section-title');
+        }
 
         $o.= html_writer::start_tag('div', array('class' => 'summarytext'));
         $o.= $this->format_summary_text($section);
-- 
1.7.9.5


From e1269d87d426c3cb4f726354e83b0e92cc06aece Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 22 Aug 2012 17:10:38 +0800
Subject: [PATCH 472/903] MDL-34444 - actually display the title, just don't
 link it..

Don't worry, i'm going on holiday, so i'll be away from this git repo
for a while to prevent any more mess.
---
 course/format/renderer.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index c51506c..f53c33d 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -291,11 +291,12 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o .= html_writer::tag('div', '', array('class' => 'right side'));
         $o .= html_writer::start_tag('div', array('class' => 'content'));
 
+        $title = get_section_name($course, $section);
         if ($section->uservisible) {
-            $title = html_writer::tag('a', get_section_name($course, $section),
+            $title = html_writer::tag('a', $title,
                     array('href' => course_get_url($course, $section->section), 'class' => $linkclasses));
-            $o .= $this->output->heading($title, 3, 'section-title');
         }
+        $o .= $this->output->heading($title, 3, 'section-title');
 
         $o.= html_writer::start_tag('div', array('class' => 'summarytext'));
         $o.= $this->format_summary_text($section);
-- 
1.7.9.5


From 9832fde1c0dc7b18cff4e9357efbefaf18a7d9f6 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Wed, 22 Aug 2012 15:19:54 +0200
Subject: [PATCH 473/903] MDL-34738 fix for the problem found during testing :
 dat files not accepted on some servers

---
 question/format/blackboard/format.php |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/question/format/blackboard/format.php b/question/format/blackboard/format.php
index 1626489..88e0130 100644
--- a/question/format/blackboard/format.php
+++ b/question/format/blackboard/format.php
@@ -43,6 +43,18 @@ class qformat_blackboard extends qformat_based_on_xml {
         return true;
     }
 
+    /**
+     * Check if the given file is capable of being imported by this plugin.
+     * As {@link file_storage::mimetype()} now uses finfo PHP extension if available,
+     * the value returned by $file->get_mimetype for a .dat file is not the same on all servers.
+     * So if the parent method fails we must use mimeinfo on the filename.
+     * @param stored_file $file the file to check
+     * @return bool whether this plugin can import the file
+     */
+    public function can_import_file($file) {
+        return parent::can_import_file($file) || mimeinfo('type', $file->get_filename()) == $this->mime_type();
+    }
+
     public function mime_type() {
         return mimeinfo('type', '.dat');
     }
-- 
1.7.9.5


From 49e77191ccf50cd3d205e69bd6f1604fed023461 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 22 Aug 2012 22:02:48 +0100
Subject: [PATCH 474/903] MDL-34430 qtype essay: upgrade from MDL-31393 needs
 a progress bar.

---
 question/type/essay/db/upgrade.php |   68 +++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 29 deletions(-)

diff --git a/question/type/essay/db/upgrade.php b/question/type/essay/db/upgrade.php
index 0441751..762c0c0 100644
--- a/question/type/essay/db/upgrade.php
+++ b/question/type/essay/db/upgrade.php
@@ -41,41 +41,51 @@ function xmldb_qtype_essay_upgrade($oldversion) {
     // Put any upgrade step following this
 
     if ($oldversion < 2011102701) {
-        // In Moodle <= 2.0 essay had both question.generalfeedback and question_answers.feedback.
-        // This was silly, and in Moodel >= 2.1 only question.generalfeedback. To avoid
-        // dataloss, we concatenate question_answers.feedback onto the end of question.generalfeedback.
-        $toupdate = $DB->get_recordset_sql("
-                SELECT q.id,
-                       q.generalfeedback,
-                       q.generalfeedbackformat,
-                       qa.feedback,
-                       qa.feedbackformat
-
+        $sql = "
                   FROM {question} q
                   JOIN {question_answers} qa ON qa.question = q.id
 
                  WHERE q.qtype = 'essay'
-                   AND " . $DB->sql_isnotempty('question_answers', 'feedback', false, true));
-
-        foreach ($toupdate as $data) {
-            upgrade_set_timeout(60);
-            if ($data->generalfeedbackformat == $data->feedbackformat) {
-                $DB->set_field('question', 'generalfeedback',
-                        $data->generalfeedback . $data->feedback,
-                        array('id' => $data->id));
-
-            } else {
-                $newdata = new stdClass();
-                $newdata->id = $data->id;
-                $newdata->generalfeedback =
-                        qtype_essay_convert_to_html($data->generalfeedback, $data->generalfeedbackformat) .
-                        qtype_essay_convert_to_html($data->feedback,        $data->feedbackformat);
-                $newdata->generalfeedbackformat = FORMAT_HTML;
-                $DB->update_record('question', $newdata);
+                   AND " . $DB->sql_isnotempty('question_answers', 'feedback', false, true);
+        // In Moodle <= 2.0 essay had both question.generalfeedback and question_answers.feedback.
+        // This was silly, and in Moodel >= 2.1 only question.generalfeedback. To avoid
+        // dataloss, we concatenate question_answers.feedback onto the end of question.generalfeedback.
+        $count = $DB->count_records_sql("
+                SELECT COUNT(1) $sql");
+        if ($count) {
+            $progressbar = new progress_bar('essay23', 500, true);
+            $done = 0;
+
+            $toupdate = $DB->get_recordset_sql("
+                    SELECT q.id,
+                           q.generalfeedback,
+                           q.generalfeedbackformat,
+                           qa.feedback,
+                           qa.feedbackformat
+                    $sql");
+
+            foreach ($toupdate as $data) {
+                $progressbar->update($done, $count, "Updating essay feedback ($done/$count).");
+                upgrade_set_timeout(60);
+                if ($data->generalfeedbackformat == $data->feedbackformat) {
+                    $DB->set_field('question', 'generalfeedback',
+                            $data->generalfeedback . $data->feedback,
+                            array('id' => $data->id));
+
+                } else {
+                    $newdata = new stdClass();
+                    $newdata->id = $data->id;
+                    $newdata->generalfeedback =
+                            qtype_essay_convert_to_html($data->generalfeedback, $data->generalfeedbackformat) .
+                            qtype_essay_convert_to_html($data->feedback,        $data->feedbackformat);
+                    $newdata->generalfeedbackformat = FORMAT_HTML;
+                    $DB->update_record('question', $newdata);
+                }
             }
-        }
 
-        $toupdate->close();
+            $progressbar->update($count, $count, "Updating essay feedback complete!");
+            $toupdate->close();
+        }
 
         // Essay savepoint reached.
         upgrade_plugin_savepoint(true, 2011102701, 'qtype', 'essay');
-- 
1.7.9.5


From 4b7b1aae4d4a7304a07ea434cf8603b6d69780b0 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 23 Aug 2012 02:04:13 +0200
Subject: [PATCH 475/903] MDL-31957 Course reset: Add missing global

---
 lib/completionlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/completionlib.php b/lib/completionlib.php
index cd07c45..54e9160 100644
--- a/lib/completionlib.php
+++ b/lib/completionlib.php
@@ -718,7 +718,7 @@ class completion_info {
      * Used by course reset page.
      */
     public function delete_all_completion_data() {
-        global $DB;
+        global $DB, $SESSION;
 
         // Delete from database.
         $DB->delete_records_select('course_modules_completion',
-- 
1.7.9.5


From 23bb88d28d4bf3da0f31c23c51b0417426d7d8bc Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 23 Aug 2012 00:34:21 +0000
Subject: [PATCH 476/903] Automatically generated installer lang files

---
 install/lang/ko/install.php |    1 +
 install/lang/pl/admin.php   |    8 ++++----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/install/lang/ko/install.php b/install/lang/ko/install.php
index c8574b5..a395a57 100644
--- a/install/lang/ko/install.php
+++ b/install/lang/ko/install.php
@@ -40,6 +40,7 @@ $string['databasehost'] = '데이터베이스 호스트';
 $string['databasename'] = '데이터베이스 명칭';
 $string['databasetypehead'] = '데이터베이스 드라이버 선택';
 $string['dataroot'] = '데이타 경로';
+$string['datarootpermission'] = '데이터 디렉토리 권한';
 $string['dbprefix'] = '테이블 접두어';
 $string['dirroot'] = '무들 디렉토리';
 $string['environmenthead'] = '구동환경을 점검합니다...';
diff --git a/install/lang/pl/admin.php b/install/lang/pl/admin.php
index 61786be..31980bd 100644
--- a/install/lang/pl/admin.php
+++ b/install/lang/pl/admin.php
@@ -34,11 +34,11 @@ $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 't';
 $string['cliincorrectvalueerror'] = 'Błąd, niepoprawna wartość "{$a->value}" dla "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Nieprawidłowa wartość, spróbuj ponownie';
-$string['clitypevalue'] = 'typ wartości';
-$string['clitypevaluedefault'] = 'typ wartości, naciśnij Enter, aby użyć wartości domyślnej ({$a})';
-$string['cliunknowoption'] = 'Nieznana opcja:
+$string['clitypevalue'] = 'wartość typu';
+$string['clitypevaluedefault'] = 'Typ wartości, naciśnij Enter, aby użyć wartości domyślnej ({$a})';
+$string['cliunknowoption'] = 'Nieznane opcje:
   {$a}
-Proszę użyć pomocy.';
+Proszę użyć opcji --help.';
 $string['cliyesnoprompt'] = 'wpisz y (czyli tak) lub n (czyli nie)';
 $string['environmentrequireinstall'] = 'jest niezbędnę, żeby było zainstalowane/włączone';
 $string['environmentrequireversion'] = 'wersja {$a->needed} jest niezbędna a ty używasz wersji {$a->current}';
-- 
1.7.9.5


From 78c2fa5cab8737f9481909e3f7cbdf782d36fcb8 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 21 Aug 2012 11:58:13 +0800
Subject: [PATCH 477/903] MDL-30022 message: made the messaging history
 display code able to deal with multiple messages
 with the same timecreated value

---
 message/lib.php |   35 +++++++++++------------------------
 1 file changed, 11 insertions(+), 24 deletions(-)

diff --git a/message/lib.php b/message/lib.php
index 1e759d6..5263217 100644
--- a/message/lib.php
+++ b/message/lib.php
@@ -749,30 +749,16 @@ function message_get_recent_conversations($user, $limitfrom=0, $limitto=100) {
         }
     }
 
-    //Sort the conversations. This is a bit complicated as we need to sort by $conversation->timecreated
-    //and there may be multiple conversations with the same timecreated value.
-    //The conversations array contains both read and unread messages (different tables) so sorting by ID won't work
-    usort($conversations, "conversationsort");
+    // Sort the conversations by $conversation->timecreated, newest to oldest
+    // There may be multiple conversations with the same timecreated
+    // The conversations array contains both read and unread messages (different tables) so sorting by ID won't work
+    $result = collatorlib::asort_objects_by_property($conversations, 'timecreated', collatorlib::SORT_NUMERIC);
+    $conversations = array_reverse($conversations);
 
     return $conversations;
 }
 
 /**
- * Sort function used to order conversations
- *
- * @param object $a A conversation object
- * @param object $b A conversation object
- * @return integer
- */
-function conversationsort($a, $b)
-{
-    if ($a->timecreated == $b->timecreated) {
-        return 0;
-    }
-    return ($a->timecreated > $b->timecreated) ? -1 : 1;
-}
-
-/**
  * Get the users recent event notifications
  *
  * @param object $user the current user
@@ -1804,7 +1790,7 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
                                                     array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
                                                     "timecreated $sort", '*', 0, $limitnum)) {
         foreach ($messages_read as $message) {
-            $messages[$message->timecreated] = $message;
+            $messages[] = $message;
         }
     }
     if ($messages_new =  $DB->get_records_select('message', "((useridto = ? AND useridfrom = ?) OR
@@ -1812,15 +1798,16 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
                                                     array($user1->id, $user2->id, $user2->id, $user1->id, $user1->id),
                                                     "timecreated $sort", '*', 0, $limitnum)) {
         foreach ($messages_new as $message) {
-            $messages[$message->timecreated] = $message;
+            $messages[] = $message;
         }
     }
 
+    $result = collatorlib::asort_objects_by_property($messages, 'timecreated', collatorlib::SORT_NUMERIC);
+
     //if we only want the last $limitnum messages
-    ksort($messages);
     $messagecount = count($messages);
-    if ($limitnum>0 && $messagecount>$limitnum) {
-        $messages = array_slice($messages, $messagecount-$limitnum, $limitnum, true);
+    if ($limitnum > 0 && $messagecount > $limitnum) {
+        $messages = array_slice($messages, $messagecount - $limitnum, $limitnum, true);
     }
 
     return $messages;
-- 
1.7.9.5


From bac15e5782256c66ebeaff9aa684f016b287474e Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 23 Aug 2012 19:25:40 +0200
Subject: [PATCH 478/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index d362bf1..2f379da 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.10;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.11;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120816)'; // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120823)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 35a95edba4d7ae66400b7cf6df04997a4acccf91 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 23 Aug 2012 00:00:27 +0100
Subject: [PATCH 479/903] MDL-31244, MDL-25063 algebra filter: fix common
 false positives.

There are two well-known cases where the algebra filter messes up input
that is obviously not meant for the algebra filter:

1. Copy and paste of unified diffs.

2. @@PLUGINFILE@@ tokens in the HTML that are due to be replaced by the
files API.

This fix detects these two cases, and just stops the algebra filter from
replacing them.
---
 filter/algebra/filter.php            |   19 +++++--
 filter/algebra/tests/filter_test.php |   90 ++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 5 deletions(-)
 create mode 100644 filter/algebra/tests/filter_test.php

diff --git a/filter/algebra/filter.php b/filter/algebra/filter.php
index 54ffaff..def6b44 100644
--- a/filter/algebra/filter.php
+++ b/filter/algebra/filter.php
@@ -89,7 +89,7 @@ function filter_algebra_image($imagefile, $tex= "", $height="", $width="", $alig
 }
 
 class filter_algebra extends moodle_text_filter {
-    function filter($text, array $options = array()){
+    public function filter($text, array $options = array()){
         global $CFG, $DB;
 
         /// Do a quick check using stripos to avoid unnecessary wor
@@ -114,9 +114,6 @@ class filter_algebra extends moodle_text_filter {
 #        return $text;
 #    }
 
-
-        $text .= ' ';
-
         preg_match_all('/@(@@+)([^@])/',$text,$matches);
         for ($i=0;$i<count($matches[0]);$i++) {
             $replacement = str_replace('@','&#x00040;',$matches[1][$i]).$matches[2][$i];
@@ -129,6 +126,17 @@ class filter_algebra extends moodle_text_filter {
         preg_match_all('/<algebra>(.+?)<\/algebra>|@@(.+?)@@/is', $text, $matches);
         for ($i=0; $i<count($matches[0]); $i++) {
             $algebra = $matches[1][$i] . $matches[2][$i];
+
+            // Look for some common false positives, and skip processing them.
+            if ($algebra == 'PLUGINFILE' || $algebra == 'DRAFTFILE') {
+                // Raw pluginfile URL.
+                continue;
+            }
+            if (preg_match('/^ -\d+(,\d+)? \+\d+(,\d+)? $/', $algebra)) {
+                // Part of a unified diff.
+                continue;
+            }
+
             $algebra = str_replace('<nolink>','',$algebra);
             $algebra = str_replace('</nolink>','',$algebra);
             $algebra = str_replace('<span class="nolink">','',$algebra);
@@ -159,7 +167,7 @@ class filter_algebra extends moodle_text_filter {
                $algebra = str_replace('upsilon','zupslon',$algebra);
                $algebra = preg_replace('!\r\n?!',' ',$algebra);
                $algebra = escapeshellarg($algebra);
-               if ( (PHP_OS == "WINNT") || (PHP_OS == "WIN32") || (PHP_OS == "Windows") ) {
+               if ( (PHP_OS == "WINNT") || (PHP_OS == "WIN32") || (PHP_OS == "Windows")) {
                   $cmd  = "cd $CFG->dirroot\\filter\\algebra & algebra2tex.pl $algebra";
                } else {
                   $cmd  = "cd $CFG->dirroot/filter/algebra; ./algebra2tex.pl $algebra";
@@ -220,6 +228,7 @@ class filter_algebra extends moodle_text_filter {
                   $texexp = preg_replace('/\\\int\\\left\((.+?d[a-z])\\\right\)/s','\int '. "\$1 ",$texexp);
                   $texexp = preg_replace('/\\\lim\\\left\((.+?),(.+?),(.+?)\\\right\)/s','\lim_'. "{\$2\\to \$3}\$1 ",$texexp);
                   $texexp = str_replace('\mbox', '', $texexp); // now blacklisted in tex, sorry
+                  $texcache = new stdClass();
                   $texcache->filter = 'algebra';
                   $texcache->version = 1;
                   $texcache->md5key = $md5;
diff --git a/filter/algebra/tests/filter_test.php b/filter/algebra/tests/filter_test.php
new file mode 100644
index 0000000..6c7db8f
--- /dev/null
+++ b/filter/algebra/tests/filter_test.php
@@ -0,0 +1,90 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit test for the filter_algebra
+ *
+ * @package    filter_algebra
+ * @category   phpunit
+ * @copyright  2012 Tim Hunt
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/filter/algebra/filter.php');
+
+
+/**
+ * Unit tests for filter_algebra.
+ *
+ * Note that this only tests some of the filter logic. It does not acutally test
+ * the normal case of the filter working, because I cannot make it work on my
+ * test server, and if it does not work here, it probably does not also work
+ * for other people. A failing test will be irritating noise.
+ *
+ * @copyright  2012 Tim Hunt
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class filter_algebra_testcase extends basic_testcase {
+
+    protected $filter;
+
+    protected function setUp() {
+        parent::setUp();
+        $this->filter = new filter_algebra(context_system::instance(), array());
+    }
+
+    function test_algebra_filter_no_algebra() {
+        $this->assertEquals('<p>Look no algebra!</p>',
+                $this->filter->filter('<p>Look no algebra!</p>'));
+    }
+
+
+    function test_algebra_filter_pluginfile() {
+        $this->assertEquals('<img src="@@PLUGINFILE@@/photo.jpg">',
+                $this->filter->filter('<img src="@@PLUGINFILE@@/photo.jpg">'));
+    }
+
+    function test_algebra_filter_draftfile() {
+        $this->assertEquals('<img src="@@DRAFTFILE@@/photo.jpg">',
+                $this->filter->filter('<img src="@@DRAFTFILE@@/photo.jpg">'));
+    }
+
+    function test_algebra_filter_unified_diff() {
+        $diff = '
+diff -u -r1.1 Worksheet.php
+--- Worksheet.php   26 Sep 2003 04:18:02 -0000  1.1
++++ Worksheet.php   18 Nov 2009 03:58:50 -0000
+@@ -1264,10 +1264,10 @@
+         }
+
+         // Strip the = or @ sign at the beginning of the formula string
+-        if (ereg("^=",$formula)) {
++        if (preg_match("/^=/",$formula)) {
+             $formula = preg_replace("/(^=)/","",$formula);
+         }
+-        elseif(ereg("^@",$formula)) {
++        elseif(preg_match("/^@/",$formula)) {
+             $formula = preg_replace("/(^@)/","",$formula);
+         }
+         else {
+';
+        $this->assertEquals('<pre>' . $diff . '</pre>',
+                $this->filter->filter('<pre>' . $diff . '</pre>'));
+    }
+}
-- 
1.7.9.5


From ff43c30f0aeaa66afa9cafe27788de309ff3dedb Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 20 Aug 2012 12:46:32 +0100
Subject: [PATCH 480/903] MDL-31837 numerical tolerance: better handling of
 very small tolerances.

The changes between Moodle 1.9 and 2.1 made the marking of very small
answers like 10^-20 almost impossible. This change fixes it.

This fix is almost entirely due the the careful research of Pierre
Pichet, who carefully testing various proposals, and worked out that
this one seemed best.
---
 question/type/numerical/question.php          |    8 +++--
 question/type/numerical/tests/answer_test.php |   42 ++++++++++++++++++++++---
 2 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/question/type/numerical/question.php b/question/type/numerical/question.php
index 93d276a..110cfdc 100644
--- a/question/type/numerical/question.php
+++ b/question/type/numerical/question.php
@@ -320,10 +320,13 @@ class qtype_numerical_answer extends question_answer {
             throw new coding_exception('Cannot work out tolerance interval for answer *.');
         }
 
+        // Smallest number that, when added to 1, is different from 1.
+        $epsilon = pow(10, -1 * ini_get('precision'));
+
         // We need to add a tiny fraction depending on the set precision to make
         // the comparison work correctly, otherwise seemingly equal values can
         // yield false. See MDL-3225.
-        $tolerance = (float) $this->tolerance + pow(10, -1 * ini_get('precision'));
+        $tolerance = abs($this->tolerance) + $epsilon;
 
         switch ($this->tolerancetype) {
             case 1: case 'relative':
@@ -331,8 +334,7 @@ class qtype_numerical_answer extends question_answer {
                 return array($this->answer - $range, $this->answer + $range);
 
             case 2: case 'nominal':
-                $tolerance = $this->tolerance + pow(10, -1 * ini_get('precision')) *
-                        max(1, abs($this->answer));
+                $tolerance = $this->tolerance + $epsilon * max(abs($this->tolerance), abs($this->answer), $epsilon);
                 return array($this->answer - $tolerance, $this->answer + $tolerance);
 
             case 3: case 'geometric':
diff --git a/question/type/numerical/tests/answer_test.php b/question/type/numerical/tests/answer_test.php
index c3d276a..a74fed3 100644
--- a/question/type/numerical/tests/answer_test.php
+++ b/question/type/numerical/tests/answer_test.php
@@ -25,8 +25,10 @@
  */
 
 global $CFG;
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
 require_once($CFG->dirroot . '/question/type/numerical/question.php');
 
+
 class qtype_numerical_answer_test extends advanced_testcase {
     public function test_within_tolerance_nominal() {
         $answer = new qtype_numerical_answer(13, 7.0, 1.0, '', FORMAT_MOODLE, 1.0);
@@ -38,16 +40,46 @@ class qtype_numerical_answer_test extends advanced_testcase {
         $this->assertFalse($answer->within_tolerance(8.01));
     }
 
+    public function test_within_tolerance_nominal_zero() {
+        // Either an answer or tolerance of 0 requires special care. We still
+        // don't want to end up comparing two floats for absolute equality.
+
+        // Zero tol, non-zero answer.
+        $answer = new qtype_numerical_answer(13, 1e-20, 1.0, '', FORMAT_MOODLE, 0.0);
+        $this->assertFalse($answer->within_tolerance(0.9999999e-20));
+        $this->assertTrue($answer->within_tolerance(1e-20));
+        $this->assertFalse($answer->within_tolerance(1.0000001e-20));
+
+        // Non-zero tol, zero answer.
+        $answer = new qtype_numerical_answer(13, 0.0, 1.0, '', FORMAT_MOODLE, 1e-24);
+        $this->assertFalse($answer->within_tolerance(-2e-24));
+        $this->assertTrue($answer->within_tolerance(-1e-24));
+        $this->assertTrue($answer->within_tolerance(0));
+        $this->assertTrue($answer->within_tolerance(1e-24));
+        $this->assertFalse($answer->within_tolerance(2e-24));
+
+        // Zero tol, zero answer.
+        $answer = new qtype_numerical_answer(13, 0.0, 1.0, '', FORMAT_MOODLE, 1e-24);
+        $this->assertFalse($answer->within_tolerance(-1e-20));
+        $this->assertTrue($answer->within_tolerance(-1e-35));
+        $this->assertTrue($answer->within_tolerance(0));
+        $this->assertTrue($answer->within_tolerance(1e-35));
+        $this->assertFalse($answer->within_tolerance(1e-20));
+
+        // Non-zero tol, non-zero answer.
+        $answer = new qtype_numerical_answer(13, 1e-20, 1.0, '', FORMAT_MOODLE, 1e-24);
+        $this->assertFalse($answer->within_tolerance(1.0002e-20));
+        $this->assertTrue($answer->within_tolerance(1.0001e-20));
+        $this->assertTrue($answer->within_tolerance(1e-20));
+        $this->assertTrue($answer->within_tolerance(1.0001e-20));
+        $this->assertFalse($answer->within_tolerance(1.0002e-20));
+    }
+
     public function test_within_tolerance_blank() {
         $answer = new qtype_numerical_answer(13, 1234, 1.0, '', FORMAT_MOODLE, '');
         $this->assertTrue($answer->within_tolerance(1234));
         $this->assertFalse($answer->within_tolerance(1234.000001));
         $this->assertFalse($answer->within_tolerance(0));
-
-        $answer = new qtype_numerical_answer(13, 0, 1.0, '', FORMAT_MOODLE, '');
-        $this->assertTrue($answer->within_tolerance(0));
-        $this->assertFalse($answer->within_tolerance(pow(10, -1 * ini_get('precision') + 1)));
-        $this->assertTrue($answer->within_tolerance(pow(10, -1 * ini_get('precision'))));
     }
 
     public function test_within_tolerance_relative() {
-- 
1.7.9.5


From 7f8d6575318b2f46e2e80d0c815497e19ff7488d Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 21 Aug 2012 14:11:13 +0100
Subject: [PATCH 481/903] MDL-34993 questions: convert numeric fields to float
 on load.

NUMBER(X,Y) typically come back from the DB as strings. If you don't
convert them to float, then when you display them, it appears as
1.0000000, which is not normally what you want.

Also, increase the size of the field on the edit form, so if you
question does have default mark 0.1234567, you can see that!
---
 lib/questionlib.php                  |    8 ++++++++
 question/type/edit_question_form.php |    2 +-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index db7be64..b99edf7 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -780,14 +780,22 @@ function question_load_questions($questionids, $extrafields = '', $join = '') {
  */
 function _tidy_question($question, $loadtags = false) {
     global $CFG;
+
+    // Load question-type specific fields.
     if (!question_bank::is_qtype_installed($question->qtype)) {
         $question->questiontext = html_writer::tag('p', get_string('warningmissingtype',
                 'qtype_missingtype')) . $question->questiontext;
     }
     question_bank::get_qtype($question->qtype)->get_question_options($question);
+
+    // Convert numeric fields to float. (Prevents these being displayed as 1.0000000.)
+    $question->defaultmark += 0;
+    $question->penalty += 0;
+
     if (isset($question->_partiallyloaded)) {
         unset($question->_partiallyloaded);
     }
+
     if ($loadtags && !empty($CFG->usetags)) {
         require_once($CFG->dirroot . '/tag/lib.php');
         $question->tags = tag_get_tags_array('question', $question->id);
diff --git a/question/type/edit_question_form.php b/question/type/edit_question_form.php
index 7428254..714d6a8 100644
--- a/question/type/edit_question_form.php
+++ b/question/type/edit_question_form.php
@@ -190,7 +190,7 @@ abstract class question_edit_form extends question_wizard_form {
         $mform->setType('questiontext', PARAM_RAW);
 
         $mform->addElement('text', 'defaultmark', get_string('defaultmark', 'question'),
-                array('size' => 3));
+                array('size' => 7));
         $mform->setType('defaultmark', PARAM_FLOAT);
         $mform->setDefault('defaultmark', 1);
         $mform->addRule('defaultmark', null, 'required', null, 'client');
-- 
1.7.9.5


From 872e445a485ac454197af4129e99fea03a3759aa Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 23 Aug 2012 11:53:47 +0100
Subject: [PATCH 482/903] MDL-35003 questions: remove stray full stop after
 correct answer.

In a few situations, this full stop makes things a bit more grammatical,
but there are many other situations where it causes problems. So, on
balance we will remove it.
---
 question/type/match/lang/en/qtype_match.php        |    2 +-
 .../type/multichoice/lang/en/qtype_multichoice.php |    2 +-
 .../type/shortanswer/lang/en/qtype_shortanswer.php |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/question/type/match/lang/en/qtype_match.php b/question/type/match/lang/en/qtype_match.php
index f9f1f02..a096607 100644
--- a/question/type/match/lang/en/qtype_match.php
+++ b/question/type/match/lang/en/qtype_match.php
@@ -25,7 +25,7 @@
 
 $string['addmoreqblanks'] = '{no} More Sets of Blanks';
 $string['availablechoices'] = 'Available choices';
-$string['correctansweris'] = 'The correct answer is: {$a}.';
+$string['correctansweris'] = 'The correct answer is: {$a}';
 $string['filloutthreeqsandtwoas'] = 'You must provide at least two questions and three answers. You can provide extra wrong answers by giving an answer with a blank question. Entries where both the question and the answer are blank will be ignored.';
 $string['nomatchinganswer'] = 'You must specify an answer matching the question \'{$a}\'.';
 $string['nomatchinganswerforq'] = 'You must specify an answer for this question.';
diff --git a/question/type/multichoice/lang/en/qtype_multichoice.php b/question/type/multichoice/lang/en/qtype_multichoice.php
index ba236be..8f3c02e 100644
--- a/question/type/multichoice/lang/en/qtype_multichoice.php
+++ b/question/type/multichoice/lang/en/qtype_multichoice.php
@@ -37,7 +37,7 @@ $string['answersingleyes'] = 'One answer only';
 $string['choiceno'] = 'Choice {$a}';
 $string['choices'] = 'Available choices';
 $string['clozeaid'] = 'Enter missing word';
-$string['correctansweris'] = 'The correct answer is: {$a}.';
+$string['correctansweris'] = 'The correct answer is: {$a}';
 $string['correctfeedback'] = 'For any correct response';
 $string['errgradesetanswerblank'] = 'Grade set, but the Answer is blank';
 $string['errfractionsaddwrong'] = 'The positive grades you have chosen do not add up to 100%<br />Instead, they add up to {$a}%';
diff --git a/question/type/shortanswer/lang/en/qtype_shortanswer.php b/question/type/shortanswer/lang/en/qtype_shortanswer.php
index df9c127..0f42cf6 100644
--- a/question/type/shortanswer/lang/en/qtype_shortanswer.php
+++ b/question/type/shortanswer/lang/en/qtype_shortanswer.php
@@ -30,7 +30,7 @@ $string['answerno'] = 'Answer {$a}';
 $string['caseno'] = 'No, case is unimportant';
 $string['casesensitive'] = 'Case sensitivity';
 $string['caseyes'] = 'Yes, case must match';
-$string['correctansweris'] = 'The correct answer is: {$a}.';
+$string['correctansweris'] = 'The correct answer is: {$a}';
 $string['correctanswers'] = 'Correct answers';
 $string['filloutoneanswer'] = 'You must provide at least one possible answer. Answers left blank will not be used. \'*\' can be used as a wildcard to match any characters. The first matching answer will be used to determine the score and feedback.';
 $string['notenoughanswers'] = 'This type of question requires at least {$a} answers';
-- 
1.7.9.5


From 07eca71195b7bd36cbe419f9bf3624abc76a0f26 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 23 Aug 2012 11:16:24 +0100
Subject: [PATCH 483/903] MDL-35023 qtype calculated: fix strict syntax
 problem.

---
 question/type/calculated/questiontype.php |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php
index e6a2414..a4655a4 100644
--- a/question/type/calculated/questiontype.php
+++ b/question/type/calculated/questiontype.php
@@ -1701,17 +1701,19 @@ class qtype_calculated extends question_type {
                      WHERE i.id = d.datasetdefinition AND i.category = ?";
             if ($records = $DB->get_records_sql($sql, array($category))) {
                 foreach ($records as $r) {
+                    $key = "$r->type-$r->category-$r->name";
                     $sql1 = "SELECT q.*
                                FROM {question} q
                               WHERE q.id = ?";
-                    if (!isset ($datasetdefs["$r->type-$r->category-$r->name"])) {
-                        $datasetdefs["$r->type-$r->category-$r->name"]= $r;
+                    if (!isset($datasetdefs[$key])) {
+                        $datasetdefs[$key] = $r;
                     }
                     if ($questionb = $DB->get_records_sql($sql1, array($r->question))) {
-                        $datasetdefs["$r->type-$r->category-$r->name"]->questions[
-                                $r->question]->name = $questionb[$r->question]->name;
-                        $datasetdefs["$r->type-$r->category-$r->name"]->questions[
-                                $r->question]->id = $questionb[$r->question]->id;
+                        $datasetdefs[$key]->questions[$r->question] = new stdClass();
+                        $datasetdefs[$key]->questions[$r->question]->name =
+                                $questionb[$r->question]->name;
+                        $datasetdefs[$key]->questions[$r->question]->id =
+                                $questionb[$r->question]->id;
                     }
                 }
             }
-- 
1.7.9.5


From 765e7564cc884fd5b070306fd57f39c23b7fe85a Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 23 Aug 2012 11:37:51 +0100
Subject: [PATCH 484/903] MDL-35026 qtype multianswer: misnamed string.

AMOS BEGIN
 MOV [questionnadded,qtype_multianswer],[questionsadded,qtype_multianswer]
AMOS END
---
 .../type/multianswer/lang/en/qtype_multianswer.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/type/multianswer/lang/en/qtype_multianswer.php b/question/type/multianswer/lang/en/qtype_multianswer.php
index 192bb77..ddc0155 100644
--- a/question/type/multianswer/lang/en/qtype_multianswer.php
+++ b/question/type/multianswer/lang/en/qtype_multianswer.php
@@ -42,7 +42,6 @@ $string['pluginnameadding'] = 'Adding an Embedded answers (Cloze) question';
 $string['pluginnameediting'] = 'Editing an Embedded answers (Cloze) question';
 $string['pluginnamesummary'] = 'Questions of this type are very flexible, but can only be created by entering text containing special codes that create embedded multiple-choice, short answers and numerical questions.';
 $string['qtypenotrecognized'] = 'questiontype {$a} not recognized';
-$string['questionnadded'] = 'Question added';
 $string['questiondefinition'] = 'Question definition';
 $string['questiondeleted'] = 'Question deleted';
 $string['questioninquiz'] = '
@@ -52,6 +51,7 @@ $string['questioninquiz'] = '
   <li>change the questions order in the text,</li>
   <li>change their question type (numerical, shortanswer, multiple choice). </li></ul>
 ';
+$string['questionsadded'] = 'Question added';
 $string['questionsless'] = '{$a} question(s) less than in the multianswer question stored in the database';
 $string['questionsmissing'] = 'The question text must include at least one embedded answer.';
 $string['questionsmore'] = '{$a} question(s) more than in the multianswer question stored in the database';
-- 
1.7.9.5


From 99aaad063e415c6688776fc238af6ef777a0eea0 Mon Sep 17 00:00:00 2001
From: M Kassaei <m.kassaei@open.ac.uk>
Date: Thu, 23 Aug 2012 17:58:56 +0100
Subject: [PATCH 485/903] MDL-35038 quiz reports: document the API changes in
 2.3.

---
 mod/quiz/report/upgrade.txt |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/mod/quiz/report/upgrade.txt b/mod/quiz/report/upgrade.txt
index c12e7ff..0a3cdd7 100644
--- a/mod/quiz/report/upgrade.txt
+++ b/mod/quiz/report/upgrade.txt
@@ -20,3 +20,24 @@ frequency should be defined in version.php, not in the quiz_reports table.
 === 2.3 ===
 
 * Support for the old way of doing cron in a separate cron.php file has been removed.
+You need a lib.php file inside the pluginneme (quiz report name) and a cron function
+with the name quiz_pluginname_cron(), where pluginnme is the report name (e.g.:
+quiz_statistics_cron()).
+
+* Some globally defined constants with the prefix "QUIZ_REPORT_ATTEMPTS_" are put inside
+the abstract class "quiz_attempts_report" in Moodle 2.3.and they associate as follows:
+
+withis the classes drived from "quiz_attempts_report":
+
+parent::ALL_WITH            replaces    QUIZ_REPORT_ATTEMPTS_ALL
+parent::ENROLLED_ALL        replaces    QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS
+parent::ENROLLED_WITH       replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH
+parent::ENROLLED_WITHOUT    replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO
+
+anywhere else:
+quiz_attempts_report::ALL_WITH            replaces    QUIZ_REPORT_ATTEMPTS_ALL
+quiz_attempts_report::ENROLLED_ALL        replaces    QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS
+quiz_attempts_report::ENROLLED_WITH       replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH
+quiz_attempts_report::ENROLLED_WITHOUT    replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO
+
+* The clas "quiz_attempt_report" ahd been renbamed as "quiz_attempts_report"
-- 
1.7.9.5


From 6009d1a32e3001b67b0f0826a9b2f18e2de40041 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 23 Aug 2012 18:26:43 +0100
Subject: [PATCH 486/903] MDL-35038 quiz reports: clarify the API changes
 docs.

Also re-organise the file to put the most recent changes at the top.
---
 mod/quiz/report/upgrade.txt |   54 +++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 25 deletions(-)

diff --git a/mod/quiz/report/upgrade.txt b/mod/quiz/report/upgrade.txt
index 0a3cdd7..d1821ca 100644
--- a/mod/quiz/report/upgrade.txt
+++ b/mod/quiz/report/upgrade.txt
@@ -3,9 +3,34 @@ This files describes API changes for quiz report plugins.
 Overview of this plugin type at http://docs.moodle.org/dev/Quiz_reports
 
 
-=== earlier versions ===
+=== 2.3 ===
 
-* ... API changes were not documented properly. Sorry. (There weren't many!)
+* Support for the old way of doing cron in a separate cron.php file has been removed.
+Instead, you need a lib.php file inside the plugin with a cron function
+called quiz_myreportname_cron(). The statistics report is an example of how
+it should be done.
+
+* There was a big refactor of the quiz reports, in issues MDL-32300, MDL-32322 and MDL-3030.
+It is difficult to explain the changes. Probably the best way to understand what
+happened is to look at
+    git log mod/quiz/report/overview
+    git log mod/quiz/report/responses
+and so on. Here are some notes on a few of the changes:
+
+The class quiz_attempt_report was renamed to quiz_attempts_report (with an extra s).
+
+Some globally defined constants with the prefix QUIZ_REPORT_ATTEMPTS_ moved into
+the quiz_attempts_report class. Specifically
+
+quiz_attempts_report::ALL_WITH         replaces QUIZ_REPORT_ATTEMPTS_ALL
+quiz_attempts_report::ENROLLED_ALL     replaces QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS
+quiz_attempts_report::ENROLLED_WITH    replaces QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH
+quiz_attempts_report::ENROLLED_WITHOUT replaces QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO
+
+Your if you have a table class, it needs to be renamed like
+quiz_report_myreportname_table -> quiz_myreportname_table. That is, all the
+class names in your plugin should start with the frankenstyle plugin name
+quiz_myreportname.
 
 
 === 2.2 ===
@@ -17,27 +42,6 @@ This replaces the old way of having a separate cron.php file. Also, the cron
 frequency should be defined in version.php, not in the quiz_reports table.
 
 
-=== 2.3 ===
-
-* Support for the old way of doing cron in a separate cron.php file has been removed.
-You need a lib.php file inside the pluginneme (quiz report name) and a cron function
-with the name quiz_pluginname_cron(), where pluginnme is the report name (e.g.:
-quiz_statistics_cron()).
-
-* Some globally defined constants with the prefix "QUIZ_REPORT_ATTEMPTS_" are put inside
-the abstract class "quiz_attempts_report" in Moodle 2.3.and they associate as follows:
-
-withis the classes drived from "quiz_attempts_report":
-
-parent::ALL_WITH            replaces    QUIZ_REPORT_ATTEMPTS_ALL
-parent::ENROLLED_ALL        replaces    QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS
-parent::ENROLLED_WITH       replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH
-parent::ENROLLED_WITHOUT    replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO
-
-anywhere else:
-quiz_attempts_report::ALL_WITH            replaces    QUIZ_REPORT_ATTEMPTS_ALL
-quiz_attempts_report::ENROLLED_ALL        replaces    QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS
-quiz_attempts_report::ENROLLED_WITH       replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH
-quiz_attempts_report::ENROLLED_WITHOUT    replaces    QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO
+=== earlier versions ===
 
-* The clas "quiz_attempt_report" ahd been renbamed as "quiz_attempts_report"
+* ... API changes were not documented properly. Sorry. (There weren't many!)
-- 
1.7.9.5


From 44ec173ea8fea922f191508d317ab6f5d682f952 Mon Sep 17 00:00:00 2001
From: Justin Filip <jfilip@gmail.com>
Date: Fri, 2 Dec 2011 14:55:27 -0500
Subject: [PATCH 487/903] MDL-29598 backup Check whether a grade_letters
 record exists before trying to insert a new record

---
 backup/moodle2/restore_stepslib.php |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index 19d183a..d74a892 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -270,7 +270,15 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
         $data->contextid = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id;
 
-        $newitemid = $DB->insert_record('grade_letters', $data);
+        // MDL-29598 - Don't insert a duplicate record if this grade letter already exists
+        $gltest = (array)$data;
+        unset($gltest['id']);
+        if (!$DB->record_exists('grade_letters', $gltest)) {
+            $newitemid = $DB->insert_record('grade_letters', $data);
+        } else {
+            $newitemid = $data->id;
+        }
+
         $this->set_mapping('grade_letter', $oldid, $newitemid);
     }
     protected function process_grade_setting($data) {
-- 
1.7.9.5


From b7da14f1c628b49c665438e734a10e192c0435b2 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Fri, 17 Aug 2012 10:18:20 +0800
Subject: [PATCH 488/903] MDL-29598 backup Avoid possible future duplicate
 grade letters

More info in restore_activity_grades_structure_step->process_grade_letter() comments
---
 backup/moodle2/restore_stepslib.php |   19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index d74a892..dbd2c14 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -270,10 +270,9 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
         $data->contextid = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id;
 
-        // MDL-29598 - Don't insert a duplicate record if this grade letter already exists
-        $gltest = (array)$data;
-        unset($gltest['id']);
-        if (!$DB->record_exists('grade_letters', $gltest)) {
+        $gradeletter = (array)$data;
+        unset($gradeletter['id']);
+        if (!$DB->record_exists('grade_letters', $gradeletter)) {
             $newitemid = $DB->insert_record('grade_letters', $data);
         } else {
             $newitemid = $data->id;
@@ -2409,17 +2408,21 @@ class restore_activity_grades_structure_step extends restore_structure_step {
 
     /**
      * process activity grade_letters. Note that, while these are possible,
-     * because grade_letters are contextid based, in proctice, only course
+     * because grade_letters are contextid based, in practice, only course
      * context letters can be defined. So we keep here this method knowing
      * it won't be executed ever. gradebook restore will restore course letters.
      */
     protected function process_grade_letter($data) {
         global $DB;
 
-        $data = (object)$data;
+        $data['contextid'] = $this->task->get_contextid();
+        $gradeletter = (object)$data;
 
-        $data->contextid = $this->task->get_contextid();
-        $newitemid = $DB->insert_record('grade_letters', $data);
+        // Check if it exists before adding it
+        unset($data['id']);
+        if (!$DB->record_exists('grade_letters', $data)) {
+            $newitemid = $DB->insert_record('grade_letters', $gradeletter);
+        }
         // no need to save any grade_letter mapping
     }
 }
-- 
1.7.9.5


From bdbdd72cdbd23d6f7cf42cd378542774bd59891f Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 17 Aug 2012 15:46:09 +0800
Subject: [PATCH 489/903] MDL-30121 Assignment 2.2: Draft submission files
 will not be included in zip, if activity is open

---
 mod/assignment/type/upload/assignment.class.php |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/mod/assignment/type/upload/assignment.class.php b/mod/assignment/type/upload/assignment.class.php
index 83afeb4..91c5f5f 100644
--- a/mod/assignment/type/upload/assignment.class.php
+++ b/mod/assignment/type/upload/assignment.class.php
@@ -1150,7 +1150,7 @@ class assignment_upload extends assignment_base {
         require_once($CFG->libdir.'/filelib.php');
         $submissions = $this->get_submissions('','');
         if (empty($submissions)) {
-            print_error('errornosubmissions', 'assignment');
+            print_error('errornosubmissions', 'assignment', new moodle_url('/mod/assignment/submissions.php', array('id'=>$this->cm->id)));
         }
         $filesforzipping = array();
         $fs = get_file_storage();
@@ -1164,6 +1164,11 @@ class assignment_upload extends assignment_base {
         }
         $filename = str_replace(' ', '_', clean_filename($this->course->shortname.'-'.$this->assignment->name.'-'.$groupname.$this->assignment->id.".zip")); //name of new zip file.
         foreach ($submissions as $submission) {
+            // If assignment is open and submission is not finalized then don't add it to zip.
+            $submissionstatus = $this->is_finalized($submission);
+            if ($this->isopen() && empty($submissionstatus)) {
+                continue;
+            }
             $a_userid = $submission->userid; //get userid
             if ((groups_is_member($groupid,$a_userid)or !$groupmode or !$groupid)) {
                 $a_assignid = $submission->assignment; //get name of this assignment for use in the file names.
@@ -1180,6 +1185,12 @@ class assignment_upload extends assignment_base {
                 }
             }
         } // end of foreach loop
+
+        // Throw error if no files are added.
+        if (empty($filesforzipping)) {
+            print_error('errornosubmissions', 'assignment', new moodle_url('/mod/assignment/submissions.php', array('id'=>$this->cm->id)));
+        }
+
         if ($zipfile = assignment_pack_files($filesforzipping)) {
             send_temp_file($zipfile, $filename); //send file and delete after sending.
         }
-- 
1.7.9.5


From e24b125a3a0d164ad15fc2aadfc0c9c3fd398c29 Mon Sep 17 00:00:00 2001
From: Tim Lock <tim@netspot.com.au>
Date: Mon, 20 Aug 2012 14:33:01 +0800
Subject: [PATCH 490/903] MDL-31623 Course: Course reset bypass modules, which
 are removed

---
 course/reset_form.php |    6 +++---
 lib/moodlelib.php     |    6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/course/reset_form.php b/course/reset_form.php
index 09fb15b..b4a86fe 100644
--- a/course/reset_form.php
+++ b/course/reset_form.php
@@ -61,13 +61,13 @@ class course_reset_form extends moodleform {
         if ($allmods = $DB->get_records('modules') ) {
             foreach ($allmods as $mod) {
                 $modname = $mod->name;
-                if (!$DB->count_records($modname, array('course'=>$COURSE->id))) {
-                    continue; // skip mods with no instances
-                }
                 $modfile = $CFG->dirroot."/mod/$modname/lib.php";
                 $mod_reset_course_form_definition = $modname.'_reset_course_form_definition';
                 $mod_reset__userdata = $modname.'_reset_userdata';
                 if (file_exists($modfile)) {
+                    if (!$DB->count_records($modname, array('course'=>$COURSE->id))) {
+                        continue; // Skip mods with no instances
+                    }
                     include_once($modfile);
                     if (function_exists($mod_reset_course_form_definition)) {
                         $mod_reset_course_form_definition($mform);
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 55cf4e8..58a6c59 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -4961,12 +4961,12 @@ function reset_course_userdata($data) {
     if ($allmods = $DB->get_records('modules') ) {
         foreach ($allmods as $mod) {
             $modname = $mod->name;
-            if (!$DB->count_records($modname, array('course'=>$data->courseid))) {
-                continue; // skip mods with no instances
-            }
             $modfile = $CFG->dirroot.'/mod/'. $modname.'/lib.php';
             $moddeleteuserdata = $modname.'_reset_userdata';   // Function to delete user data
             if (file_exists($modfile)) {
+                if (!$DB->count_records($modname, array('course'=>$data->courseid))) {
+                    continue; // Skip mods with no instances
+                }
                 include_once($modfile);
                 if (function_exists($moddeleteuserdata)) {
                     $modstatus = $moddeleteuserdata($data);
-- 
1.7.9.5


From 9fc95b6558a5d8850b4c64b1db67c031de91d15b Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 21 Aug 2012 11:28:27 +0800
Subject: [PATCH 491/903] MDL-31633 grades: Fixing incorrect redirect when
 trying to edit grade letters from admin settings

---
 grade/lib.php |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/grade/lib.php b/grade/lib.php
index b166e54..d7d3b5b 100644
--- a/grade/lib.php
+++ b/grade/lib.php
@@ -2574,6 +2574,7 @@ abstract class grade_helper {
      * @return array
      */
     public static function get_info_letters($courseid) {
+        global $SITE;
         if (self::$letterinfo !== null) {
             return self::$letterinfo;
         }
@@ -2581,9 +2582,15 @@ abstract class grade_helper {
         $canmanage = has_capability('moodle/grade:manage', $context);
         $canmanageletters = has_capability('moodle/grade:manageletters', $context);
         if ($canmanage || $canmanageletters) {
+            // Redirect to system context when report is accessed from admin settings MDL-31633
+            if ($context->instanceid == $SITE->id) {
+                $param = array('edit' => 1);
+            } else {
+                $param = array('edit' => 1,'id' => $context->id);
+            }
             self::$letterinfo = array(
                 'view' => new grade_plugin_info('view', new moodle_url('/grade/edit/letter/index.php', array('id'=>$context->id)), get_string('view')),
-                'edit' => new grade_plugin_info('edit', new moodle_url('/grade/edit/letter/index.php', array('edit'=>1,'id'=>$context->id)), get_string('edit'))
+                'edit' => new grade_plugin_info('edit', new moodle_url('/grade/edit/letter/index.php', $param), get_string('edit'))
             );
         } else {
             self::$letterinfo = false;
-- 
1.7.9.5


From cc0188c21cfa30b75c4ffa4f8bd8a86481c68568 Mon Sep 17 00:00:00 2001
From: Jean-Michel Vedrine <vedrine@vedrine.org>
Date: Sat, 11 Aug 2012 21:00:54 +0200
Subject: [PATCH 492/903] MDL-25492 Blackboard V6+ question import is broken.

---
 question/format.php                                |   68 +-
 question/format/blackboard/format.php              |   27 -
 question/format/blackboard_six/format.php          | 1029 +++----------------
 question/format/blackboard_six/formatbase.php      |  163 +++
 question/format/blackboard_six/formatpool.php      |  467 +++++++++
 question/format/blackboard_six/formatqti.php       |  894 +++++++++++++++++
 .../lang/en/qformat_blackboard_six.php             |   13 +-
 .../tests/blackboardformatpool_test.php            |  330 ++++++
 .../tests/blackboardsixformatqti_test.php          |  330 ++++++
 .../tests/fixtures/sample_blackboard_pool.dat      |  142 +++
 .../tests/fixtures/sample_blackboard_qti.dat       | 1058 ++++++++++++++++++++
 question/format/blackboard_six/version.php         |    5 +-
 question/format/examview/format.php                |   35 -
 question/format/gift/format.php                    |   13 -
 14 files changed, 3593 insertions(+), 981 deletions(-)
 create mode 100644 question/format/blackboard_six/formatbase.php
 create mode 100644 question/format/blackboard_six/formatpool.php
 create mode 100644 question/format/blackboard_six/formatqti.php
 create mode 100644 question/format/blackboard_six/tests/blackboardformatpool_test.php
 create mode 100644 question/format/blackboard_six/tests/blackboardsixformatqti_test.php
 create mode 100644 question/format/blackboard_six/tests/fixtures/sample_blackboard_pool.dat
 create mode 100644 question/format/blackboard_six/tests/fixtures/sample_blackboard_qti.dat

diff --git a/question/format.php b/question/format.php
index a0e9df4..dd02cfc 100644
--- a/question/format.php
+++ b/question/format.php
@@ -408,20 +408,44 @@ class qformat_default {
             $question->timecreated = time();
             $question->modifiedby = $USER->id;
             $question->timemodified = time();
+            $fileoptions = array(
+                    'subdirs' => false,
+                    'maxfiles' => -1,
+                    'maxbytes' => 0,
+                );
+            if (is_array($question->questiontext)) {
+                // Importing images from draftfile.
+                $questiontext = $question->questiontext;
+                $question->questiontext = $questiontext['text'];
+            }
+            if (is_array($question->generalfeedback)) {
+                $generalfeedback = $question->generalfeedback;
+                $question->generalfeedback = $generalfeedback['text'];
+            }
 
             $question->id = $DB->insert_record('question', $question);
-            if (isset($question->questiontextfiles)) {
+
+            if (!empty($questiontext['itemid'])) {
+                $question->questiontext = file_save_draft_area_files($questiontext['itemid'],
+                        $this->importcontext->id, 'question', 'questiontext', $question->id,
+                        $fileoptions, $question->questiontext);
+            } else if (isset($question->questiontextfiles)) {
                 foreach ($question->questiontextfiles as $file) {
                     question_bank::get_qtype($question->qtype)->import_file(
                             $this->importcontext, 'question', 'questiontext', $question->id, $file);
                 }
             }
-            if (isset($question->generalfeedbackfiles)) {
+            if (!empty($generalfeedback['itemid'])) {
+                $question->generalfeedback = file_save_draft_area_files($generalfeedback['itemid'],
+                        $this->importcontext->id, 'question', 'generalfeedback', $question->id,
+                        $fileoptions, $question->generalfeedback);
+            } else if (isset($question->generalfeedbackfiles)) {
                 foreach ($question->generalfeedbackfiles as $file) {
                     question_bank::get_qtype($question->qtype)->import_file(
                             $this->importcontext, 'question', 'generalfeedback', $question->id, $file);
                 }
             }
+            $DB->update_record('question', $question);
 
             $this->questionids[] = $question->id;
 
@@ -637,6 +661,24 @@ class qformat_default {
     }
 
     /**
+     * Add a blank combined feedback to a question object.
+     * @param object question
+     * @return object question
+     */
+    protected function add_blank_combined_feedback($question) {
+        $question->correctfeedback['text'] = '';
+        $question->correctfeedback['format'] = $question->questiontextformat;
+        $question->correctfeedback['files'] = array();
+        $question->partiallycorrectfeedback['text'] = '';
+        $question->partiallycorrectfeedback['format'] = $question->questiontextformat;
+        $question->partiallycorrectfeedback['files'] = array();
+        $question->incorrectfeedback['text'] = '';
+        $question->incorrectfeedback['format'] = $question->questiontextformat;
+        $question->incorrectfeedback['files'] = array();
+        return $question;
+    }
+
+    /**
      * Given the data known to define a question in
      * this format, this function converts it into a question
      * object suitable for processing and insertion into Moodle.
@@ -902,6 +944,28 @@ class qformat_default {
 class qformat_based_on_xml extends qformat_default {
 
     /**
+     * A lot of imported files contain unwanted entities.
+     * This method tries to clean up all known problems.
+     * @param string str string to correct
+     * @return string the corrected string
+     */
+    public function cleaninput($str) {
+
+        $html_code_list = array(
+            "&#039;" => "'",
+            "&#8217;" => "'",
+            "&#8220;" => "\"",
+            "&#8221;" => "\"",
+            "&#8211;" => "-",
+            "&#8212;" => "-",
+        );
+        $str = strtr($str, $html_code_list);
+        // Use textlib entities_to_utf8 function to convert only numerical entities.
+        $str = textlib::entities_to_utf8($str, false);
+        return $str;
+    }
+
+    /**
      * Return the array moodle is expecting
      * for an HTML text. No processing is done on $text.
      * qformat classes that want to process $text
diff --git a/question/format/blackboard/format.php b/question/format/blackboard/format.php
index 88e0130..1e7fa0d 100644
--- a/question/format/blackboard/format.php
+++ b/question/format/blackboard/format.php
@@ -60,33 +60,6 @@ class qformat_blackboard extends qformat_based_on_xml {
     }
 
     /**
-     * Some softwares put entities in exported files.
-     * This method try to clean up known problems.
-     * @param string str string to correct
-     * @return string the corrected string
-     */
-    public function cleaninput($str) {
-        if (!$this->ishtml) {
-            return $str;
-        }
-        $html_code_list = array(
-            "&#039;" => "'",
-            "&#8217;" => "'",
-            "&#091;" => "[",
-            "&#8220;" => "\"",
-            "&#8221;" => "\"",
-            "&#093;" => "]",
-            "&#039;" => "'",
-            "&#8211;" => "-",
-            "&#8212;" => "-",
-        );
-        $str = strtr($str, $html_code_list);
-        // Use textlib entities_to_utf8 function to convert only numerical entities.
-        $str = textlib::entities_to_utf8($str, false);
-        return $str;
-    }
-
-    /**
      * Parse the array of lines into an array of questions
      * this *could* burn memory - but it won't happen that much
      * so fingers crossed!
diff --git a/question/format/blackboard_six/format.php b/question/format/blackboard_six/format.php
index 047bfa9..32652d1 100644
--- a/question/format/blackboard_six/format.php
+++ b/question/format/blackboard_six/format.php
@@ -15,936 +15,169 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Blackboard 6.0 question importer.
+ * Blackboard V5 and V6 question importer.
  *
- * @package    qformat
- * @subpackage blackboard_six
+ * @package    qformat_blackboard_six
  * @copyright  2005 Michael Penney
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
 defined('MOODLE_INTERNAL') || die();
 
-require_once ($CFG->libdir . '/xmlize.php');
-
-
-/**
- * Blackboard 6.0 question importer.
- *
- * @copyright  2005 Michael Penney
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class qformat_blackboard_six extends qformat_default {
-    function provide_import() {
-        return true;
-    }
-
-    public function can_import_file($file) {
-        $mimetypes = array(
-            mimeinfo('type', '.dat'),
-            mimeinfo('type', '.zip')
-        );
-        return in_array($file->get_mimetype(), $mimetypes);
-    }
-
-
-    //Function to check and create the needed dir to unzip file to
-    function check_and_create_import_dir($unique_code) {
-
-        global $CFG;
-
-        $status = $this->check_dir_exists($CFG->tempdir."",true);
-        if ($status) {
-            $status = $this->check_dir_exists($CFG->tempdir."/bbquiz_import",true);
-        }
-        if ($status) {
-            $status = $this->check_dir_exists($CFG->tempdir."/bbquiz_import/".$unique_code,true);
-        }
-
-        return $status;
-    }
-
-    function clean_temp_dir($dir='') {
+require_once($CFG->libdir . '/xmlize.php');
+require_once($CFG->dirroot . '/question/format/blackboard_six/formatbase.php');
+require_once($CFG->dirroot . '/question/format/blackboard_six/formatqti.php');
+require_once($CFG->dirroot . '/question/format/blackboard_six/formatpool.php');
+
+class qformat_blackboard_six extends qformat_blackboard_six_base {
+    /** @var int Blackboard assessment qti files were always imported by the blackboard_six plugin. */
+    const FILETYPE_QTI = 1;
+    /** @var int Blackboard question pool files were previously handled by the blackboard plugin. */
+    const FILETYPE_POOL = 2;
+    /** @var int type of file being imported, one of the constants FILETYPE_QTI or FILETYPE_POOL. */
+    public $filetype;
+
+    public function get_filecontent($path) {
+        $fullpath = $this->tempdir . '/' . $path;
+        if (is_file($fullpath) && is_readable($fullpath)) {
+            return file_get_contents($fullpath);
+        }
+        return false;
+    }
+
+    /**
+     * Set the file type being imported
+     * @param int $type the imported file's type
+     */
+    public function set_filetype($type) {
+        $this->filetype = $type;
+    }
+
+    /**
+     * Return content of all files containing questions,
+     * as an array one element for each file found,
+     * For each file, the corresponding element is an array of lines.
+     * @param string filename name of file
+     * @return mixed contents array or false on failure
+     */
+    public function readdata($filename) {
         global $CFG;
 
-        // for now we will just say everything happened okay note
-        // that a mess may be piling up in $CFG->tempdir/bbquiz_import
-        // TODO return true at top of the function renders all the following code useless
-        return true;
-
-        if ($dir == '') {
-            $dir = $this->temp_dir;
-        }
-        $slash = "/";
-
-        // Create arrays to store files and directories
-        $dir_files      = array();
-        $dir_subdirs    = array();
-
-        // Make sure we can delete it
-        chmod($dir, $CFG->directorypermissions);
-
-        if ((($handle = opendir($dir))) == FALSE) {
-            // The directory could not be opened
-            return false;
-        }
-
-        // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
-        while(false !== ($entry = readdir($handle))) {
-            if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {
-                $dir_subdirs[] = $dir. $slash .$entry;
-            }
-            else if ($entry != ".." && $entry != ".") {
-                $dir_files[] = $dir. $slash .$entry;
-            }
-        }
-
-        // Delete all files in the curent directory return false and halt if a file cannot be removed
-        $countdir_files = count($dir_files);
-        for($i=0; $i<$countdir_files; $i++) {
-            chmod($dir_files[$i], $CFG->directorypermissions);
-            if (((unlink($dir_files[$i]))) == FALSE) {
+        // Find if we are importing a .dat file.
+        if (strtolower(pathinfo($filename, PATHINFO_EXTENSION)) == 'dat') {
+            if (!is_readable($filename)) {
+                $this->error(get_string('filenotreadable', 'error'));
                 return false;
             }
-        }
-
-        // Empty sub directories and then remove the directory
-        $countdir_subdirs = count($dir_subdirs);
-        for($i=0; $i<$countdir_subdirs; $i++) {
-            chmod($dir_subdirs[$i], $CFG->directorypermissions);
-            if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {
-                return false;
+            // As we are not importing a .zip file,
+            // there is no imsmanifest, and it is not possible
+            // to parse it to find the file type.
+            // So we need to guess the file type by looking at the content.
+            // For now we will do that searching for a required tag.
+            // This is certainly not bullet-proof but works for all usual files.
+            $text = file_get_contents($filename);
+            if (strpos($text, '<questestinterop>')) {
+                $this->set_filetype(self::FILETYPE_QTI);
             }
-            else {
-                if (rmdir($dir_subdirs[$i]) == FALSE) {
-                return false;
-                }
+            if (strpos($text, '<POOL>')) {
+                $this->set_filetype(self::FILETYPE_POOL);
             }
-        }
+            // In all other cases we are not able to handle this question file.
 
-        // Close directory
-        closedir($handle);
-        if (rmdir($this->temp_dir) == FALSE) {
-            return false;
+            // Readquestions is now expecting an array of strings.
+            return array($text);
         }
-        // Success, every thing is gone return true
-        return true;
-    }
-
-    //Function to check if a directory exists and, optionally, create it
-    function check_dir_exists($dir,$create=false) {
-
-        global $CFG;
-
-        $status = true;
-        if(!is_dir($dir)) {
-            if (!$create) {
-                $status = false;
-            } else {
-                umask(0000);
-                $status = mkdir ($dir,$CFG->directorypermissions);
+        // We are importing a zip file.
+        // Create name for temporary directory.
+        $unique_code = time();
+        $this->tempdir = make_temp_directory('bbquiz_import/' . $unique_code);
+        if (is_readable($filename)) {
+            if (!copy($filename, $this->tempdir . '/bboard.zip')) {
+                $this->error(get_string('cannotcopybackup', 'question'));
+                fulldelete($this->tempdir);
+                return false;
             }
-        }
-        return $status;
-    }
+            if (unzip_file($this->tempdir . '/bboard.zip', '', false)) {
+                $dom = new DomDocument();
 
-    function importpostprocess() {
-    /// Does any post-processing that may be desired
-    /// Argument is a simple array of question ids that
-    /// have just been added.
-
-        // need to clean up temporary directory
-        return $this->clean_temp_dir();
-    }
-
-    function copy_file_to_course($filename) {
-        global $CFG, $COURSE;
-        $filename = str_replace('\\','/',$filename);
-        $fullpath = $this->temp_dir.'/res00001/'.$filename;
-        $basename = basename($filename);
-
-        $copy_to = $CFG->dataroot.'/'.$COURSE->id.'/bb_import';
-
-        if ($this->check_dir_exists($copy_to,true)) {
-            if(is_readable($fullpath)) {
-                $copy_to.= '/'.$basename;
-                if (!copy($fullpath, $copy_to)) {
+                if (!$dom->load($this->tempdir . '/imsmanifest.xml')) {
+                    $this->error(get_string('errormanifest', 'qformat_blackboard_six'));
+                    fulldelete($this->tempdir);
                     return false;
                 }
-                else {
-                    return $copy_to;
-                }
-            }
-        }
-        else {
-            return false;
-        }
-    }
 
-    function readdata($filename) {
-    /// Returns complete file with an array, one item per line
-        global $CFG;
+                $xpath = new DOMXPath($dom);
 
-        // if the extension is .dat we just return that,
-        // if .zip we unzip the file and get the data
-        $ext = substr($this->realfilename, strpos($this->realfilename,'.'), strlen($this->realfilename)-1);
-        if ($ext=='.dat') {
-            if (!is_readable($filename)) {
-                print_error('filenotreadable', 'error');
-            }
-            return file($filename);
-        }
+                // We starts from the root element.
+                $query = '//resources/resource';
+                $this->filebase = $this->tempdir;
+                $q_file = array();
 
-        $unique_code = time();
-        $temp_dir = $CFG->tempdir."/bbquiz_import/".$unique_code;
-        $this->temp_dir = $temp_dir;
-        if ($this->check_and_create_import_dir($unique_code)) {
-            if(is_readable($filename)) {
-                if (!copy($filename, "$temp_dir/bboard.zip")) {
-                    print_error('cannotcopybackup', 'question');
-                }
-                if(unzip_file("$temp_dir/bboard.zip", '', false)) {
-                    // assuming that the information is in res0001.dat
-                    // after looking at 6 examples this was always the case
-                    $q_file = "$temp_dir/res00001.dat";
-                    if (is_file($q_file)) {
-                        if (is_readable($q_file)) {
-                            $filearray = file($q_file);
-                            /// Check for Macintosh OS line returns (ie file on one line), and fix
-                            if (preg_match("~\r~", $filearray[0]) AND !preg_match("~\n~", $filearray[0])) {
-                                return explode("\r", $filearray[0]);
-                            } else {
-                                return $filearray;
-                            }
+                $examfiles = $xpath->query($query);
+                foreach ($examfiles as $examfile) {
+                    if ($examfile->getAttribute('type') == 'assessment/x-bb-qti-test'
+                            || $examfile->getAttribute('type') == 'assessment/x-bb-qti-pool') {
+
+                        if ($content = $this->get_filecontent($examfile->getAttribute('bb:file'))) {
+                            $this->set_filetype(self::FILETYPE_QTI);
+                            $q_file[] = $content;
                         }
                     }
-                    else {
-                        print_error('cannotfindquestionfile', 'questioni');
-                    }
-                }
-                else {
-                    print "filename: $filename<br />tempdir: $temp_dir <br />";
-                    print_error('cannotunzip', 'question');
-                }
-            }
-            else {
-                print_error('cannotreaduploadfile');
-            }
-        }
-        else {
-            print_error('cannotcreatetempdir');
-        }
-    }
-
-    function save_question_options($question) {
-        return true;
-    }
-
-
-
-  protected function readquestions($lines) {
-    /// Parses an array of lines into an array of questions,
-    /// where each item is a question object as defined by
-    /// readquestion().
-
-    $text = implode($lines, " ");
-    $xml = xmlize($text, 0);
-
-    $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];
-    $questions = array();
-
-    foreach($raw_questions as $quest) {
-        $question = $this->create_raw_question($quest);
-
-        switch($question->qtype) {
-            case "Matching":
-                $this->process_matching($question, $questions);
-                break;
-            case "Multiple Choice":
-                $this->process_mc($question, $questions);
-                break;
-            case "Essay":
-                $this->process_essay($question, $questions);
-                break;
-            case "Multiple Answer":
-                $this->process_ma($question, $questions);
-                break;
-            case "True/False":
-                $this->process_tf($question, $questions);
-                break;
-            case 'Fill in the Blank':
-                $this->process_fblank($question, $questions);
-                break;
-            case 'Short Response':
-                $this->process_essay($question, $questions);
-                break;
-            default:
-                print "Unknown or unhandled question type: \"$question->qtype\"<br />";
-                break;
-        }
-
-    }
-    return $questions;
-  }
-
-
-// creates a cleaner object to deal with for processing into moodle
-// the object created is NOT a moodle question object
-function create_raw_question($quest) {
-
-    $question = new stdClass();
-    $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];
-    $question->id = $quest['#']['itemmetadata'][0]['#']['bbmd_asi_object_id'][0]['#'];
-    $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];
-
-    foreach($presentation->blocks as $pblock) {
-
-        $block = NULL;
-        $block->type = $pblock['@']['class'];
-
-        switch($block->type) {
-            case 'QUESTION_BLOCK':
-                $sub_blocks = $pblock['#']['flow'];
-                foreach($sub_blocks as $sblock) {
-                    //echo "Calling process_block from line 263<br>";
-                    $this->process_block($sblock, $block);
-                }
-                break;
-
-            case 'RESPONSE_BLOCK':
-                $choices = NULL;
-                switch($question->qtype) {
-                    case 'Matching':
-                        $bb_subquestions = $pblock['#']['flow'];
-                        $sub_questions = array();
-                        foreach($bb_subquestions as $bb_subquestion) {
-                            $sub_question = NULL;
-                            $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];
-                            $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);
-                            $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
-                            $choices = array();
-                            $this->process_choices($bb_choices, $choices);
-                            $sub_question->choices = $choices;
-                            if (!isset($block->subquestions)) {
-                                $block->subquestions = array();
-                            }
-                            $block->subquestions[] = $sub_question;
+                    if ($examfile->getAttribute('type') == 'assessment/x-bb-pool') {
+                        if ($examfile->getAttribute('baseurl')) {
+                            $this->filebase = $this->tempdir. '/' . $examfile->getAttribute('baseurl');
                         }
-                        break;
-                    case 'Multiple Answer':
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
-                        $choices = array();
-                        $this->process_choices($bb_choices, $choices);
-                        $block->choices = $choices;
-                        break;
-                    case 'Essay':
-                        // Doesn't apply since the user responds with text input
-                        break;
-                    case 'Multiple Choice':
-                        $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
-                            foreach($mc_choices as $mc_choice) {
-                            $choices = NULL;
-                            $choices = $this->process_block($mc_choice, $choices);
-                            $block->choices[] = $choices;
+                        if ($content = $this->get_filecontent($examfile->getAttribute('file'))) {
+                            $this->set_filetype(self::FILETYPE_POOL);
+                            $q_file[] = $content;
                         }
-                        break;
-                    case 'Short Response':
-                        // do nothing?
-                        break;
-                    case 'Fill in the Blank':
-                        // do nothing?
-                        break;
-                    default:
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
-                        $choices = array();
-                        $this->process_choices($bb_choices, $choices);
-                        $block->choices = $choices;
-                }
-                break;
-            case 'RIGHT_MATCH_BLOCK':
-                $matching_answerset = $pblock['#']['flow'];
-
-                $answerset = array();
-                foreach($matching_answerset as $answer) {
-                    // $answerset[] = $this->process_block($answer, $bb_answer);
-                    $bb_answer = null;
-                    $bb_answer->text = $answer['#']['flow'][0]['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
-                    $answerset[] = $bb_answer;
-                }
-                $block->matching_answerset = $answerset;
-                break;
-            default:
-                print "UNHANDLED PRESENTATION BLOCK";
-                break;
-        }
-        $question->{$block->type} = $block;
-    }
-
-    // determine response processing
-    // there is a section called 'outcomes' that I don't know what to do with
-    $resprocessing = $quest['#']['resprocessing'];
-    $respconditions = $resprocessing[0]['#']['respcondition'];
-    $reponses = array();
-    if ($question->qtype == 'Matching') {
-        $this->process_matching_responses($respconditions, $responses);
-    }
-    else {
-        $this->process_responses($respconditions, $responses);
-    }
-    $question->responses = $responses;
-    $feedbackset = $quest['#']['itemfeedback'];
-    $feedbacks = array();
-    $this->process_feedback($feedbackset, $feedbacks);
-    $question->feedback = $feedbacks;
-    return $question;
-}
-
-function process_block($cur_block, &$block) {
-    global $COURSE, $CFG;
-
-    $cur_type = $cur_block['@']['class'];
-    switch($cur_type) {
-        case 'FORMATTED_TEXT_BLOCK':
-            $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']);
-            break;
-        case 'FILE_BLOCK':
-            //revisit this to make sure it is working correctly
-            // Commented out ['matapplication']..., etc. because I
-            // noticed that when I imported a new Blackboard 6 file
-            // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06
-            $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];
-            if ($block->file != '') {
-                // if we have a file copy it to the course dir and adjust its name to be visible over the web.
-                $block->file = $this->copy_file_to_course($block->file);
-                $block->file = $CFG->wwwroot.'/file.php/'.$COURSE->id.'/bb_import/'.basename($block->file);
-            }
-            break;
-        case 'Block':
-            if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {
-            $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];
-            }
-            else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {
-                $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
-            }
-            else if (isset($cur_block['#']['response_label'])) {
-                // this is a response label block
-                $sub_blocks = $cur_block['#']['response_label'][0];
-                if(!isset($block->ident)) {
-                    if(isset($sub_blocks['@']['ident'])) {
-                        $block->ident = $sub_blocks['@']['ident'];
                     }
                 }
-                foreach($sub_blocks['#']['flow_mat'] as $sub_block) {
-                    $this->process_block($sub_block, $block);
-                }
-            }
-            else {
-                if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {
-                    if (isset($cur_block['#']['flow_mat'])) {
-                        $sub_blocks = $cur_block['#']['flow_mat'];
-                    }
-                    elseif (isset($cur_block['#']['flow'])) {
-                        $sub_blocks = $cur_block['#']['flow'];
-                    }
-                   foreach ($sub_blocks as $sblock) {
-                        // this will recursively grab the sub blocks which should be of one of the other types
-                        $this->process_block($sblock, $block);
-                    }
-                }
-            }
-            break;
-        case 'LINK_BLOCK':
-            // not sure how this should be included
-            if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {
-                $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];
-            }
-            else {
-               $block->link = '';
-            }
-            break;
-    }
-    return $block;
-}
 
-function process_choices($bb_choices, &$choices) {
-    foreach($bb_choices as $choice) {
-            if (isset($choice['@']['ident'])) {
-            $cur_choice = $choice['@']['ident'];
-        }
-        else { //for multiple answer
-            $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];
-        }
-        if (isset($choice['#']['flow_mat'][0])) { //for multiple answer
-            $cur_block = $choice['#']['flow_mat'][0];
-            // Reset $cur_choice to NULL because process_block is expecting an object
-            // for the second argument and not a string, which is what is was set as
-            // originally - CT 8/7/06
-            $cur_choice = null;
-            $this->process_block($cur_block, $cur_choice);
-        }
-        elseif (isset($choice['#']['response_label'])) {
-            // Reset $cur_choice to NULL because process_block is expecting an object
-            // for the second argument and not a string, which is what is was set as
-            // originally - CT 8/7/06
-            $cur_choice = null;
-            $this->process_block($choice, $cur_choice);
-        }
-        $choices[] = $cur_choice;
-    }
-}
-
-function process_matching_responses($bb_responses, &$responses) {
-    foreach($bb_responses as $bb_response) {
-        $response = NULL;
-        if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {
-            $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];
-            $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];
-        }
-        else {
-            $response->correct =  'Broken Question?';
-            $response->ident = 'Broken Question?';
-        }
-        $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
-        $responses[] = $response;
-    }
-}
-
-function process_responses($bb_responses, &$responses) {
-    foreach($bb_responses as $bb_response) {
-        //Added this line to instantiate $response.
-        // Without instantiating the $response variable, the same object
-        // gets added to the array
-        $response = new stdClass();
-        if (isset($bb_response['@']['title'])) {
-                $response->title = $bb_response['@']['title'];
-            }
-            else {
-                $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
-            }
-            $reponse->ident = array();
-            if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#'];
-            }
-            else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];
-            }
-
-            if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {
-                $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];
-                foreach($responseset as $rs) {
-                    $response->ident[] = $rs['#'];
-                    if(!isset($response->feedback) and isset( $rs['@'] ) ) {
-                        $response->feedback = $rs['@']['respident'];
-                    }
-                }
-            }
-            else {
-                $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
-            }
-
-            // determine what point value to give response
-            if (isset($bb_response['#']['setvar'])) {
-                switch ($bb_response['#']['setvar'][0]['#']) {
-                    case "SCORE.max":
-                        $response->fraction = 1;
-                        break;
-                    default:
-                        // I have only seen this being 0 or unset
-                        // there are probably fractional values of SCORE.max, but I'm not sure what they look like
-                        $response->fraction = 0;
-                        break;
-                }
-            }
-            else {
-               // just going to assume this is the case this is probably not correct.
-               $response->fraction = 0;
-            }
-
-            $responses[] = $response;
-        }
-}
-
-function process_feedback($feedbackset, &$feedbacks) {
-    foreach($feedbackset as $bb_feedback) {
-        // Added line $feedback=null so that $feedback does not get reused in the loop
-        // and added the the $feedbacks[] array multiple times
-        $feedback = null;
-        $feedback->ident = $bb_feedback['@']['ident'];
-        if (isset($bb_feedback['#']['flow_mat'][0])) {
-            $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);
-        }
-        elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {
-            $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);
-        }
-        $feedbacks[] = $feedback;
-    }
-}
-
-/**
- * Create common parts of question
- */
-function process_common( $quest ) {
-    $question = $this->defaultquestion();
-    $question->questiontext = $quest->QUESTION_BLOCK->text;
-    $question->name = shorten_text( $quest->id, 250 );
-
-    return $question;
-}
-
-//----------------------------------------
-// Process True / False Questions
-//----------------------------------------
-function process_tf($quest, &$questions) {
-    $question = $this->process_common( $quest );
-
-    $question->qtype = TRUEFALSE;
-    $question->single = 1; // Only one answer is allowed
-    // 0th [response] is the correct answer.
-    $responses = $quest->responses;
-    $correctresponse = $responses[0]->ident[0]['varequal'][0]['#'];
-    if ($correctresponse != 'false') {
-        $correct = true;
-    }
-    else {
-        $correct = false;
-    }
-
-    foreach($quest->feedback as $fb) {
-        $fback->{$fb->ident} = $fb->text;
-    }
-
-    if ($correct) {  // true is correct
-        $question->answer = 1;
-        $question->feedbacktrue = $fback->correct;
-        $question->feedbackfalse = $fback->incorrect;
-    } else {  // false is correct
-        $question->answer = 0;
-        $question->feedbacktrue = $fback->incorrect;
-        $question->feedbackfalse = $fback->correct;
-    }
-    $question->correctanswer = $question->answer;
-    $questions[] = $question;
-}
-
-
-//----------------------------------------
-// Process Fill in the Blank
-//----------------------------------------
-function process_fblank($quest, &$questions) {
-    $question = $this->process_common( $quest );
-    $question->qtype = SHORTANSWER;
-    $question->single = 1;
-
-    $answers = array();
-    $fractions = array();
-    $feedbacks = array();
-
-    // extract the feedback
-    $feedback = array();
-    foreach($quest->feedback as $fback) {
-        if (isset($fback->ident)) {
-            if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {
-                $feedback[$fback->ident] = $fback->text;
-            }
-        }
-    }
-
-    foreach($quest->responses as $response) {
-        if(isset($response->title)) {
-            if (isset($response->ident[0]['varequal'][0]['#'])) {
-                //for BB Fill in the Blank, only interested in correct answers
-                if ($response->feedback = 'correct') {
-                    $answers[] = $response->ident[0]['varequal'][0]['#'];
-                    $fractions[] = 1;
-                    if (isset($feedback['correct'])) {
-                        $feedbacks[] = $feedback['correct'];
-                    }
-                    else {
-                        $feedbacks[] = '';
-                    }
+                if ($q_file) {
+                    return $q_file;
+                } else {
+                    $this->error(get_string('cannotfindquestionfile', 'question'));
+                    fulldelete($this->tempdir);
                 }
-            }
-
-        }
-    }
-
-    //Adding catchall to so that students can see feedback for incorrect answers when they enter something the
-    //instructor did not enter
-    $answers[] = '*';
-    $fractions[] = 0;
-    if (isset($feedback['incorrect'])) {
-        $feedbacks[] = $feedback['incorrect'];
-    }
-    else {
-        $feedbacks[] = '';
-    }
-
-    $question->answer = $answers;
-    $question->fraction = $fractions;
-    $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of
-
-    if (!empty($question)) {
-        $questions[] = $question;
-    }
-
-}
-
-//----------------------------------------
-// Process Multiple Choice Questions
-//----------------------------------------
-function process_mc($quest, &$questions) {
-    $question = $this->process_common( $quest );
-    $question->qtype = MULTICHOICE;
-    $question->single = 1;
-
-    $feedback = array();
-    foreach($quest->feedback as $fback) {
-        $feedback[$fback->ident] = $fback->text;
-    }
-
-    foreach($quest->responses as $response) {
-        if (isset($response->title)) {
-            if ($response->title == 'correct') {
-                // only one answer possible for this qtype so first index is correct answer
-                $correct = $response->ident[0]['varequal'][0]['#'];
-            }
-        }
-        else {
-            // fallback method for when the title is not set
-            if ($response->feedback == 'correct') {
-               // only one answer possible for this qtype so first index is correct answer
-               $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06
-            }
-        }
-    }
-
-    $i = 0;
-    foreach($quest->RESPONSE_BLOCK->choices as $response) {
-        $question->answer[$i] = $response->text;
-        if ($correct == $response->ident) {
-            $question->fraction[$i] = 1;
-            // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists
-            // then specific feedback for this question (maybe this should be switched?, but from my example
-            // question pools I have not seen response specific feedback, only correct or incorrect feedback
-            if (!empty($feedback['correct'])) {
-                $question->feedback[$i] = $feedback['correct'];
-            }
-            elseif (!empty($feedback[$i])) {
-                $question->feedback[$i] = $feedback[$i];
-            }
-            else {
-                // failsafe feedback (should be '' instead?)
-                $question->feedback[$i] = "correct";
-            }
-        }
-        else {
-            $question->fraction[$i] = 0;
-            if (!empty($feedback['incorrect'])) {
-                $question->feedback[$i] = $feedback['incorrect'];
-            }
-            elseif (!empty($feedback[$i])) {
-                $question->feedback[$i] = $feedback[$i];
-            }
-            else {
-                // failsafe feedback (should be '' instead?)
-                $question->feedback[$i] = 'incorrect';
-            }
-        }
-        $i++;
-    }
-
-    if (!empty($question)) {
-        $questions[] = $question;
-    }
-}
-
-//----------------------------------------
-// Process Multiple Choice Questions With Multiple Answers
-//----------------------------------------
-function process_ma($quest, &$questions) {
-    $question = $this->process_common( $quest ); // copied this from process_mc
-    $question->qtype = MULTICHOICE;
-    $question->single = 0; // More than one answer allowed
-
-    $answers = $quest->responses;
-    $correct_answers = array();
-    foreach($answers as $answer) {
-        if($answer->title == 'correct') {
-            $answerset = $answer->ident[0]['and'][0]['#']['varequal'];
-            foreach($answerset as $ans) {
-                $correct_answers[] = $ans['#'];
-            }
-        }
-    }
-
-    foreach ($quest->feedback as $fb) {
-        $feedback->{$fb->ident} = trim($fb->text);
-    }
-
-    $correct_answer_count = count($correct_answers);
-    $choiceset = $quest->RESPONSE_BLOCK->choices;
-    $i = 0;
-    foreach($choiceset as $choice) {
-        $question->answer[$i] = trim($choice->text);
-        if (in_array($choice->ident, $correct_answers)) {
-            // correct answer
-            $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places
-            $question->feedback[$i] = $feedback->correct;
-        }
-        else {
-            // wrong answer
-            $question->fraction[$i] = 0;
-            $question->feedback[$i] = $feedback->incorrect;
-        }
-        $i++;
-    }
-
-    $questions[] = $question;
-}
-
-//----------------------------------------
-// Process Essay Questions
-//----------------------------------------
-function process_essay($quest, &$questions) {
-// this should be rewritten to accomodate moodle 1.6 essay question type eventually
-
-    if (defined("ESSAY")) {
-        // treat as short answer
-        $question = $this->process_common( $quest ); // copied this from process_mc
-        $question->qtype = ESSAY;
-
-        $question->feedback = array();
-        // not sure where to get the correct answer from
-        foreach($quest->feedback as $feedback) {
-            // Added this code to put the possible solution that the
-            // instructor gives as the Moodle answer for an essay question
-            if ($feedback->ident == 'solution') {
-                $question->feedback = $feedback->text;
-            }
-        }
-        //Added because essay/questiontype.php:save_question_option is expecting a
-        //fraction property - CT 8/10/06
-        $question->fraction[] = 1;
-        if (!empty($question)) {
-            $questions[]=$question;
-        }
-    }
-    else {
-        print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
-    }
-}
-
-//----------------------------------------
-// Process Matching Questions
-//----------------------------------------
-function process_matching($quest, &$questions) {
-    // renderedmatch is an optional plugin, so we need to check if it is defined
-    if (question_bank::is_qtype_installed('renderedmatch')) {
-        $question = $this->process_common($quest);
-        $question->valid = true;
-        $question->qtype = 'renderedmatch';
-
-        foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
-            foreach($quest->responses as $rid => $resp) {
-                if ($resp->ident == $subq->ident) {
-                    $correct = $resp->correct;
-                    $feedback = $resp->feedback;
-                }
-            }
-
-            foreach($subq->choices as $cid => $choice) {
-                if ($choice == $correct) {
-                    $question->subquestions[] = $subq->text;
-                    $question->subanswers[] = $quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text;
-                }
-            }
-        }
-
-        // check format
-        $status = true;
-        if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {
-            $status = false;
-        }
-        else {
-            // need to redo to make sure that no two questions have the same answer (rudimentary now)
-            foreach($question->subanswers as $qstn) {
-                if(isset($previous)) {
-                    if ($qstn == $previous) {
-                        $status = false;
-                    }
-                }
-                $previous = $qstn;
-                if ($qstn == '') {
-                    $status = false;
-                }
-            }
-        }
-
-        if ($status) {
-            $questions[] = $question;
-        }
-        else {
-            global $COURSE, $CFG;
-            print '<table class="boxaligncenter" border="1">';
-            print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>';
-
-            print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;
-            if (isset($quest->QUESTION_BLOCK->file)) {
-                print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';
-                if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {
-                    print '<img src="'.$CFG->wwwroot.'/file.php/'.$COURSE->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';
-                }
-            }
-            print "</td></tr>";
-            print "<tr><td>Subquestions:</td><td><ul>";
-            foreach($quest->responses as $rs) {
-                $correct_responses->{$rs->ident} = $rs->correct;
-            }
-            foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {
-                print '<li>'.$subq->text.'<ul>';
-                foreach($subq->choices as $id=>$choice) {
-                    print '<li>';
-                    if ($choice == $correct_responses->{$subq->ident}) {
-                        print '<font color="green">';
-                    }
-                    else {
-                        print '<font color="red">';
-                    }
-                    print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';
-                }
-                print '</ul>';
-            }
-            print '</ul></td></tr>';
-
-            print '<tr><td>Feedback:</td><td><ul>';
-            foreach($quest->feedback as $fb) {
-                print '<li>'.$fb->ident.': '.$fb->text.'</li>';
-            }
-            print '</ul></td></tr></table>';
+            } else {
+                $this->error(get_string('cannotunzip', 'question'));
+                fulldelete($this->temp_dir);
+            }
+        } else {
+            $this->error(get_string('cannotreaduploadfile', 'error'));
+            fulldelete($this->tempdir);
+        }
+        return false;
+    }
+
+    /**
+     * Parse the array of strings into an array of questions.
+     * Each string is the content of a .dat questions file.
+     * This *could* burn memory - but it won't happen that much
+     * so fingers crossed!
+     * @param array of strings from the input file.
+     * @param stdClass $context
+     * @return array (of objects) question objects.
+     */
+    public function readquestions($lines) {
+
+        // Set up array to hold all our questions.
+        $questions = array();
+        if ($this->filetype == self::FILETYPE_QTI) {
+            $importer = new qformat_blackboard_six_qti();
+        } else if ($this->filetype == self::FILETYPE_POOL) {
+            $importer = new qformat_blackboard_six_pool();
+        } else {
+            // In all other cases we are not able to import the file.
+            return false;
         }
-    }
-    else {
-        print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
-    }
-}
+        $importer->set_filebase($this->filebase);
 
-
-function strip_applet_tags_get_mathml($string) {
-    if(stristr($string, '</APPLET>') === FALSE) {
-        return $string;
-    }
-    else {
-        // strip all applet tags keeping stuff before/after and inbetween (if mathml) them
-        while (stristr($string, '</APPLET>') !== FALSE) {
-            preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);
-            $string = $mathmls[1].$mathmls[2].$mathmls[3];
+        // Each element of $lines is a string containing a complete xml document.
+        foreach ($lines as $text) {
+                $questions = array_merge($questions, $importer->readquestions($text));
         }
-        return $string;
+        return $questions;
     }
 }
-
-} // close object
-
diff --git a/question/format/blackboard_six/formatbase.php b/question/format/blackboard_six/formatbase.php
new file mode 100644
index 0000000..da08e91
--- /dev/null
+++ b/question/format/blackboard_six/formatbase.php
@@ -0,0 +1,163 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blackboard V5 and V6 question importer.
+ *
+ * @package    qformat_blackboard_six
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Base class question import format for zip files with images
+ *
+ */
+
+class qformat_blackboard_six_base extends qformat_based_on_xml {
+    /** @var string path to path to root of image tree in unzipped archive. */
+    public $filebase = '';
+    /** @var string path to the temporary directory. */
+    public $tempdir = '';
+    /**
+     * This plugin provide import
+     * @return bool true
+     */
+    public function provide_import() {
+        return true;
+    }
+
+    /**
+     * Check if the given file is capable of being imported by this plugin.
+     * As {@link file_storage::mimetype()} now uses finfo PHP extension if available,
+     * the value returned by $file->get_mimetype for a .dat file is not the same on all servers.
+     * So we must made 2 checks to verify if the plugin can import the file.
+     * @param stored_file $file the file to check
+     * @return bool whether this plugin can import the file
+     */
+    public function can_import_file($file) {
+        $mimetypes = array(
+            mimeinfo('type', '.dat'),
+            mimeinfo('type', '.zip')
+        );
+        return in_array($file->get_mimetype(), $mimetypes) || in_array(mimeinfo('type', $file->get_filename()), $mimetypes);
+    }
+
+    public function mime_type() {
+        return mimeinfo('type', '.zip');
+    }
+
+    /**
+     * Does any post-processing that may be desired
+     * Clean the temporary directory if a zip file was imported
+     * @return bool success
+     */
+    public function importpostprocess() {
+        if ($this->tempdir != '') {
+            fulldelete($this->tempdir);
+        }
+        return true;
+    }
+    /**
+     * Set the path to the root of images tree
+     * @param string $path path to images root
+     */
+    public function set_filebase($path) {
+        $this->filebase = $path;
+    }
+
+    /**
+     * Store an image file in a draft filearea
+     * @param array $text, if itemid element don't exists it will be created
+     * @param string tempdir path to root of image tree
+     * @param string filepathinsidetempdir path to image in the tree
+     * @param string filename image's name
+     * @return string new name of the image as it was stored
+     */
+    protected function store_file_for_text_field(&$text, $tempdir, $filepathinsidetempdir, $filename) {
+        global $USER;
+        $fs = get_file_storage();
+        if (empty($text['itemid'])) {
+            $text['itemid'] = file_get_unused_draft_itemid();
+        }
+        // As question file areas don't support subdirs,
+        // convert path to filename.
+        // So that images with same name can be imported.
+        $newfilename = clean_param(str_replace('/', '__', $filepathinsidetempdir . '__' . $filename), PARAM_FILE);
+        $filerecord = array(
+            'contextid' => context_user::instance($USER->id)->id,
+            'component' => 'user',
+            'filearea'  => 'draft',
+            'itemid'    => $text['itemid'],
+            'filepath'  => '/',
+            'filename'  => $newfilename,
+        );
+        $fs->create_file_from_pathname($filerecord, $tempdir . '/' . $filepathinsidetempdir . '/' . $filename);
+        return $newfilename;
+    }
+
+    /**
+     * Given an HTML text with references to images files,
+     * store all images in a draft filearea,
+     * and return an array with all urls in text recoded,
+     * format set to FORMAT_HTML, and itemid set to filearea itemid
+     * @param string text text to parse and recode
+     * @return array with keys text, format, itemid.
+     */
+    public function text_field($text) {
+        $data = array();
+        // Step one, find all file refs then add to array.
+        preg_match_all('|<img[^>]+src="([^"]*)"|i', $text, $out); // Find all src refs.
+
+        foreach ($out[1] as $path) {
+            $fullpath = $this->filebase . '/' . $path;
+
+            if (is_readable($fullpath)) {
+                $dirpath = dirname($path);
+                $filename = basename($path);
+                $newfilename = $this->store_file_for_text_field($data, $this->filebase, $dirpath, $filename);
+                $text = preg_replace("|$path|", "@@PLUGINFILE@@/" . $newfilename, $text);
+            }
+
+        }
+        $data['text'] = $text;
+        $data['format'] = FORMAT_HTML;
+        return $data;
+    }
+
+    /**
+     * Same as text_field but text is cleaned.
+     * @param string text text to parse and recode
+     * @return array with keys text, format, itemid.
+     */
+    public function cleaned_text_field($text) {
+        return $this->text_field($this->cleaninput($text));
+    }
+
+    /**
+     * Convert the question text to plain text.
+     * We need to overwrite this function because questiontext is an array.
+     */
+    protected function format_question_text($question) {
+        global $DB;
+        $formatoptions = new stdClass();
+        $formatoptions->noclean = true;
+        return html_to_text(format_text($question->questiontext['text'],
+                $question->questiontext['format'], $formatoptions), 0, false);
+    }
+}
diff --git a/question/format/blackboard_six/formatpool.php b/question/format/blackboard_six/formatpool.php
new file mode 100644
index 0000000..80867f3
--- /dev/null
+++ b/question/format/blackboard_six/formatpool.php
@@ -0,0 +1,467 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blackboard V5 and V6 question importer.
+ *
+ * @package    qformat_blackboard_six
+ * @copyright  2003 Scott Elliott
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/xmlize.php');
+
+/**
+ * Blackboard pool question importer.
+ *
+ * @copyright  2003 Scott Elliott
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class qformat_blackboard_six_pool extends qformat_blackboard_six_base {
+    // Is the current question's question text escaped HTML (true for most if not all Blackboard files).
+    public $ishtml = true;
+
+    /**
+     * Parse the xml document into an array of questions
+     * this *could* burn memory - but it won't happen that much
+     * so fingers crossed!
+     * @param array of lines from the input file.
+     * @param stdClass $context
+     * @return array (of objects) questions objects.
+     */
+    protected function readquestions($text) {
+
+        // This converts xml to big nasty data structure,
+        // the 0 means keep white space as it is.
+        try {
+            $xml = xmlize($text, 0, 'UTF-8', true);
+        } catch (xml_format_exception $e) {
+            $this->error($e->getMessage(), '');
+            return false;
+        }
+
+        $questions = array();
+
+        $this->process_tf($xml, $questions);
+        $this->process_mc($xml, $questions);
+        $this->process_ma($xml, $questions);
+        $this->process_fib($xml, $questions);
+        $this->process_matching($xml, $questions);
+        $this->process_essay($xml, $questions);
+
+        return $questions;
+    }
+
+    /**
+     * Do question import processing common to every qtype.
+     * @param array $questiondata the xml tree related to the current question
+     * @return object initialized question object.
+     */
+    public function process_common($questiondata) {
+
+        // This routine initialises the question object.
+        $question = $this->defaultquestion();
+
+        // Determine if the question is already escaped html.
+        $this->ishtml = $this->getpath($questiondata,
+                array('#', 'BODY', 0, '#', 'FLAGS', 0, '#', 'ISHTML', 0, '@', 'value'),
+                false, false);
+
+        // Put questiontext in question object.
+        $text = $this->getpath($questiondata,
+                array('#', 'BODY', 0, '#', 'TEXT', 0, '#'),
+                '', true, get_string('importnotext', 'qformat_blackboard_six'));
+
+        $question->questiontext = $this->cleaned_text_field($text);
+        $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
+
+        // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
+        $question->name = shorten_text(strip_tags($question->questiontext['text']), 200);
+        $question->name = substr($question->name, 0, 250);
+        if (!$question->name) {
+            $id = $this->getpath($questiondata,
+                    array('@', 'id'), '',  true);
+            $question->name = get_string('defaultname', 'qformat_blackboard_six' , $id);
+        }
+
+        $question->generalfeedback = '';
+        $question->generalfeedbackformat = FORMAT_HTML;
+        $question->generalfeedbackfiles = array();
+
+        // TODO : read the mark from the POOL TITLE QUESTIONLIST section.
+        $question->defaultmark = 1;
+        return $question;
+    }
+
+    /**
+     * Process Essay Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_essay($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_ESSAY'), false, false)) {
+            $essayquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_ESSAY'), false, false);
+        } else {
+            return;
+        }
+
+        foreach ($essayquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $question->qtype = 'essay';
+
+            $question->answer = '';
+            $answer = $this->getpath($thisquestion,
+                    array('#', 'ANSWER', 0, '#', 'TEXT', 0, '#'), '', true);
+            $question->graderinfo =  $this->cleaned_text_field($answer);
+            $question->feedback = '';
+            $question->responseformat = 'editor';
+            $question->responsefieldlines = 15;
+            $question->attachments = 0;
+            $question->fraction = 0;
+
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process True / False Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_tf($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false)) {
+            $tfquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false);
+        } else {
+            return;
+        }
+
+        foreach ($tfquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $question->qtype = 'truefalse';
+            $question->single = 1; // Only one answer is allowed.
+
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), array(), false);
+
+            $correctanswer = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'),
+                    '', true);
+
+            // First choice is true, second is false.
+            $id = $this->getpath($choices[0], array('@', 'id'), '', true);
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            if (strcmp($id,  $correctanswer) == 0) {  // True is correct.
+                $question->answer = 1;
+                $question->feedbacktrue = $this->cleaned_text_field($correctfeedback);
+                $question->feedbackfalse = $this->cleaned_text_field($incorrectfeedback);
+            } else {  // False is correct.
+                $question->answer = 0;
+                $question->feedbacktrue = $this->cleaned_text_field($incorrectfeedback);
+                $question->feedbackfalse = $this->cleaned_text_field($correctfeedback);
+            }
+            $question->correctanswer = $question->answer;
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process Multiple Choice Questions with single answer
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_mc($xml, &$questions) {
+
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false)) {
+            $mcquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false);
+        } else {
+            return;
+        }
+
+        foreach ($mcquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->cleaned_text_field($correctfeedback);
+            $question->partiallycorrectfeedback = $this->text_field('');
+            $question->incorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
+
+            $question->qtype = 'multichoice';
+            $question->single = 1; // Only one answer is allowed.
+
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            $correctanswerid = $this->getpath($thisquestion,
+                        array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'),
+                        '', true);
+            foreach ($choices as $choice) {
+                $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true);
+                // Put this choice in the question object.
+                $question->answer[] =  $this->cleaned_text_field($choicetext);
+
+                $choiceid = $this->getpath($choice, array('@', 'id'), '', true);
+                // If choice is the right answer, give 100% mark, otherwise give 0%.
+                if (strcmp ($choiceid, $correctanswerid) == 0) {
+                    $question->fraction[] = 1;
+                } else {
+                    $question->fraction[] = 0;
+                }
+                // There is never feedback specific to each choice.
+                $question->feedback[] =  $this->text_field('');
+            }
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process Multiple Choice Questions With Multiple Answers
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_ma($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false)) {
+            $maquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false);
+        } else {
+            return;
+        }
+
+        foreach ($maquestions as $thisquestion) {
+            $question = $this->process_common($thisquestion);
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->cleaned_text_field($correctfeedback);
+            // As there is no partially correct feedback we use incorrect one.
+            $question->partiallycorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
+            $question->incorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
+
+            $question->qtype = 'multichoice';
+            $question->defaultmark = 1;
+            $question->single = 0; // More than one answers allowed.
+
+            $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            $correctanswerids = array();
+            foreach ($this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false) as $correctanswer) {
+                if ($correctanswer) {
+                    $correctanswerids[] = $this->getpath($correctanswer,
+                            array('@', 'answer_id'),
+                            '', true);
+                }
+            }
+            $fraction = 1/count($correctanswerids);
+
+            foreach ($choices as $choice) {
+                $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true);
+                // Put this choice in the question object.
+                $question->answer[] =  $this->cleaned_text_field($choicetext);
+
+                $choiceid = $this->getpath($choice, array('@', 'id'), '', true);
+
+                $iscorrect = in_array($choiceid, $correctanswerids);
+
+                if ($iscorrect) {
+                    $question->fraction[] = $fraction;
+                } else {
+                    $question->fraction[] = 0;
+                }
+                // There is never feedback specific to each choice.
+                $question->feedback[] =  $this->text_field('');
+            }
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process Fill in the Blank Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_fib($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false)) {
+            $fibquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false);
+        } else {
+            return;
+        }
+
+        foreach ($fibquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+
+            $question->qtype = 'shortanswer';
+            $question->usecase = 0; // Ignore case.
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $answers = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false);
+            foreach ($answers as $answer) {
+                $question->answer[] = $this->getpath($answer,
+                        array('#', 'TEXT', 0, '#'), '', true);
+                $question->fraction[] = 1;
+                $question->feedback[] = $this->cleaned_text_field($correctfeedback);
+            }
+            $question->answer[] = '*';
+            $question->fraction[] = 0;
+            $question->feedback[] = $this->cleaned_text_field($incorrectfeedback);
+
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process Matching Questions
+     * @param array xml the xml tree
+     * @param array questions the questions already parsed
+     */
+    public function process_matching($xml, &$questions) {
+        if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MATCH'), false, false)) {
+            $matchquestions = $this->getpath($xml,
+                    array('POOL', '#', 'QUESTION_MATCH'), false, false);
+        } else {
+            return;
+        }
+        // Blackboard questions can't be imported in core Moodle without a loss in data,
+        // as core match question don't allow HTML in subanswers. The contributed ddmatch
+        // question type support HTML in subanswers.
+        // The ddmatch question type is not part of core, so we need to check if it is defined.
+        $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
+
+        foreach ($matchquestions as $thisquestion) {
+
+            $question = $this->process_common($thisquestion);
+            if ($ddmatchisinstalled) {
+                $question->qtype = 'ddmatch';
+            } else {
+                $question->qtype = 'match';
+            }
+
+            $correctfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'),
+                    '', true);
+            $incorrectfeedback = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'),
+                    '', true);
+            $question->correctfeedback = $this->cleaned_text_field($correctfeedback);
+            // As there is no partially correct feedback we use incorrect one.
+            $question->partiallycorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
+            $question->incorrectfeedback = $this->cleaned_text_field($incorrectfeedback);
+
+            $choices = $this->getpath($thisquestion,
+                    array('#', 'CHOICE'), false, false); // Blackboard "choices" are Moodle subanswers.
+            $answers = $this->getpath($thisquestion,
+                    array('#', 'ANSWER'), false, false); // Blackboard "answers" are Moodle subquestions.
+            $correctanswers = $this->getpath($thisquestion,
+                    array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false); // Mapping between choices and answers.
+            $mappings = array();
+            foreach ($correctanswers as $correctanswer) {
+                if ($correctanswer) {
+                    $correctchoiceid = $this->getpath($correctanswer,
+                                array('@', 'choice_id'), '', true);
+                    $correctanswerid = $this->getpath($correctanswer,
+                            array('@', 'answer_id'),
+                            '', true);
+                    $mappings[$correctanswerid] = $correctchoiceid;
+                }
+            }
+
+            foreach ($choices as $choice) {
+                if ($ddmatchisinstalled) {
+                    $choicetext = $this->cleaned_text_field($this->getpath($choice,
+                            array('#', 'TEXT', 0, '#'), '', true));
+                } else {
+                    $choicetext = trim(strip_tags($this->getpath($choice,
+                            array('#', 'TEXT', 0, '#'), '', true)));
+                }
+
+                if ($choicetext != '') { // Only import non empty subanswers.
+                    $subquestion = '';
+                    $choiceid = $this->getpath($choice,
+                            array('@', 'id'), '', true);
+                    $fiber = array_search($choiceid, $mappings);
+                    $fiber = array_keys ($mappings, $choiceid);
+                    foreach ($fiber as $correctanswerid) {
+                        // We have found a correspondance for this choice so we need to take the associated answer.
+                        foreach ($answers as $answer) {
+                            $currentanswerid = $this->getpath($answer,
+                                    array('@', 'id'), '', true);
+                            if (strcmp ($currentanswerid, $correctanswerid) == 0) {
+                                $subquestion = $this->getpath($answer,
+                                        array('#', 'TEXT', 0, '#'), '', true);
+                                break;
+                            }
+                        }
+                        $question->subquestions[] = $this->cleaned_text_field($subquestion);
+                        $question->subanswers[] = $choicetext;
+                    }
+
+                    if ($subquestion == '') { // Then in this case, $choice is a distractor.
+                        $question->subquestions[] = $this->text_field('');
+                        $question->subanswers[] = $choicetext;
+                    }
+                }
+            }
+
+            // Verify that this matching question has enough subquestions and subanswers.
+            $subquestioncount = 0;
+            $subanswercount = 0;
+            $subanswers = $question->subanswers;
+            foreach ($question->subquestions as $key => $subquestion) {
+                $subquestion = $subquestion['text'];
+                $subanswer = $subanswers[$key];
+                if ($subquestion != '') {
+                    $subquestioncount++;
+                }
+                $subanswercount++;
+            }
+            if ($subquestioncount < 2 || $subanswercount < 3) {
+                    $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext['text']));
+            } else {
+                $questions[] = $question;
+            }
+
+        }
+    }
+}
diff --git a/question/format/blackboard_six/formatqti.php b/question/format/blackboard_six/formatqti.php
new file mode 100644
index 0000000..223d9f6
--- /dev/null
+++ b/question/format/blackboard_six/formatqti.php
@@ -0,0 +1,894 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Blackboard V5 and V6 question importer.
+ *
+ * @package    qformat_blackboard_six
+ * @copyright  2005 Michael Penney
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/xmlize.php');
+
+/**
+ * Blackboard 6.0 question importer.
+ *
+ * @copyright  2005 Michael Penney
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
+    /**
+     * Parse the xml document into an array of questions
+     * this *could* burn memory - but it won't happen that much
+     * so fingers crossed!
+     * @param array of lines from the input file.
+     * @param stdClass $context
+     * @return array (of objects) questions objects.
+     */
+    protected function readquestions($text) {
+
+        // This converts xml to big nasty data structure,
+        // the 0 means keep white space as it is.
+        try {
+            $xml = xmlize($text, 0, 'UTF-8', true);
+        } catch (xml_format_exception $e) {
+            $this->error($e->getMessage(), '');
+            return false;
+        }
+
+        $questions = array();
+        // First step : we are only interested in the <item> tags.
+        $rawquestions = $this->getpath($xml,
+                array('questestinterop', '#', 'assessment', 0, '#', 'section', 0, '#', 'item'),
+                array(), false);
+        // Each <item> tag contains data related to a single question.
+        foreach ($rawquestions as $quest) {
+            // Second step : parse each question data into the intermediate
+            // rawquestion structure array.
+            // Warning : rawquestions are not Moodle questions.
+            $question = $this->create_raw_question($quest);
+            // Third step : convert a rawquestion into a Moodle question.
+            switch($question->qtype) {
+                case "Matching":
+                    $this->process_matching($question, $questions);
+                    break;
+                case "Multiple Choice":
+                    $this->process_mc($question, $questions);
+                    break;
+                case "Essay":
+                    $this->process_essay($question, $questions);
+                    break;
+                case "Multiple Answer":
+                    $this->process_ma($question, $questions);
+                    break;
+                case "True/False":
+                    $this->process_tf($question, $questions);
+                    break;
+                case 'Fill in the Blank':
+                    $this->process_fblank($question, $questions);
+                    break;
+                case 'Short Response':
+                    $this->process_essay($question, $questions);
+                    break;
+                default:
+                    $this->error(get_string('unknownorunhandledtype', 'qformat_blackboard_six', $question->qtype));
+                    break;
+            }
+        }
+        return $questions;
+    }
+
+    /**
+     * Creates a cleaner object to deal with for processing into Moodle.
+     * The object returned is NOT a moodle question object.
+     * @param array $quest XML <item> question  data
+     * @return object rawquestion
+     */
+    public function create_raw_question($quest) {
+
+        $rawquestion = new stdClass();
+        $rawquestion->qtype = $this->getpath($quest,
+                array('#', 'itemmetadata', 0, '#', 'bbmd_questiontype', 0, '#'),
+                '', true);
+        $rawquestion->id = $this->getpath($quest,
+                array('#', 'itemmetadata', 0, '#', 'bbmd_asi_object_id', 0, '#'),
+                '', true);
+        $presentation = new stdClass();
+        $presentation->blocks = $this->getpath($quest,
+                array('#', 'presentation', 0, '#', 'flow', 0, '#', 'flow'),
+                array(), false);
+
+        foreach ($presentation->blocks as $pblock) {
+            $block = new stdClass();
+            $block->type = $this->getpath($pblock,
+                    array('@', 'class'),
+                    '', true);
+
+            switch($block->type) {
+                case 'QUESTION_BLOCK':
+                    $subblocks = $this->getpath($pblock,
+                            array('#', 'flow'),
+                            array(), false);
+                    foreach ($subblocks as $sblock) {
+                        $this->process_block($sblock, $block);
+                    }
+                    break;
+
+                case 'RESPONSE_BLOCK':
+                    $choices = null;
+                    switch($rawquestion->qtype) {
+                        case 'Matching':
+                            $bbsubquestions = $this->getpath($pblock,
+                                    array('#', 'flow'),
+                                    array(), false);
+                            $sub_questions = array();
+                            foreach ($bbsubquestions as $bbsubquestion) {
+                                $sub_question = new stdClass();
+                                $sub_question->ident = $this->getpath($bbsubquestion,
+                                        array('#', 'response_lid', 0, '@', 'ident'),
+                                        '', true);
+                                $this->process_block($this->getpath($bbsubquestion,
+                                        array('#', 'flow', 0),
+                                        false, false), $sub_question);
+                                $bbchoices = $this->getpath($bbsubquestion,
+                                        array('#', 'response_lid', 0, '#', 'render_choice', 0,
+                                        '#', 'flow_label', 0, '#', 'response_label'),
+                                        array(), false);
+                                $choices = array();
+                                $this->process_choices($bbchoices, $choices);
+                                $sub_question->choices = $choices;
+                                if (!isset($block->subquestions)) {
+                                    $block->subquestions = array();
+                                }
+                                $block->subquestions[] = $sub_question;
+                            }
+                            break;
+                        case 'Multiple Answer':
+                            $bbchoices = $this->getpath($pblock,
+                                    array('#', 'response_lid', 0, '#', 'render_choice', 0, '#', 'flow_label'),
+                                    array(), false);
+                            $choices = array();
+                            $this->process_choices($bbchoices, $choices);
+                            $block->choices = $choices;
+                            break;
+                        case 'Essay':
+                            // Doesn't apply since the user responds with text input.
+                            break;
+                        case 'Multiple Choice':
+                            $mcchoices = $this->getpath($pblock,
+                                    array('#', 'response_lid', 0, '#', 'render_choice', 0, '#', 'flow_label'),
+                                    array(), false);
+                            foreach ($mcchoices as $mcchoice) {
+                                $choices = new stdClass();
+                                $choices = $this->process_block($mcchoice, $choices);
+                                $block->choices[] = $choices;
+                            }
+                            break;
+                        case 'Short Response':
+                            // Do nothing?
+                            break;
+                        case 'Fill in the Blank':
+                            // Do nothing?
+                            break;
+                        default:
+                            $bbchoices = $this->getpath($pblock,
+                                    array('#', 'response_lid', 0, '#', 'render_choice', 0, '#',
+                                    'flow_label', 0, '#', 'response_label'),
+                                    array(), false);
+                            $choices = array();
+                            $this->process_choices($bbchoices, $choices);
+                            $block->choices = $choices;
+                    }
+                    break;
+                case 'RIGHT_MATCH_BLOCK':
+                    $matchinganswerset = $this->getpath($pblock,
+                            array('#', 'flow'),
+                            false, false);
+
+                    $answerset = array();
+                    foreach ($matchinganswerset as $answer) {
+                        $bbanswer = new stdClass;
+                        $bbanswer->text =  $this->getpath($answer,
+                                array('#', 'flow', 0, '#', 'material', 0, '#', 'mat_extension',
+                                0, '#', 'mat_formattedtext', 0, '#'),
+                                false, false);
+                        $answerset[] = $bbanswer;
+                    }
+                    $block->matchinganswerset = $answerset;
+                    break;
+                default:
+                    $this->error(get_string('unhandledpresblock', 'qformat_blackboard_six'));
+                    break;
+            }
+            $rawquestion->{$block->type} = $block;
+        }
+
+        // Determine response processing.
+        // There is a section called 'outcomes' that I don't know what to do with.
+        $resprocessing = $this->getpath($quest,
+                array('#', 'resprocessing'),
+                array(), false);
+
+        $respconditions = $this->getpath($resprocessing[0],
+                array('#', 'respcondition'),
+                array(), false);
+        $responses = array();
+        if ($rawquestion->qtype == 'Matching') {
+            $this->process_matching_responses($respconditions, $responses);
+        } else {
+            $this->process_responses($respconditions, $responses);
+        }
+        $rawquestion->responses = $responses;
+        $feedbackset = $this->getpath($quest,
+                array('#', 'itemfeedback'),
+                array(), false);
+
+        $feedbacks = array();
+        $this->process_feedback($feedbackset, $feedbacks);
+        $rawquestion->feedback = $feedbacks;
+        return $rawquestion;
+    }
+
+    /**
+     * Helper function to process an XML block into an object.
+     * Can call himself recursively if necessary to parse this branch of the XML tree.
+     * @param array $curblock XML block to parse
+     * @return object $block parsed
+     */
+    public function process_block($curblock, $block) {
+
+        $curtype = $this->getpath($curblock,
+                array('@', 'class'),
+                '', true);
+
+        switch($curtype) {
+            case 'FORMATTED_TEXT_BLOCK':
+                $text = $this->getpath($curblock,
+                        array('#', 'material', 0, '#', 'mat_extension', 0, '#', 'mat_formattedtext', 0, '#'),
+                        '', true);
+                $block->text = $this->strip_applet_tags_get_mathml($text);
+                break;
+            case 'FILE_BLOCK':
+                $block->filename = $this->getpath($curblock,
+                        array('#', 'material', 0, '#'),
+                        '', true);
+                if ($block->filename != '') {
+                    // TODO : determine what to do with the file's content.
+                    $this->error(get_string('filenothandled', 'qformat_blackboard_six', $block->filename));
+                }
+                break;
+            case 'Block':
+                if ($this->getpath($curblock,
+                        array('#', 'material', 0, '#', 'mattext'),
+                        false, false)) {
+                    $block->text = $this->getpath($curblock,
+                            array('#', 'material', 0, '#', 'mattext', 0, '#'),
+                            '', true);
+                } else if ($this->getpath($curblock,
+                        array('#', 'material', 0, '#', 'mat_extension', 0, '#', 'mat_formattedtext'),
+                        false, false)) {
+                    $block->text = $this->getpath($curblock,
+                            array('#', 'material', 0, '#', 'mat_extension', 0, '#', 'mat_formattedtext', 0, '#'),
+                            '', true);
+                } else if ($this->getpath($curblock,
+                        array('#', 'response_label'),
+                        false, false)) {
+                    // This is a response label block.
+                    $subblocks = $this->getpath($curblock,
+                            array('#', 'response_label', 0),
+                            array(), false);
+                    if (!isset($block->ident)) {
+
+                        if ($this->getpath($subblocks,
+                                array('@', 'ident'), '', true)) {
+                            $block->ident = $this->getpath($subblocks,
+                                array('@', 'ident'), '', true);
+                        }
+                    }
+                    foreach ($this->getpath($subblocks,
+                            array('#', 'flow_mat'), array(), false) as $subblock) {
+                        $this->process_block($subblock, $block);
+                    }
+                } else {
+                    if ($this->getpath($curblock,
+                                array('#', 'flow_mat'), false, false)
+                            || $this->getpath($curblock,
+                                array('#', 'flow'), false, false)) {
+                        if ($this->getpath($curblock,
+                                array('#', 'flow_mat'), false, false)) {
+                            $subblocks = $this->getpath($curblock,
+                                    array('#', 'flow_mat'), array(), false);
+                        } else if ($this->getpath($curblock,
+                                array('#', 'flow'), false, false)) {
+                            $subblocks = $this->getpath($curblock,
+                                    array('#', 'flow'), array(), false);
+                        }
+                        foreach ($subblocks as $sblock) {
+                            // This will recursively grab the sub blocks which should be of one of the other types.
+                            $this->process_block($sblock, $block);
+                        }
+                    }
+                }
+                break;
+            case 'LINK_BLOCK':
+                // Not sure how this should be included?
+                $link = $this->getpath($curblock,
+                            array('#', 'material', 0, '#', 'mattext', 0, '@', 'uri'), '', true);
+                if (!empty($link)) {
+                    $block->link = $link;
+                } else {
+                    $block->link = '';
+                }
+                break;
+        }
+        return $block;
+    }
+
+    /**
+     * Preprocess XML blocks containing data for questions' choices.
+     * Called by {@link create_raw_question()}
+     * for matching, multichoice and fill in the blank questions.
+     * @param array $bbchoices XML block to parse
+     * @param array $choices array of choices suitable for a rawquestion.
+     */
+    protected function process_choices($bbchoices, &$choices) {
+        foreach ($bbchoices as $choice) {
+            if ($this->getpath($choice,
+                    array('@', 'ident'), '', true)) {
+                $curchoice = $this->getpath($choice,
+                        array('@', 'ident'), '', true);
+            } else { // For multiple answers.
+                $curchoice = $this->getpath($choice,
+                         array('#', 'response_label', 0), array(), false);
+            }
+            if ($this->getpath($choice,
+                    array('#', 'flow_mat', 0), false, false)) { // For multiple answers.
+                $curblock = $this->getpath($choice,
+                    array('#', 'flow_mat', 0), false, false);
+                // Reset $curchoice to new stdClass because process_block is expecting an object
+                // for the second argument and not a string,
+                // which is what is was set as originally - CT 8/7/06.
+                $curchoice = new stdClass();
+                $this->process_block($curblock, $curchoice);
+            } else if ($this->getpath($choice,
+                    array('#', 'response_label'), false, false)) {
+                // Reset $curchoice to new stdClass because process_block is expecting an object
+                // for the second argument and not a string,
+                // which is what is was set as originally - CT 8/7/06.
+                $curchoice = new stdClass();
+                $this->process_block($choice, $curchoice);
+            }
+            $choices[] = $curchoice;
+        }
+    }
+
+    /**
+     * Preprocess XML blocks containing data for subanswers
+     * Called by {@link create_raw_question()}
+     * for matching questions only.
+     * @param array $bbresponses XML block to parse
+     * @param array $responses array of responses suitable for a matching rawquestion.
+     */
+    protected function process_matching_responses($bbresponses, &$responses) {
+        foreach ($bbresponses as $bbresponse) {
+            $response = new stdClass;
+            if ($this->getpath($bbresponse,
+                    array('#', 'conditionvar', 0, '#', 'varequal'), false, false)) {
+                $response->correct = $this->getpath($bbresponse,
+                        array('#', 'conditionvar', 0, '#', 'varequal', 0, '#'), '', true);
+                $response->ident = $this->getpath($bbresponse,
+                        array('#', 'conditionvar', 0, '#', 'varequal', 0, '@', 'respident'), '', true);
+            }
+            // Suppressed an else block because if the above if condition is false,
+            // the question is not necessary a broken one, most of the time it's an <other> tag.
+
+            $response->feedback = $this->getpath($bbresponse,
+                    array('#', 'displayfeedback', 0, '@', 'linkrefid'), '', true);
+            $responses[] = $response;
+        }
+    }
+
+    /**
+     * Preprocess XML blocks containing data for responses processing.
+     * Called by {@link create_raw_question()}
+     * for all questions types.
+     * @param array $bbresponses XML block to parse
+     * @param array $responses array of responses suitable for a rawquestion.
+     */
+    protected function process_responses($bbresponses, &$responses) {
+        foreach ($bbresponses as $bbresponse) {
+            $response = new stdClass();
+            if ($this->getpath($bbresponse,
+                    array('@', 'title'), '', true)) {
+                $response->title = $this->getpath($bbresponse,
+                        array('@', 'title'), '', true);
+            } else {
+                $response->title = $this->getpath($bbresponse,
+                        array('#', 'displayfeedback', 0, '@', 'linkrefid'), '', true);
+            }
+            $response->ident = array();
+            if ($this->getpath($bbresponse,
+                    array('#', 'conditionvar', 0, '#'), false, false)) {
+                $response->ident[0] = $this->getpath($bbresponse,
+                        array('#', 'conditionvar', 0, '#'), array(), false);
+            } else if ($this->getpath($bbresponse,
+                    array('#', 'conditionvar', 0, '#', 'other', 0, '#'), false, false)) {
+                $response->ident[0] = $this->getpath($bbresponse,
+                        array('#', 'conditionvar', 0, '#', 'other', 0, '#'), array(), false);
+            }
+            if ($this->getpath($bbresponse,
+                    array('#', 'conditionvar', 0, '#', 'and'), false, false)) {
+                $responseset = $this->getpath($bbresponse,
+                    array('#', 'conditionvar', 0, '#', 'and'), array(), false);
+                foreach ($responseset as $rs) {
+                    $response->ident[] = $this->getpath($rs, array('#'), array(), false);
+                    if (!isset($response->feedback) and $this->getpath($rs, array('@'), false, false)) {
+                        $response->feedback = $this->getpath($rs,
+                                array('@', 'respident'), '', true);
+                    }
+                }
+            } else {
+                $response->feedback = $this->getpath($bbresponse,
+                        array('#', 'displayfeedback', 0, '@', 'linkrefid'), '', true);
+            }
+
+            // Determine what fraction to give response.
+            if ($this->getpath($bbresponse,
+                        array('#', 'setvar'), false, false)) {
+                switch ($this->getpath($bbresponse,
+                        array('#', 'setvar', 0, '#'), false, false)) {
+                    case "SCORE.max":
+                        $response->fraction = 1;
+                        break;
+                    default:
+                        // I have only seen this being 0 or unset.
+                        // There are probably fractional values of SCORE.max, but I'm not sure what they look like.
+                        $response->fraction = 0;
+                        break;
+                }
+            } else {
+                // Just going to assume this is the case this is probably not correct.
+                $response->fraction = 0;
+            }
+
+            $responses[] = $response;
+        }
+    }
+
+    /**
+     * Preprocess XML blocks containing data for responses feedbacks.
+     * Called by {@link create_raw_question()}
+     * for all questions types.
+     * @param array $feedbackset XML block to parse
+     * @param array $feedbacks array of feedbacks suitable for a rawquestion.
+     */
+    public function process_feedback($feedbackset, &$feedbacks) {
+        foreach ($feedbackset as $bb_feedback) {
+            $feedback = new stdClass();
+            $feedback->ident = $this->getpath($bb_feedback,
+                    array('@', 'ident'), '', true);
+            $feedback->text = '';
+            if ($this->getpath($bb_feedback,
+                    array('#', 'flow_mat', 0), false, false)) {
+                $this->process_block($this->getpath($bb_feedback,
+                        array('#', 'flow_mat', 0), false, false), $feedback);
+            } else if ($this->getpath($bb_feedback,
+                    array('#', 'solution', 0, '#', 'solutionmaterial', 0, '#', 'flow_mat', 0), false, false)) {
+                $this->process_block($this->getpath($bb_feedback,
+                        array('#', 'solution', 0, '#', 'solutionmaterial', 0, '#', 'flow_mat', 0), false, false), $feedback);
+            }
+
+            $feedbacks[$feedback->ident] = $feedback;
+        }
+    }
+
+    /**
+     * Create common parts of question
+     * @param object $quest rawquestion
+     * @return object Moodle question.
+     */
+    public function process_common($quest) {
+        $question = $this->defaultquestion();
+        $text = $quest->QUESTION_BLOCK->text;
+
+        $question->questiontext = $this->cleaned_text_field($text);
+        $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
+
+        $question->name = shorten_text(strip_tags($question->questiontext['text']), 200);
+        $question->name = substr($question->name, 0, 250);
+        if (!$question->name) {
+            $question->name = get_string('defaultname', 'qformat_blackboard_six' , $quest->id);
+        }
+        $question->generalfeedback = '';
+        $question->generalfeedbackformat = FORMAT_HTML;
+        $question->generalfeedbackfiles = array();
+
+        return $question;
+    }
+
+    /**
+     * Process True / False Questions
+     * Parse a truefalse rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    protected function process_tf($quest, &$questions) {
+        $question = $this->process_common($quest);
+
+        $question->qtype = 'truefalse';
+        $question->single = 1; // Only one answer is allowed.
+        $question->penalty = 1; // Penalty = 1 for truefalse questions.
+        // 0th [response] is the correct answer.
+        $responses = $quest->responses;
+        $correctresponse = $this->getpath($responses[0]->ident[0],
+                array('varequal', 0, '#'), '', true);
+        if ($correctresponse != 'false') {
+            $correct = true;
+        } else {
+            $correct = false;
+        }
+        $fback = new stdClass();
+
+        foreach ($quest->feedback as $fb) {
+            $fback->{$fb->ident} = $fb->text;
+        }
+
+        if ($correct) {  // True is correct.
+            $question->answer = 1;
+            $question->feedbacktrue = $this->cleaned_text_field($fback->correct);
+            $question->feedbackfalse = $this->cleaned_text_field($fback->incorrect);
+        } else {  // False is correct.
+            $question->answer = 0;
+            $question->feedbacktrue = $this->cleaned_text_field($fback->incorrect);
+            $question->feedbackfalse = $this->cleaned_text_field($fback->correct);
+        }
+        $question->correctanswer = $question->answer;
+        $questions[] = $question;
+    }
+
+    /**
+     * Process Fill in the Blank Questions
+     * Parse a fillintheblank rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    protected function process_fblank($quest, &$questions) {
+        $question = $this->process_common($quest);
+        $question->qtype = 'shortanswer';
+        $question->usecase = 0; // Ignore case.
+
+        $answers = array();
+        $fractions = array();
+        $feedbacks = array();
+
+        // Extract the feedback.
+        $feedback = array();
+        foreach ($quest->feedback as $fback) {
+            if (isset($fback->ident)) {
+                if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {
+                    $feedback[$fback->ident] = $fback->text;
+                }
+            }
+        }
+
+        foreach ($quest->responses as $response) {
+            if (isset($response->title)) {
+                if ($this->getpath($response->ident[0],
+                        array('varequal', 0, '#'), false, false)) {
+                    // For BB Fill in the Blank, only interested in correct answers.
+                    if ($response->feedback = 'correct') {
+                        $answers[] = $this->getpath($response->ident[0],
+                                array('varequal', 0, '#'), '', true);
+                        $fractions[] = 1;
+                        if (isset($feedback['correct'])) {
+                            $feedbacks[] = $this->cleaned_text_field($feedback['correct']);
+                        } else {
+                            $feedbacks[] = $this->text_field('');
+                        }
+                    }
+                }
+
+            }
+        }
+
+        // Adding catchall to so that students can see feedback for incorrect answers when they enter something,
+        // the instructor did not enter.
+        $answers[] = '*';
+        $fractions[] = 0;
+        if (isset($feedback['incorrect'])) {
+            $feedbacks[] = $this->cleaned_text_field($feedback['incorrect']);
+        } else {
+            $feedbacks[] = $this->text_field('');
+        }
+
+        $question->answer = $answers;
+        $question->fraction = $fractions;
+        $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of.
+
+        if (!empty($question)) {
+            $questions[] = $question;
+        }
+
+    }
+
+    /**
+     * Process Multichoice Questions
+     * Parse a multichoice single answer rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    protected function process_mc($quest, &$questions) {
+        $question = $this->process_common($quest);
+        $question->qtype = 'multichoice';
+        $question = $this->add_blank_combined_feedback($question);
+        $question->single = 1;
+        $feedback = array();
+        foreach ($quest->feedback as $fback) {
+            $feedback[$fback->ident] = $fback->text;
+        }
+
+        foreach ($quest->responses as $response) {
+            if (isset($response->title)) {
+                if ($response->title == 'correct') {
+                    // Only one answer possible for this qtype so first index is correct answer.
+                    $correct = $this->getpath($response->ident[0],
+                            array('varequal', 0, '#'), '', true);
+                }
+            } else {
+                // Fallback method for when the title is not set.
+                if ($response->feedback == 'correct') {
+                    // Only one answer possible for this qtype so first index is correct answer.
+                    $correct = $this->getpath($response->ident[0],
+                            array('varequal', 0, '#'), '', true);
+                }
+            }
+        }
+
+        $i = 0;
+        foreach ($quest->RESPONSE_BLOCK->choices as $response) {
+            $question->answer[$i] = $this->cleaned_text_field($response->text);
+            if ($correct == $response->ident) {
+                $question->fraction[$i] = 1;
+                // This is a bit of a hack to catch the feedback... first we see if a  'specific'
+                // feedback for this response exists, then if a 'correct' feedback exists.
+
+                if (!empty($feedback[$response->ident]) ) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$response->ident]);
+                } else if (!empty($feedback['correct'])) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback['correct']);
+                } else if (!empty($feedback[$i])) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$i]);
+                } else {
+                    $question->feedback[$i] = $this->cleaned_text_field(get_string('correct', 'question'));
+                }
+            } else {
+                $question->fraction[$i] = 0;
+                if (!empty($feedback[$response->ident]) ) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$response->ident]);
+                } else if (!empty($feedback['incorrect'])) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback['incorrect']);
+                } else if (!empty($feedback[$i])) {
+                    $question->feedback[$i] = $this->cleaned_text_field($feedback[$i]);
+                } else {
+                    $question->feedback[$i] = $this->cleaned_text_field(get_string('incorrect', 'question'));
+                }
+            }
+            $i++;
+        }
+
+        if (!empty($question)) {
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Process Multiple Choice Questions With Multiple Answers.
+     * Parse a multichoice multianswer rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    public function process_ma($quest, &$questions) {
+        $question = $this->process_common($quest);
+        $question->qtype = 'multichoice';
+        $question = $this->add_blank_combined_feedback($question);
+        $question->single = 0; // More than one answer allowed.
+
+        $answers = $quest->responses;
+        $correctanswers = array();
+        foreach ($answers as $answer) {
+            if ($answer->title == 'correct') {
+                $answerset = $this->getpath($answer->ident[0],
+                        array('and', 0, '#', 'varequal'), array(), false);
+                foreach ($answerset as $ans) {
+                    $correctanswers[] = $ans['#'];
+                }
+            }
+        }
+        $feedback = new stdClass();
+        foreach ($quest->feedback as $fb) {
+            $feedback->{$fb->ident} = trim($fb->text);
+        }
+
+        $correctanswercount = count($correctanswers);
+        $fraction = 1/$correctanswercount;
+        $choiceset = $quest->RESPONSE_BLOCK->choices;
+        $i = 0;
+        foreach ($choiceset as $choice) {
+            $question->answer[$i] = $this->cleaned_text_field(trim($choice->text));
+            if (in_array($choice->ident, $correctanswers)) {
+                // Correct answer.
+                $question->fraction[$i] = $fraction;
+                $question->feedback[$i] = $this->cleaned_text_field($feedback->correct);
+            } else {
+                // Wrong answer.
+                $question->fraction[$i] = 0;
+                $question->feedback[$i] = $this->cleaned_text_field($feedback->incorrect);
+            }
+            $i++;
+        }
+
+        $questions[] = $question;
+    }
+
+    /**
+     * Process Essay Questions
+     * Parse an essay rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    public function process_essay($quest, &$questions) {
+
+        $question = $this->process_common($quest);
+        $question->qtype = 'essay';
+
+        $question->feedback = array();
+        // Not sure where to get the correct answer from?
+        foreach ($quest->feedback as $feedback) {
+            // Added this code to put the possible solution that the
+            // instructor gives as the Moodle answer for an essay question.
+            if ($feedback->ident == 'solution') {
+                $question->graderinfo = $this->cleaned_text_field($feedback->text);
+            }
+        }
+        // Added because essay/questiontype.php:save_question_option is expecting a
+        // fraction property - CT 8/10/06.
+        $question->fraction[] = 1;
+        $question->defaultmark = 1;
+        $question->responseformat = 'editor';
+        $question->responsefieldlines = 15;
+        $question->attachments = 0;
+
+        $questions[]=$question;
+    }
+
+    /**
+     * Process Matching Questions
+     * Parse a matching rawquestion and add the result
+     * to the array of questions already parsed.
+     * @param object $quest rawquestion
+     * @param $questions array of Moodle questions already done.
+     */
+    public function process_matching($quest, &$questions) {
+
+        // Blackboard matching questions can't be imported in core Moodle without a loss in data,
+        // as core match question don't allow HTML in subanswers. The contributed ddmatch
+        // question type support HTML in subanswers.
+        // The ddmatch question type is not part of core, so we need to check if it is defined.
+        $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
+
+        $question = $this->process_common($quest);
+        $question = $this->add_blank_combined_feedback($question);
+        $question->valid = true;
+        if ($ddmatchisinstalled) {
+            $question->qtype = 'ddmatch';
+        } else {
+            $question->qtype = 'match';
+        }
+        // Construction of the array holding mappings between subanswers and subquestions.
+        foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
+            foreach ($quest->responses as $rid => $resp) {
+                if (isset($resp->ident) && $resp->ident == $subq->ident) {
+                    $correct = $resp->correct;
+                }
+            }
+
+            foreach ($subq->choices as $cid => $choice) {
+                if ($choice == $correct) {
+                    $mappings[$subq->ident] = $cid;
+                }
+            }
+        }
+
+        foreach ($subq->choices as $choiceid => $choice) {
+            $subanswertext = $quest->RIGHT_MATCH_BLOCK->matchinganswerset[$choiceid]->text;
+            if ($ddmatchisinstalled) {
+                $subanswer = $this->cleaned_text_field($subanswertext);
+            } else {
+                $subanswertext = html_to_text($this->cleaninput($subanswertext), 0);
+                $subanswer = $subanswertext;
+            }
+
+            if ($subanswertext != '') { // Only import non empty subanswers.
+                $subquestion = '';
+
+                $fiber = array_keys ($mappings, $choiceid);
+                foreach ($fiber as $correctanswerid) {
+                    // We have found a correspondance for this subanswer so we need to take the associated subquestion.
+                    foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
+                        $currentsubqid = $subq->ident;
+                        if (strcmp ($currentsubqid, $correctanswerid) == 0) {
+                            $subquestion = $subq->text;
+                            break;
+                        }
+                    }
+                    $question->subquestions[] = $this->cleaned_text_field($subquestion);
+                    $question->subanswers[] = $subanswer;
+                }
+
+                if ($subquestion == '') { // Then in this case, $choice is a distractor.
+                    $question->subquestions[] = $this->text_field('');
+                    $question->subanswers[] = $subanswer;
+                }
+            }
+        }
+
+        // Verify that this matching question has enough subquestions and subanswers.
+        $subquestioncount = 0;
+        $subanswercount = 0;
+        $subanswers = $question->subanswers;
+        foreach ($question->subquestions as $key => $subquestion) {
+            $subquestion = $subquestion['text'];
+            $subanswer = $subanswers[$key];
+            if ($subquestion != '') {
+                $subquestioncount++;
+            }
+            $subanswercount++;
+        }
+        if ($subquestioncount < 2 || $subanswercount < 3) {
+                $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext['text']));
+        } else {
+            $questions[] = $question;
+        }
+    }
+
+    /**
+     * Strip the applet tag used by Blackboard to render mathml formulas,
+     * keeping the mathml tag.
+     * @param string $string
+     * @return string
+     */
+    public function strip_applet_tags_get_mathml($string) {
+        if (stristr($string, '</APPLET>') === false) {
+            return $string;
+        } else {
+            // Strip all applet tags keeping stuff before/after and inbetween (if mathml) them.
+            while (stristr($string, '</APPLET>') !== false) {
+                preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i", $string, $mathmls);
+                $string = $mathmls[1].$mathmls[2].$mathmls[3];
+            }
+            return $string;
+        }
+    }
+
+}
diff --git a/question/format/blackboard_six/lang/en/qformat_blackboard_six.php b/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
index 75ff1e1..020c7a2 100644
--- a/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
+++ b/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
@@ -17,11 +17,18 @@
 /**
  * Strings for component 'qformat_blackboard_six', language 'en', branch 'MOODLE_20_STABLE'
  *
- * @package    qformat
- * @subpackage blackboard_six
+ * @package    qformat_blackboard_six
  * @copyright  2010 Helen Foster
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['defaultname'] = 'Imported question {$a}';
+$string['errormanifest'] = 'Error while parsing the IMS manifest document';
+$string['importnotext'] = 'Missing question text in XML file';
+$string['filenothandled'] = 'This archive contains reference to a file material {$a} wich is not currently handled by import';
+$string['imagenotfound'] = 'Image file with path {$a} was not found in the import.';
+$string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
 $string['pluginname'] = 'Blackboard V6+';
-$string['pluginname_help'] = 'Blackboard V6+ format enables questions saved in Blackboard\'s export format to be imported via zip file. It provides limited support for Blackboard Version 6 and 7.';
+$string['pluginname_help'] = 'Blackboard V6+ format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
+$string['unhandledpresblock'] = 'Unhandled presentation bloc';
+$string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
diff --git a/question/format/blackboard_six/tests/blackboardformatpool_test.php b/question/format/blackboard_six/tests/blackboardformatpool_test.php
new file mode 100644
index 0000000..22cadb7
--- /dev/null
+++ b/question/format/blackboard_six/tests/blackboardformatpool_test.php
@@ -0,0 +1,330 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the Moodle Blackboard V6+ format.
+ *
+ * @package    qformat_blackboard_six
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/blackboard_six/format.php');
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the blackboard question import format.
+ *
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_blackboard_six_pool_test extends question_testcase {
+
+    public function make_test_xml() {
+        $xml = file_get_contents(__DIR__ . '/fixtures/sample_blackboard_pool.dat');
+        return array(0=>$xml);
+    }
+
+    public function test_import_match() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+
+        $q = $questions[4];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'match';
+        $expectedq->name = 'Classify the animals.';
+        $expectedq->questiontext = array(
+                'text' => '<i>Classify the animals.</i>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML);
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML);
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML);
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->subquestions = array(
+            array('text' => 'cat', 'format' => FORMAT_HTML),
+            array('text' => '', 'format' => FORMAT_HTML),
+            array('text' => 'frog', 'format' => FORMAT_HTML),
+            array('text' => 'newt', 'format' => FORMAT_HTML));
+        $expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian');
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_single() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[1];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 1;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = array(
+                'text' =>'<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML);
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML);
+        $expectedq->incorrectfeedback = array('text' => 'Only yellow is between orange and green in the spectrum.',
+                'format' => FORMAT_HTML);
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                )
+            );
+        $expectedq->fraction = array(0, 1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_multi() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[2];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 0;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array(
+                'text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->partiallycorrectfeedback = array(
+                'text' => 'Only yellow and off-beige are between orange and green in the spectrum.',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->incorrectfeedback = array(
+                'text' => 'Only yellow and off-beige are between orange and green in the spectrum.',
+                'format' => FORMAT_HTML,
+                );
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">off-beige</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                3 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                )
+            );
+        $expectedq->fraction = array(0.5, 0, 0.5, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                3 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_truefalse() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'truefalse';
+        $expectedq->name = '42 is the Absolute Answer to everything.';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->correctanswer = 0;
+        $expectedq->feedbacktrue = array(
+                'text' => '42 is the Ultimate Answer.',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->feedbackfalse = array(
+                'text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML,
+            );
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_fill_in_the_blank() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[3];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'shortanswer';
+        $expectedq->name = 'Name an amphibian: __________.';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">Name an amphibian: __________.</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->usecase = 0;
+        $expectedq->answer = array('frog', '*');
+        $expectedq->fraction = array(1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_essay() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(2);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[5];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'essay';
+        $expectedq->name = 'How are you?';
+        $expectedq->questiontext = array(
+                'text' => 'How are you?',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->responseformat = 'editor';
+        $expectedq->responsefieldlines = 15;
+        $expectedq->attachments = 0;
+        $expectedq->graderinfo = array(
+                'text' => 'Blackboard answer for essay questions will be imported as informations for graders.',
+                'format' => FORMAT_HTML,
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+}
diff --git a/question/format/blackboard_six/tests/blackboardsixformatqti_test.php b/question/format/blackboard_six/tests/blackboardsixformatqti_test.php
new file mode 100644
index 0000000..68df181
--- /dev/null
+++ b/question/format/blackboard_six/tests/blackboardsixformatqti_test.php
@@ -0,0 +1,330 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the Moodle Blackboard V6+ format.
+ *
+ * @package    qformat_blackboard_six
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/blackboard_six/format.php');
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the blackboard question import format.
+ *
+ * @copyright  2012 Jean-Michel Vedrine
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_blackboard_six_qti_test extends question_testcase {
+
+    public function make_test_xml() {
+        $xml = file_get_contents(__DIR__ . '/fixtures/sample_blackboard_qti.dat');
+        return array(0=>$xml);
+    }
+    public function test_import_match() {
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[3];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'match';
+        $expectedq->name = 'Classify the animals.';
+        $expectedq->questiontext = array(
+                'text' => 'Classify the animals.',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->subquestions = array(
+            array('text' => '', 'format' => FORMAT_HTML),
+            array('text' => 'cat', 'format' => FORMAT_HTML),
+            array('text' => 'frog', 'format' => FORMAT_HTML),
+            array('text' => 'newt', 'format' => FORMAT_HTML));
+        $expectedq->subanswers = array('insect', 'mammal', 'amphibian', 'amphibian');
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_single() {
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[1];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 1;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">What\'s between orange and green in the spectrum?</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->partiallycorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->incorrectfeedback = array('text' => '',
+                'format' => FORMAT_HTML, 'files' => array());
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                )
+            );
+        $expectedq->fraction = array(0, 1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => 'Red is not between orange and green in the spectrum but yellow is.',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => 'You gave the right answer.',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => 'Blue is not between orange and green in the spectrum but yellow is.',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_multichoice_multi() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[2];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'multichoice';
+        $expectedq->single = 0;
+        $expectedq->name = 'What\'s between orange and green in the spectrum?';
+        $expectedq->questiontext = array(
+                'text' => '<i>What\'s between orange and green in the spectrum?</i>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->correctfeedback = array(
+                'text' => '',
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $expectedq->partiallycorrectfeedback = array(
+                'text' => '',
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $expectedq->incorrectfeedback = array(
+                'text' => '',
+                'format' => FORMAT_HTML,
+                'files' => array(),
+            );
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->penalty = 0.3333333;
+        $expectedq->shuffleanswers = get_config('quiz', 'shuffleanswers');
+        $expectedq->answer = array(
+                0 => array(
+                    'text' => '<span style="font-size:12pt">yellow</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '<span style="font-size:12pt">red</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '<span style="font-size:12pt">off-beige</span>',
+                    'format' => FORMAT_HTML,
+                ),
+                3 => array(
+                    'text' => '<span style="font-size:12pt">blue</span>',
+                    'format' => FORMAT_HTML,
+                )
+            );
+        $expectedq->fraction = array(0.5, 0, 0.5, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                2 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                ),
+                3 => array(
+                    'text' => '',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_truefalse() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[0];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'truefalse';
+        $expectedq->name = '42 is the Absolute Answer to everything.';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->correctanswer = 0;
+        $expectedq->feedbacktrue = array(
+                'text' => '42 is the <b>Ultimate</b> Answer.',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->feedbackfalse = array(
+                'text' => 'You gave the right answer.',
+                'format' => FORMAT_HTML,
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_fill_in_the_blank() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[4];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'shortanswer';
+        $expectedq->name = 'Name an amphibian: __________.';
+        $expectedq->questiontext = array(
+                'text' => '<span style="font-size:12pt">Name an amphibian: __________.</span>',
+                'format' => FORMAT_HTML,
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->usecase = 0;
+        $expectedq->answer = array('frog', '*');
+        $expectedq->fraction = array(1, 0);
+        $expectedq->feedback = array(
+                0 => array(
+                    'text' => 'A frog is an amphibian.',
+                    'format' => FORMAT_HTML,
+                ),
+                1 => array(
+                    'text' => 'A frog is an amphibian.',
+                    'format' => FORMAT_HTML,
+                )
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+
+    public function test_import_essay() {
+
+        $xml = $this->make_test_xml();
+
+        $importer = new qformat_blackboard_six();
+        $importer->set_filetype(1);
+        $questions = $importer->readquestions($xml);
+        $q = $questions[5];
+
+        $expectedq = new stdClass();
+        $expectedq->qtype = 'essay';
+        $expectedq->name = 'How are you?';
+        $expectedq->questiontext = array(
+                'text' => 'How are you?',
+                'format' => FORMAT_HTML
+            );
+        $expectedq->questiontextformat = FORMAT_HTML;
+        $expectedq->generalfeedback = '';
+        $expectedq->generalfeedbackformat = FORMAT_HTML;
+        $expectedq->defaultmark = 1;
+        $expectedq->length = 1;
+        $expectedq->responseformat = 'editor';
+        $expectedq->responsefieldlines = 15;
+        $expectedq->attachments = 0;
+        $expectedq->graderinfo = array(
+                'text' => 'Blackboard answer for essay questions will be imported as informations for graders.',
+                'format' => FORMAT_HTML,
+            );
+
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
+    }
+}
diff --git a/question/format/blackboard_six/tests/fixtures/sample_blackboard_pool.dat b/question/format/blackboard_six/tests/fixtures/sample_blackboard_pool.dat
new file mode 100644
index 0000000..93bb583
--- /dev/null
+++ b/question/format/blackboard_six/tests/fixtures/sample_blackboard_pool.dat
@@ -0,0 +1,142 @@
+<?xml version='1.0' encoding='utf-8'?>
+<POOL>
+    <TITLE value='exam 3 2008-9'/>
+    <QUESTIONLIST>
+        <QUESTION id='q1' class='QUESTION_TRUEFALSE' points='1'/>
+        <QUESTION id='q7' class='QUESTION_MULTIPLECHOICE' points='1'/>
+        <QUESTION id='q8' class='QUESTION_MULTIPLEANSWER' points='1'/>
+        <QUESTION id='q39-44' class='QUESTION_MATCH' points='1'/>
+        <QUESTION id='q9' class='QUESTION_ESSAY' points='1'/>
+        <QUESTION id='q27' class='QUESTION_FILLINBLANK' points='1'/>
+    </QUESTIONLIST>
+    <QUESTION_TRUEFALSE id='q1'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">42 is the Absolute Answer to everything.</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q1_a1'>
+            <TEXT>False</TEXT>
+        </ANSWER>
+        <ANSWER id='q1_a2'>
+            <TEXT>True</TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q1_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[42 is the Ultimate Answer.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_TRUEFALSE>
+    <QUESTION_MULTIPLECHOICE id='q7'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q7_a1' position='1'>
+        <TEXT><![CDATA[<span style="font-size:12pt">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a2' position='2'>
+        <TEXT><![CDATA[<span style="font-size:12pt">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q7_a3' position='3'>
+        <TEXT><![CDATA[<span style="font-size:12pt">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q7_a2'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow is between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_MULTIPLECHOICE>
+    <QUESTION_MULTIPLEANSWER id='q8'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">What's between orange and green in the spectrum?</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q8_a1' position='1'>
+        <TEXT><![CDATA[<span style="font-size:12pt">yellow</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a2' position='2'>
+        <TEXT><![CDATA[<span style="font-size:12pt">red</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a3' position='3'>
+        <TEXT><![CDATA[<span style="font-size:12pt">off-beige</span>]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q8_a4' position='4'>
+        <TEXT><![CDATA[<span style="font-size:12pt">blue</span>]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q8_a1'/>
+            <CORRECTANSWER answer_id='q8_a3'/>
+            <FEEDBACK_WHEN_CORRECT><![CDATA[You gave the right answer.]]></FEEDBACK_WHEN_CORRECT>
+            <FEEDBACK_WHEN_INCORRECT><![CDATA[Only yellow and off-beige are between orange and green in the spectrum.]]></FEEDBACK_WHEN_INCORRECT>
+        </GRADABLE>
+    </QUESTION_MULTIPLEANSWER>
+    <QUESTION_MATCH id='q39-44'>
+        <BODY>
+            <TEXT><![CDATA[<i>Classify the animals.</i>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q39-44_a1' position='1'>
+            <TEXT><![CDATA[frog]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a2' position='2'>
+            <TEXT><![CDATA[cat]]></TEXT>
+        </ANSWER>
+        <ANSWER id='q39-44_a3' position='3'>
+            <TEXT><![CDATA[newt]]></TEXT>
+        </ANSWER>
+        <CHOICE id='q39-44_c1' position='1'>
+            <TEXT><![CDATA[mammal]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c2' position='2'>
+            <TEXT><![CDATA[insect]]></TEXT>
+        </CHOICE>
+        <CHOICE id='q39-44_c3' position='3'>
+            <TEXT><![CDATA[amphibian]]></TEXT>
+        </CHOICE>
+        <GRADABLE>
+            <CORRECTANSWER answer_id='q39-44_a1' choice_id='q39-44_c3'/>
+            <CORRECTANSWER answer_id='q39-44_a2' choice_id='q39-44_c1'/>
+            <CORRECTANSWER answer_id='q39-44_a3' choice_id='q39-44_c3'/>
+        </GRADABLE>
+    </QUESTION_MATCH>
+    <QUESTION_ESSAY id='q9'>
+        <BODY>
+            <TEXT><![CDATA[How are you?]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q9_a1'>
+            <TEXT><![CDATA[Blackboard answer for essay questions will be imported as informations for graders.]]></TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_ESSAY>
+    <QUESTION_FILLINBLANK id='q27'>
+        <BODY>
+            <TEXT><![CDATA[<span style="font-size:12pt">Name an amphibian: __________.</span>]]></TEXT>
+            <FLAGS>
+                <ISHTML value='true'/>
+                <ISNEWLINELITERAL value='false'/>
+            </FLAGS>
+        </BODY>
+        <ANSWER id='q27_a1' position='1'>
+            <TEXT>frog</TEXT>
+        </ANSWER>
+        <GRADABLE>
+        </GRADABLE>
+    </QUESTION_FILLINBLANK>
+</POOL>
diff --git a/question/format/blackboard_six/tests/fixtures/sample_blackboard_qti.dat b/question/format/blackboard_six/tests/fixtures/sample_blackboard_qti.dat
new file mode 100644
index 0000000..4705c2b
--- /dev/null
+++ b/question/format/blackboard_six/tests/fixtures/sample_blackboard_qti.dat
@@ -0,0 +1,1058 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<questestinterop>
+    <assessment title="sample_blackboard_six">
+        <section>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>E03EE0034702442C9306629CBF618049</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>True/False</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,1.0</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>1.0</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;42 is the Absolute Answer to everything.&lt;/span&gt;</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <response_lid ident="response" rcardinality="Single" rtiming="No">
+                                <render_choice maxnumber="0" minnumber="0" shuffle="No">
+                                    <flow_label class="Block">
+                                        <response_label ident="true" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="Block">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" xml:space="default">true</mattext>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                        <response_label ident="false" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="Block">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" xml:space="default">false</mattext>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                </render_choice>
+                            </response_lid>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="1.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition title="correct">
+                        <conditionvar>
+                            <varequal case="No" respident="response">false</varequal>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">SCORE.max</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML">You gave the right answer.</mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML">42 is the &lt;b&gt;Ultimate&lt;/b&gt; Answer.</mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+            </item>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>C74698725FFD4F85A692662108608D53</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>Multiple Choice</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,1.0</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>1.0</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;What's between orange and green in the spectrum?&lt;/span&gt;</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <response_lid ident="response" rcardinality="Single" rtiming="No">
+                                <render_choice maxnumber="0" minnumber="0" shuffle="Yes">
+                                    <flow_label class="Block">
+                                        <response_label ident="7C2A0246CE8D46599FC0120BAE9FC92D" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;red&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                    <flow_label class="Block">
+                                        <response_label ident="2CBE1E044DE54F8395BDE7877A57837A" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;yellow&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                    <flow_label class="Block">
+                                        <response_label ident="67A8748A0883467FB45328E922C31D29" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;blue&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                </render_choice>
+                            </response_lid>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="1.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition title="correct">
+                        <conditionvar>
+                            <varequal case="No" respident="response">2CBE1E044DE54F8395BDE7877A57837A</varequal>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">SCORE.max</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="7C2A0246CE8D46599FC0120BAE9FC92D" view="All">
+                    <solution feedbackstyle="Complete" view="All">
+                        <solutionmaterial>
+                            <flow_mat class="Block">
+                                <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">Red is not between orange and green in the spectrum but yellow is.</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow_mat>
+                                <flow_mat class="FILE_BLOCK">
+                                    <material/>
+                                </flow_mat>
+                                <flow_mat class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow_mat>
+                            </flow_mat>
+                        </solutionmaterial>
+                    </solution>
+                </itemfeedback>
+                <itemfeedback ident="2CBE1E044DE54F8395BDE7877A57837A" view="All">
+                    <solution feedbackstyle="Complete" view="All">
+                        <solutionmaterial>
+                            <flow_mat class="Block">
+                                <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">You gave the right answer.</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow_mat>
+                                <flow_mat class="FILE_BLOCK">
+                                    <material/>
+                                </flow_mat>
+                                <flow_mat class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow_mat>
+                            </flow_mat>
+                        </solutionmaterial>
+                    </solution>
+                </itemfeedback>
+                <itemfeedback ident="67A8748A0883467FB45328E922C31D29" view="All">
+                    <solution feedbackstyle="Complete" view="All">
+                        <solutionmaterial>
+                            <flow_mat class="Block">
+                                <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">Blue is not between orange and green in the spectrum but yellow is.</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow_mat>
+                                <flow_mat class="FILE_BLOCK">
+                                    <material/>
+                                </flow_mat>
+                                <flow_mat class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow_mat>
+                            </flow_mat>
+                        </solutionmaterial>
+                    </solution>
+                </itemfeedback>
+            </item>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>C18C56154AA04D56A4AE2FE430F4F49D</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>Multiple Answer</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,1.0</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>1.0</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">&lt;i&gt;What's between orange and green in the spectrum?&lt;/i&gt;</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <response_lid ident="response" rcardinality="Multiple" rtiming="No">
+                                <render_choice maxnumber="0" minnumber="0" shuffle="Yes">
+                                    <flow_label class="Block">
+                                        <response_label ident="76CA08C366984445AC94B0244D1DBF4A" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;yellow&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                    <flow_label class="Block">
+                                        <response_label ident="FEC2A9886C8B498787A573C9181C9698" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;red&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                    <flow_label class="Block">
+                                        <response_label ident="7F66D24D2CAA472EA728773D46706DF3" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;off-beige&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                    <flow_label class="Block">
+                                        <response_label ident="547B16C1D788446396618EDD0A41D623" rarea="Ellipse" rrange="Exact" shuffle="Yes">
+                                            <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                                <material>
+                                                    <mat_extension>
+                                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;blue&lt;/span&gt;</mat_formattedtext>
+                                                    </mat_extension>
+                                                </material>
+                                            </flow_mat>
+                                            <flow_mat class="FILE_BLOCK">
+                                                <material/>
+                                            </flow_mat>
+                                            <flow_mat class="LINK_BLOCK">
+                                                <material>
+                                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                                </material>
+                                            </flow_mat>
+                                        </response_label>
+                                    </flow_label>
+                                </render_choice>
+                            </response_lid>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="1.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition title="correct">
+                        <conditionvar>
+                            <and>
+                                <varequal case="No" respident="response">76CA08C366984445AC94B0244D1DBF4A</varequal>
+                                <not>
+                                    <varequal case="No" respident="response">FEC2A9886C8B498787A573C9181C9698</varequal>
+                                </not>
+                                <varequal case="No" respident="response">7F66D24D2CAA472EA728773D46706DF3</varequal>
+                                <not>
+                                    <varequal case="No" respident="response">547B16C1D788446396618EDD0A41D623</varequal>
+                                </not>
+                            </and>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">SCORE.max</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+            </item>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>9C5DBA6A142A4B5887C61D333CFFEDA9</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>Matching</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,3</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>3</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">Classify the animals.</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">cat</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                                <response_lid ident="6D3235200B3F43DFA8FA13E2B31BB40B" rcardinality="Single" rtiming="No">
+                                    <render_choice maxnumber="0" minnumber="0" shuffle="Yes">
+                                        <flow_label class="Block">
+                                            <response_label ident="2F591AA030B240EF869FD56392FC41BC" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="D75FEB705DCE41D59106659A2F94D819" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="207B18A11C4B42BF87882A4BAF3CC805" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                        </flow_label>
+                                    </render_choice>
+                                </response_lid>
+                            </flow>
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">frog</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                                <response_lid ident="0933892218204F5AB561E62A27701447" rcardinality="Single" rtiming="No">
+                                    <render_choice maxnumber="0" minnumber="0" shuffle="Yes">
+                                        <flow_label class="Block">
+                                            <response_label ident="2C1FB19B5F9A4F7A85E798B9C46B8BF8" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="0EEF502254D2496FB21FFD82B0A7F2B9" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="8A9B69A93B0943AFAB890702199AB290" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                        </flow_label>
+                                    </render_choice>
+                                </response_lid>
+                            </flow>
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">newt</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                                <response_lid ident="80F56B540A44490B8E94EC71C4584722" rcardinality="Single" rtiming="No">
+                                    <render_choice maxnumber="0" minnumber="0" shuffle="Yes">
+                                        <flow_label class="Block">
+                                            <response_label ident="1D066C2DAEF349EB8E7845B339B0A4A9" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="F2FB88DFE0D04DBEBD42B961728CA022" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                            <response_label ident="4D1F5B3DB0EB4C41A0012625750DF86C" rarea="Ellipse" rrange="Exact" shuffle="Yes"/>
+                                        </flow_label>
+                                    </render_choice>
+                                </response_lid>
+                            </flow>
+                        </flow>
+                        <flow class="RIGHT_MATCH_BLOCK">
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">insect</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                            </flow>
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">mammal</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                            </flow>
+                            <flow class="Block">
+                                <flow class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">amphibian</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow>
+                                <flow class="FILE_BLOCK">
+                                    <material/>
+                                </flow>
+                                <flow class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow>
+                            </flow>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="3.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition>
+                        <conditionvar>
+                            <varequal case="No" respident="6D3235200B3F43DFA8FA13E2B31BB40B">D75FEB705DCE41D59106659A2F94D819</varequal>
+                        </conditionvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition>
+                        <conditionvar>
+                            <varequal case="No" respident="0933892218204F5AB561E62A27701447">8A9B69A93B0943AFAB890702199AB290</varequal>
+                        </conditionvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition>
+                        <conditionvar>
+                            <varequal case="No" respident="80F56B540A44490B8E94EC71C4584722">4D1F5B3DB0EB4C41A0012625750DF86C</varequal>
+                        </conditionvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+            </item>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>DD76E663D4244C598FC91CFC433F6D5B</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>Fill in the Blank</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,1.0</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>1.0</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">&lt;span style="font-size:12pt"&gt;Name an amphibian&amp;#58; __________.&lt;/span&gt;</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <response_str ident="response" rcardinality="Single" rtiming="No">
+                                <render_fib charset="us-ascii" columns="127" encoding="UTF_8" fibtype="String" maxchars="0" maxnumber="0" minnumber="0" prompt="Box" rows="1"/>
+                            </response_str>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="1.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition title="1CE934E53BDB437B8FD315E68063DA47">
+                        <conditionvar>
+                            <varequal case="No" respident="response">frog</varequal>
+                        </conditionvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                        <displayfeedback feedbacktype="Response" linkrefid="1CE934E53BDB437B8FD315E68063DA47"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML">A frog is an amphibian.</mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML">A frog is an amphibian.</mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="1CE934E53BDB437B8FD315E68063DA47" view="All">
+                    <solution feedbackstyle="Complete" view="All">
+                        <solutionmaterial>
+                            <flow_mat class="Block">
+                                <flow_mat class="FORMATTED_TEXT_BLOCK">
+                                    <material>
+                                        <mat_extension>
+                                            <mat_formattedtext type="HTML">A frog is an amphibian.</mat_formattedtext>
+                                        </mat_extension>
+                                    </material>
+                                </flow_mat>
+                                <flow_mat class="FILE_BLOCK">
+                                    <material/>
+                                </flow_mat>
+                                <flow_mat class="LINK_BLOCK">
+                                    <material>
+                                        <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                    </material>
+                                </flow_mat>
+                            </flow_mat>
+                        </solutionmaterial>
+                    </solution>
+                </itemfeedback>
+            </item>
+            <item maxattempts="0">
+                <itemmetadata>
+                    <bbmd_asi_object_id>39970AD8D5AE425A82338E17D42B7845</bbmd_asi_object_id>
+                    <bbmd_asitype>Item</bbmd_asitype>
+                    <bbmd_assessmenttype>Pool</bbmd_assessmenttype>
+                    <bbmd_sectiontype>Subsection</bbmd_sectiontype>
+                    <bbmd_questiontype>Essay</bbmd_questiontype>
+                    <bbmd_is_from_cartridge>false</bbmd_is_from_cartridge>
+                    <qmd_absolutescore>0.0,1.0</qmd_absolutescore>
+                    <qmd_absolutescore_min>0.0</qmd_absolutescore_min>
+                    <qmd_absolutescore_max>1.0</qmd_absolutescore_max>
+                    <qmd_assessmenttype>Proprietary</qmd_assessmenttype>
+                    <qmd_itemtype>Logical Identifier</qmd_itemtype>
+                    <qmd_levelofdifficulty>School</qmd_levelofdifficulty>
+                    <qmd_maximumscore>0.0</qmd_maximumscore>
+                    <qmd_numberofitems>0</qmd_numberofitems>
+                    <qmd_renderingtype>Proprietary</qmd_renderingtype>
+                    <qmd_responsetype>Single</qmd_responsetype>
+                    <qmd_scoretype>Absolute</qmd_scoretype>
+                    <qmd_status>Normal</qmd_status>
+                    <qmd_timelimit>0</qmd_timelimit>
+                    <qmd_weighting>0.0</qmd_weighting>
+                    <qmd_typeofsolution>Complete</qmd_typeofsolution>
+                </itemmetadata>
+                <presentation>
+                    <flow class="Block">
+                        <flow class="QUESTION_BLOCK">
+                            <flow class="FORMATTED_TEXT_BLOCK">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">How are you?</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow>
+                            <flow class="FILE_BLOCK">
+                                <material/>
+                            </flow>
+                            <flow class="LINK_BLOCK">
+                                <material>
+                                    <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                                </material>
+                            </flow>
+                        </flow>
+                        <flow class="RESPONSE_BLOCK">
+                            <response_str ident="response" rcardinality="Single" rtiming="No">
+                                <render_fib charset="us-ascii" columns="127" encoding="UTF_8" fibtype="String" maxchars="0" maxnumber="0" minnumber="0" prompt="Box" rows="8"/>
+                            </response_str>
+                        </flow>
+                    </flow>
+                </presentation>
+                <resprocessing scoremodel="SumOfScores">
+                    <outcomes>
+                        <decvar defaultval="0.0" maxvalue="1.0" minvalue="0.0" varname="SCORE" vartype="Decimal"/>
+                    </outcomes>
+                    <respcondition title="correct">
+                        <conditionvar/>
+                        <setvar action="Set" variablename="SCORE">SCORE.max</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="correct"/>
+                    </respcondition>
+                    <respcondition title="incorrect">
+                        <conditionvar>
+                            <other/>
+                        </conditionvar>
+                        <setvar action="Set" variablename="SCORE">0.0</setvar>
+                        <displayfeedback feedbacktype="Response" linkrefid="incorrect"/>
+                    </respcondition>
+                </resprocessing>
+                <itemfeedback ident="correct" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="incorrect" view="All">
+                    <flow_mat class="Block">
+                        <flow_mat class="FORMATTED_TEXT_BLOCK">
+                            <material>
+                                <mat_extension>
+                                    <mat_formattedtext type="HTML"></mat_formattedtext>
+                                </mat_extension>
+                            </material>
+                        </flow_mat>
+                        <flow_mat class="FILE_BLOCK">
+                            <material/>
+                        </flow_mat>
+                        <flow_mat class="LINK_BLOCK">
+                            <material>
+                                <mattext charset="us-ascii" texttype="text/plain" uri="" xml:space="default"/>
+                            </material>
+                        </flow_mat>
+                    </flow_mat>
+                </itemfeedback>
+                <itemfeedback ident="solution" view="All">
+                    <solution feedbackstyle="Complete" view="All">
+                        <solutionmaterial>
+                            <flow_mat class="Block">
+                                <material>
+                                    <mat_extension>
+                                        <mat_formattedtext type="HTML">Blackboard answer for essay questions will be imported as informations for graders.</mat_formattedtext>
+                                    </mat_extension>
+                                </material>
+                            </flow_mat>
+                        </solutionmaterial>
+                    </solution>
+                </itemfeedback>
+            </item>
+        </section>
+    </assessment>
+</questestinterop>
diff --git a/question/format/blackboard_six/version.php b/question/format/blackboard_six/version.php
index c037b03..c413d77 100644
--- a/question/format/blackboard_six/version.php
+++ b/question/format/blackboard_six/version.php
@@ -15,10 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Version information for the calculated question type.
+ * Version information for the blackboard_six question import format.
  *
- * @package    qformat
- * @subpackage blackboard_six
+ * @package    qformat_blackboard_six
  * @copyright  2011 The Open University
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index 7cea482..9cb9bb5 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -62,28 +62,6 @@ class qformat_examview extends qformat_based_on_xml {
     }
 
     /**
-     * Some softwares put entities in exported files.
-     * This method try to clean up known problems.
-     * @param string str string to correct
-     * @return string the corrected string
-     */
-    public function cleaninput($str) {
-
-        $html_code_list = array(
-            "&#039;" => "'",
-            "&#8217;" => "'",
-            "&#8220;" => "\"",
-            "&#8221;" => "\"",
-            "&#8211;" => "-",
-            "&#8212;" => "-",
-        );
-        $str = strtr($str, $html_code_list);
-        // Use textlib entities_to_utf8 function to convert only numerical entities.
-        $str = textlib::entities_to_utf8( $str, false);
-        return $str;
-    }
-
-    /**
      * unxmlise reconstructs part of the xml data structure in order
      * to identify the actual data therein
      * @param array $xml section of the xml data structure
@@ -109,19 +87,6 @@ class qformat_examview extends qformat_based_on_xml {
         return $text;
     }
 
-    protected function add_blank_combined_feedback($question) {
-        $question->correctfeedback['text'] = '';
-        $question->correctfeedback['format'] = $question->questiontextformat;
-        $question->correctfeedback['files'] = array();
-        $question->partiallycorrectfeedback['text'] = '';
-        $question->partiallycorrectfeedback['format'] = $question->questiontextformat;
-        $question->partiallycorrectfeedback['files'] = array();
-        $question->incorrectfeedback['text'] = '';
-        $question->incorrectfeedback['format'] = $question->questiontextformat;
-        $question->incorrectfeedback['files'] = array();
-        return $question;
-    }
-
     public function parse_matching_groups($matching_groups) {
         if (empty($matching_groups)) {
             return;
diff --git a/question/format/gift/format.php b/question/format/gift/format.php
index 06bcebc..1cb0e25 100644
--- a/question/format/gift/format.php
+++ b/question/format/gift/format.php
@@ -537,19 +537,6 @@ class qformat_gift extends qformat_default {
         }
     }
 
-    protected function add_blank_combined_feedback($question) {
-        $question->correctfeedback['text'] = '';
-        $question->correctfeedback['format'] = $question->questiontextformat;
-        $question->correctfeedback['files'] = array();
-        $question->partiallycorrectfeedback['text'] = '';
-        $question->partiallycorrectfeedback['format'] = $question->questiontextformat;
-        $question->partiallycorrectfeedback['files'] = array();
-        $question->incorrectfeedback['text'] = '';
-        $question->incorrectfeedback['format'] = $question->questiontextformat;
-        $question->incorrectfeedback['files'] = array();
-        return $question;
-    }
-
     protected function repchar($text, $notused = 0) {
         // Escapes 'reserved' characters # = ~ {) :
         // Removes new lines
-- 
1.7.9.5


From 4d0a7e2b1f755888d9ac4c94a6f34c2ef6d92aa6 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 24 Aug 2012 15:34:20 +0100
Subject: [PATCH 493/903] MDL-35055 question import: slight error with the
 Match grades option.

Even in the 'Error if grade not listed case', it was applying a small
tolerance. In the case of a fuzzy match, it was returning the inexact
grade from the import file, rather than the precise grade that Moodle
was expecting.

That causes problems when the editing form is displayed, because the
value from the database does not match any of the available options, so
the grade is changed to 0%.
---
 lib/questionlib.php            |   41 ++++++++++++++++++++++------------------
 lib/tests/questionlib_test.php |   15 +++++++++++++++
 2 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index db7be64..7b74499 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -209,39 +209,44 @@ function get_grade_options() {
 }
 
 /**
- * match grade options
- * if no match return error or match nearest
+ * Check whether a given grade is one of a list of allowed options. If not,
+ * depending on $matchgrades, either return the nearest match, or return false
+ * to signal an error.
  * @param array $gradeoptionsfull list of valid options
  * @param int $grade grade to be tested
  * @param string $matchgrades 'error' or 'nearest'
- * @return mixed either 'fixed' value or false if erro
+ * @return mixed either 'fixed' value or false if error.
  */
-function match_grade_options($gradeoptionsfull, $grade, $matchgrades='error') {
+function match_grade_options($gradeoptionsfull, $grade, $matchgrades = 'error') {
+
     if ($matchgrades == 'error') {
-        // if we just need an error...
+        // (Almost) exact match, or an error.
         foreach ($gradeoptionsfull as $value => $option) {
-            // slightly fuzzy test, never check floats for equality :-)
+            // Slightly fuzzy test, never check floats for equality.
             if (abs($grade - $value) < 0.00001) {
-                return $grade;
+                return $value; // Be sure the return the proper value.
             }
         }
-        // didn't find a match so that's an error
+        // Didn't find a match so that's an error.
         return false;
+
     } else if ($matchgrades == 'nearest') {
-        // work out nearest value
-        $hownear = array();
+        // Work out nearest value
+        $best = false;
+        $bestmismatch = 2;
         foreach ($gradeoptionsfull as $value => $option) {
-            if ($grade==$value) {
-                return $grade;
+            $newmismatch = abs($grade - $value);
+            if ($newmismatch < $bestmismatch) {
+                $best = $value;
+                $bestmismatch = $newmismatch;
             }
-            $hownear[ $value ] = abs( $grade - $value );
         }
-        // reverse sort list of deltas and grab the last (smallest)
-        asort( $hownear, SORT_NUMERIC );
-        reset( $hownear );
-        return key( $hownear );
+        return $best;
+
     } else {
-        return false;
+        // Unknow option passed.
+        throw new coding_exception('Unknown $matchgrades ' . $matchgrades .
+                ' passed to match_grade_options');
     }
 }
 
diff --git a/lib/tests/questionlib_test.php b/lib/tests/questionlib_test.php
index 2e5d431..d7d767d 100644
--- a/lib/tests/questionlib_test.php
+++ b/lib/tests/questionlib_test.php
@@ -55,4 +55,19 @@ class questionlib_testcase extends basic_testcase {
             array(0 => 't1', 1 => 't2', 2 => 't3'));
     }
 
+    public function test_match_grade_options() {
+        $gradeoptions = question_bank::fraction_options_full();
+
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.3333333, 'error'));
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.333333, 'error'));
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33333, 'error'));
+        $this->assertFalse(match_grade_options($gradeoptions, 0.3333, 'error'));
+
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.3333333, 'nearest'));
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.333333, 'nearest'));
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33333, 'nearest'));
+        $this->assertEquals(0.3333333, match_grade_options($gradeoptions, 0.33, 'nearest'));
+
+        $this->assertEquals(-0.1428571, match_grade_options($gradeoptions, -0.15, 'nearest'));
+    }
 }
-- 
1.7.9.5


From 409eab351048c7cedcae43f70ce7d63f83bcc403 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Thu, 16 Aug 2012 20:58:12 +0100
Subject: [PATCH 494/903] MDL-34936 Warn if the sectioncache property is
 missing in a get_fast_modinfo call

---
 lib/modinfolib.php |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/modinfolib.php b/lib/modinfolib.php
index db9b7f6..0739f76 100644
--- a/lib/modinfolib.php
+++ b/lib/modinfolib.php
@@ -1196,6 +1196,10 @@ function get_fast_modinfo(&$course, $userid=0) {
         debugging('Coding problem - missing course modinfo property in get_fast_modinfo() call');
     }
 
+    if (!property_exists($course, 'sectioncache')) {
+        debugging('Coding problem - missing course sectioncache property in get_fast_modinfo() call');
+    }
+
     unset($cache[$course->id]); // prevent potential reference problems when switching users
 
     $cache[$course->id] = new course_modinfo($course, $userid);
-- 
1.7.9.5


From a129b76cc347c6422c88bd129646f0a4819df060 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 24 Aug 2012 14:19:27 +0100
Subject: [PATCH 495/903] MDL-32464 qformat multianswer: fix missing include.

Also, add a sample file that can be used for testing, and add a unit
test to verify this is working.
---
 question/format/multianswer/format.php             |   31 ++++----
 .../tests/fixtures/questions.multianswer.txt       |    8 +++
 .../multianswer/tests/multianswerformat_test.php   |   76 ++++++++++++++++++++
 question/type/multianswer/questiontype.php         |    6 +-
 4 files changed, 104 insertions(+), 17 deletions(-)
 create mode 100644 question/format/multianswer/tests/fixtures/questions.multianswer.txt
 create mode 100644 question/format/multianswer/tests/multianswerformat_test.php

diff --git a/question/format/multianswer/format.php b/question/format/multianswer/format.php
index 45179d8..d7a7ac7 100644
--- a/question/format/multianswer/format.php
+++ b/question/format/multianswer/format.php
@@ -17,10 +17,9 @@
 /**
  * Embedded answer (Cloze) question importer.
  *
- * @package    qformat
- * @subpackage multianswer
- * @copyright  2003 Henrik Kaipe
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package   qformat_multianswer
+ * @copyright 2003 Henrik Kaipe
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 
@@ -31,32 +30,36 @@ defined('MOODLE_INTERNAL') || die();
  * Importer that imports a text file containing a single Multianswer question
  * from a text file.
  *
- * @copyright  2003 Henrik Kaipe
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright 2003 Henrik Kaipe
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qformat_multianswer extends qformat_default {
 
     public function provide_import() {
-      return true;
+        return true;
     }
 
-    protected function readquestions($lines) {
+    public function readquestions($lines) {
+        question_bank::get_qtype('multianswer'); // Ensure the multianswer code is loaded.
+
         // For this class the method has been simplified as
         // there can never be more than one question for a
-        // multianswer import
+        // multianswer import.
         $questions = array();
 
         $questiontext = array();
         $questiontext['text'] = implode('', $lines);
-        $questiontext['format'] = 0 ;
+        $questiontext['format'] = FORMAT_MOODLE;
         $questiontext['itemid'] = '';
         $question = qtype_multianswer_extract_question($questiontext);
-        $question->questiontext = $question->questiontext['text'] ;
-        $question->questiontextformat = 0 ;
+        $question->questiontext = $question->questiontext['text'];
+        $question->questiontextformat = 0;
 
-        $question->qtype = MULTIANSWER;
+        $question->qtype = 'multianswer';
         $question->generalfeedback = '';
-        $question->course = $this->course;
+        $question->generalfeedbackformat = FORMAT_MOODLE;
+        $question->length = 1;
+        $question->penalty = 0.3333333;
 
         if (!empty($question)) {
             $name = html_to_text(implode(' ', $lines));
diff --git a/question/format/multianswer/tests/fixtures/questions.multianswer.txt b/question/format/multianswer/tests/fixtures/questions.multianswer.txt
new file mode 100644
index 0000000..57a56a9
--- /dev/null
+++ b/question/format/multianswer/tests/fixtures/questions.multianswer.txt
@@ -0,0 +1,8 @@
+Match the following cities with the correct state:
+* San Francisco: {1:MULTICHOICE:=California#OK~Arizona#Wrong}
+* Tucson: {1:MULTICHOICE:California#Wrong~%100%Arizona#OK}
+* Los Angeles: {1:MULTICHOICE:=California#OK~Arizona#Wrong}
+* Phoenix: {1:MULTICHOICE:%0%California#Wrong~=Arizona#OK}
+The capital of France is {1:SHORTANSWER:%100%Paris#Congratulations!
+~%50%Marseille#No, that is the second largest city in France (after
+Paris).~*#Wrong answer. The capital of France is Paris, of course.}.
diff --git a/question/format/multianswer/tests/multianswerformat_test.php b/question/format/multianswer/tests/multianswerformat_test.php
new file mode 100644
index 0000000..29c3224
--- /dev/null
+++ b/question/format/multianswer/tests/multianswerformat_test.php
@@ -0,0 +1,76 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for the Embedded answer (Cloze) question importer.
+ *
+ * @package   qformat_multianswer
+ * @copyright 2012 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/multianswer/format.php');
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the Embedded answer (Cloze) question importer.
+ *
+ * @copyright 2012 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_multianswer_test extends question_testcase {
+
+    public function test_import() {
+        $lines = file(__DIR__ . '/fixtures/questions.multianswer.txt');
+
+        $importer = new qformat_multianswer();
+        $qs = $importer->readquestions($lines);
+
+        $expectedq = (object) array(
+            'name' => 'Match the following cities with the ...',
+            'questiontext' => 'Match the following cities with the correct state:
+* San Francisco: {#1}
+* Tucson: {#2}
+* Los Angeles: {#3}
+* Phoenix: {#4}
+The capital of France is {#5}.
+',
+            'questiontextformat' => FORMAT_MOODLE,
+            'generalfeedback' => '',
+            'generalfeedbackformat' => FORMAT_MOODLE,
+            'qtype' => 'multianswer',
+            'defaultmark' => 5,
+            'penalty' => 0.3333333,
+            'length' => 1,
+        );
+
+        $this->assertEquals(1, count($qs));
+        $this->assert(new question_check_specified_fields_expectation($expectedq), $qs[0]);
+
+        $this->assertEquals('multichoice', $qs[0]->options->questions[1]->qtype);
+        $this->assertEquals('multichoice', $qs[0]->options->questions[2]->qtype);
+        $this->assertEquals('multichoice', $qs[0]->options->questions[3]->qtype);
+        $this->assertEquals('multichoice', $qs[0]->options->questions[4]->qtype);
+        $this->assertEquals('shortanswer', $qs[0]->options->questions[5]->qtype);
+    }
+}
diff --git a/question/type/multianswer/questiontype.php b/question/type/multianswer/questiontype.php
index c87e8e7..b39848d 100644
--- a/question/type/multianswer/questiontype.php
+++ b/question/type/multianswer/questiontype.php
@@ -304,7 +304,7 @@ function qtype_multianswer_extract_question($text) {
     $question->defaultmark = 0; // Will be increased for each answer norm
 
     for ($positionkey = 1;
-            preg_match('/'.ANSWER_REGEX.'/', $question->questiontext['text'], $answerregs);
+            preg_match('/'.ANSWER_REGEX.'/s', $question->questiontext['text'], $answerregs);
             ++$positionkey) {
         $wrapped = new stdClass();
         $wrapped->generalfeedback['text'] = '';
@@ -390,7 +390,7 @@ function qtype_multianswer_extract_question($text) {
         $answerindex = 0;
 
         $remainingalts = $answerregs[ANSWER_REGEX_ALTERNATIVES];
-        while (preg_match('/~?'.ANSWER_ALTERNATIVE_REGEX.'/', $remainingalts, $altregs)) {
+        while (preg_match('/~?'.ANSWER_ALTERNATIVE_REGEX.'/s', $remainingalts, $altregs)) {
             if ('=' == $altregs[ANSWER_ALTERNATIVE_REGEX_FRACTION]) {
                 $wrapped->fraction["$answerindex"] = '1';
             } else if ($percentile = $altregs[ANSWER_ALTERNATIVE_REGEX_PERCENTILE_FRACTION]) {
@@ -412,7 +412,7 @@ function qtype_multianswer_extract_question($text) {
 
             }
             if (!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_NUMERICAL])
-                    && preg_match('~'.NUMERICAL_ALTERNATIVE_REGEX.'~',
+                    && preg_match('~'.NUMERICAL_ALTERNATIVE_REGEX.'~s',
                             $altregs[ANSWER_ALTERNATIVE_REGEX_ANSWER], $numregs)) {
                 $wrapped->answer[] = $numregs[NUMERICAL_CORRECT_ANSWER];
                 if (array_key_exists(NUMERICAL_ABS_ERROR_MARGIN, $numregs)) {
-- 
1.7.9.5


From fdc57a14bdaa28816566ef4d00b235308e0a5973 Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Fri, 24 Aug 2012 21:53:45 +0200
Subject: [PATCH 496/903] MDL-34952 - change get_info() to public access

---
 mod/feedback/item/multichoice/lib.php      |    2 +-
 mod/feedback/item/multichoicerated/lib.php |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/feedback/item/multichoice/lib.php b/mod/feedback/item/multichoice/lib.php
index 4b7a841..c129b45 100644
--- a/mod/feedback/item/multichoice/lib.php
+++ b/mod/feedback/item/multichoice/lib.php
@@ -609,7 +609,7 @@ class feedback_item_multichoice extends feedback_item_base {
         return 1;
     }
 
-    private function get_info($item) {
+    public function get_info($item) {
         $presentation = empty($item->presentation) ? '' : $item->presentation;
 
         $info = new stdClass();
diff --git a/mod/feedback/item/multichoicerated/lib.php b/mod/feedback/item/multichoicerated/lib.php
index 00ee832..696afda 100644
--- a/mod/feedback/item/multichoicerated/lib.php
+++ b/mod/feedback/item/multichoicerated/lib.php
@@ -465,7 +465,7 @@ class feedback_item_multichoicerated extends feedback_item_base {
         return 1;
     }
 
-    private function get_info($item) {
+    public function get_info($item) {
         $presentation = empty($item->presentation) ? '' : $item->presentation;
 
         $info = new stdClass();
-- 
1.7.9.5


From 441fa9c71de2054e9e863288c63a1ebaf3b12d2f Mon Sep 17 00:00:00 2001
From: Andreas Grabs <moodle@grabs-edv.de>
Date: Fri, 24 Aug 2012 23:07:17 +0200
Subject: [PATCH 497/903] MDL-34996 - Improve help text for Feedback
 dependancies

---
 mod/feedback/lang/en/feedback.php |   28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/mod/feedback/lang/en/feedback.php b/mod/feedback/lang/en/feedback.php
index c35b24c..2e27645 100644
--- a/mod/feedback/lang/en/feedback.php
+++ b/mod/feedback/lang/en/feedback.php
@@ -62,28 +62,26 @@ $string['delete_item'] = 'Delete question';
 $string['delete_old_items'] = 'Delete old items';
 $string['delete_template'] = 'Delete template';
 $string['delete_templates'] = 'Delete template...';
-$string['depending'] = 'depending items';
-$string['depending_help'] = 'Depending items allow you to show items depend on values from other items.<br />
-<strong>Here an build example to use it:</strong><br />
+$string['depending'] = 'Dependencies';
+$string['depending_help'] = 'It is possible to show an item depending on the value of another item.<br />
+<strong>Here is an example.</strong><br />
 <ul>
-<li>First create an item on which value other items depends.</li>
-<li>Next add a pagebreak.</li>
-<li>Next add the items depend on the item-value before<br />
-Choose in the item creation-form the item in the list "depend item" and put the needed value into the textbox "depend value".</li>
+<li>First, create an item on which another item will depend on.</li>
+<li>Next, add a pagebreak.</li>
+<li>Then add the items dependant on the value of the item created before. Choose the item from the list labelled "Dependence item" and write the required value in the textbox labelled "Dependence value".</li>
 </ul>
-<strong>The structure should looks like this:</strong>
+<strong>The item structure should look like this.</strong>
 <ol>
-<li>Item Q: do you have a car? A: yes/no</li>
+<li>Item Q: Do you have a car? A: yes/no</li>
 <li>Pagebreak</li>
-<li>Item Q: what color has your car?<br />
+<li>Item Q: What colour is your car?<br />
 (this item depends on item 1 with value = yes)</li>
-<li>Item Q: why you have not a car?<br />
+<li>Item Q: Why don\'t you have a car?<br />
 (this item depends on item 1 with value = no)</li>
 <li> ... other items</li>
-</ol>
-That is all. Have fun!';
-$string['dependitem'] = 'depend item';
-$string['dependvalue'] = 'depend value';
+</ol>';
+$string['dependitem'] = 'Dependence item';
+$string['dependvalue'] = 'Dependence value';
 $string['description'] = 'Description';
 $string['do_not_analyse_empty_submits'] = 'Do not analyse empty submits';
 $string['dropdown'] = 'Multiple choice - single answer allowed (dropdownlist)';
-- 
1.7.9.5


From b710f91ed9ee8deed863b5bb05b00f7060800cda Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 26 Aug 2012 20:49:27 +0100
Subject: [PATCH 498/903] MDL-35048 theme_formal_white: removed p {margin:0}
 from style/formal_white.css which was causing a
 regression in some areas of theme

---
 theme/formal_white/style/formal_white.css |    2 --
 1 file changed, 2 deletions(-)

diff --git a/theme/formal_white/style/formal_white.css b/theme/formal_white/style/formal_white.css
index 2a262c9..248ea33 100644
--- a/theme/formal_white/style/formal_white.css
+++ b/theme/formal_white/style/formal_white.css
@@ -24,8 +24,6 @@ h4 {font-weight:bold;}
 h1.headerheading {margin:14px 11px 8px 11px;float:left;font-size:200%;}
 h2.main, h3.main, h4.main {margin:1em;padding:0;text-align:center;}
 
-p {margin:0}
-
 /* page-header */
 #page-header{line-height:0;overflow:hidden;}
 
-- 
1.7.9.5


From aac67f6384a11c839801231da305ae26f7a6cf92 Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Fri, 20 Jul 2012 13:40:42 +1200
Subject: [PATCH 499/903] MDL-32386 completion: Fix incorrect method
 parameters

---
 lib/completionlib.php            |    6 +++++-
 lib/tests/completionlib_test.php |    2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/lib/completionlib.php b/lib/completionlib.php
index 54e9160..fcd5910 100644
--- a/lib/completionlib.php
+++ b/lib/completionlib.php
@@ -621,16 +621,20 @@ class completion_info {
             debugging('set_module_viewed must be called before header is printed',
                     DEBUG_DEVELOPER);
         }
+
         // Don't do anything if view condition is not turned on
         if ($cm->completionview == COMPLETION_VIEW_NOT_REQUIRED || !$this->is_enabled($cm)) {
             return;
         }
+
         // Get current completion state
-        $data = $this->get_data($cm, $userid);
+        $data = $this->get_data($cm, false, $userid);
+
         // If we already viewed it, don't do anything
         if ($data->viewed == COMPLETION_VIEWED) {
             return;
         }
+
         // OK, change state, save it, and update completion
         $data->viewed = COMPLETION_VIEWED;
         $this->internal_set_data($cm, $data);
diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php
index 6e81cd7..5092831 100644
--- a/lib/tests/completionlib_test.php
+++ b/lib/tests/completionlib_test.php
@@ -257,7 +257,7 @@ class completionlib_testcase extends basic_testcase {
             ->will($this->returnValue(true));
         $c->expects($this->at(1))
             ->method('get_data')
-            ->with($cm, 1337)
+            ->with($cm, false, 1337)
             ->will($this->returnValue((object)array('viewed'=>COMPLETION_NOT_VIEWED)));
         $c->expects($this->at(2))
             ->method('internal_set_data')
-- 
1.7.9.5


From 3342bb835cf8a806cd546fea7038f51be138cd2f Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Mon, 27 Aug 2012 00:32:46 +0000
Subject: [PATCH 500/903] Automatically generated installer lang files

---
 install/lang/lt/admin.php |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/install/lang/lt/admin.php b/install/lang/lt/admin.php
index 3c005d8..9977e2b 100644
--- a/install/lang/lt/admin.php
+++ b/install/lang/lt/admin.php
@@ -34,9 +34,11 @@ $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 't';
 $string['cliincorrectvalueerror'] = 'Klaida, klaidinga "{$a->option}" reikšmė "{$a->value}"';
 $string['cliincorrectvalueretry'] = 'Klaidinga reikšmė, bandykite dar kartą';
-$string['clitypevalue'] = 'tipo reikšmė';
-$string['clitypevaluedefault'] = 'tipo reikšmė, paspauskite „Enter“, jei norite naudoti numatytąją reikšmę ({$a})';
-$string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno parinktį.';
+$string['clitypevalue'] = 'įveskite reikšmę';
+$string['clitypevaluedefault'] = 'įveskite reikšmę, paspauskite „Enter“, jei norite naudoti numatytąją reikšmę ({$a})';
+$string['cliunknowoption'] = 'Neatpažintos parinktys:
+{$a}
+Naudokite --help parinktį.';
 $string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
 $string['environmentrequireinstall'] = 'turi būti įdiegta ir įgalinta';
 $string['environmentrequireversion'] = 'reikalinga {$a->needed} versija, o Jūs turite {$a->current}';
-- 
1.7.9.5


From 339c95491305845264742c463dc714174cf87267 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 27 Aug 2012 13:59:09 +0800
Subject: [PATCH 501/903] MDL-34537 Enrolments: Assign alternative odd and
 even class to manual enrol popup

---
 enrol/manual/yui/quickenrolment/quickenrolment.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/enrol/manual/yui/quickenrolment/quickenrolment.js b/enrol/manual/yui/quickenrolment/quickenrolment.js
index 88c09ea..5f4efe6 100644
--- a/enrol/manual/yui/quickenrolment/quickenrolment.js
+++ b/enrol/manual/yui/quickenrolment/quickenrolment.js
@@ -339,7 +339,7 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
                 count++;
                 var user = result.response.users[i];
                 users.append(create('<div class="'+CSS.USER+' clearfix" rel="'+user.id+'"></div>')
-                    .addClass((i%2)?CSS.ODD:CSS.EVEN)
+                    .addClass((count%2)?CSS.ODD:CSS.EVEN)
                     .append(create('<div class="'+CSS.COUNT+'">'+count+'</div>'))
                     .append(create('<div class="'+CSS.PICTURE+'"></div>')
                         .append(create(user.picture)))
-- 
1.7.9.5


From acff4866644454cc6c8f1fc5edd8f66155a3b1b8 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 27 Aug 2012 14:55:02 +0800
Subject: [PATCH 502/903] MDl-34606 Administration: id for clear button is set
 properly, and disabled on page load

---
 user/selector/module.js |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/user/selector/module.js b/user/selector/module.js
index e6818c8..68b743d 100644
--- a/user/selector/module.js
+++ b/user/selector/module.js
@@ -77,8 +77,9 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
             var clearbtn = Y.one('#'+this.name + '_clearbutton');
             this.clearbutton = Y.Node.create('<input type="button" value="'+clearbtn.get('value')+'" />');
             clearbtn.replace(Y.Node.getDOMNode(this.clearbutton));
-            this.clearbutton.set('id',+this.name+"_clearbutton");
+            this.clearbutton.set('id', this.name+"_clearbutton");
             this.clearbutton.on('click', this.handle_clear, this);
+            this.clearbutton.set('disabled', (this.get_search_text() == ''));
 
             this.send_query(false);
         },
-- 
1.7.9.5


From f0c1bcf5a235c0c783ffa4cfbeff0af4fa649302 Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaronb@catalyst.net.nz>
Date: Tue, 21 Aug 2012 13:07:57 +1200
Subject: [PATCH 503/903] MDL-30020 blocks/completion: Some criteria do not
 display complete

Also includes a spruce up of the code
---
 blocks/completionstatus/block_completionstatus.php |   28 +--
 blocks/completionstatus/details.php                |  239 +++++++++++---------
 .../lang/en/block_completionstatus.php             |    1 +
 3 files changed, 143 insertions(+), 125 deletions(-)

diff --git a/blocks/completionstatus/block_completionstatus.php b/blocks/completionstatus/block_completionstatus.php
index 0daec7c..449e632 100644
--- a/blocks/completionstatus/block_completionstatus.php
+++ b/blocks/completionstatus/block_completionstatus.php
@@ -19,15 +19,14 @@
  *
  * @package    block
  * @subpackage completion
- * @copyright  2009 Catalyst IT Ltd
+ * @copyright  2009-2012 Catalyst IT Ltd
  * @author     Aaron Barnes <aaronb@catalyst.net.nz>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-
-require_once($CFG->libdir.'/completionlib.php');
+require_once("{$CFG->libdir}/completionlib.php");
 
 /**
  * Course completion status
@@ -36,25 +35,27 @@ require_once($CFG->libdir.'/completionlib.php');
 class block_completionstatus extends block_base {
 
     public function init() {
-        $this->title   = get_string('pluginname', 'block_completionstatus');
+        $this->title = get_string('pluginname', 'block_completionstatus');
     }
 
     public function get_content() {
-        global $USER, $CFG, $DB, $COURSE;
+        global $USER;
 
         // If content is cached
         if ($this->content !== NULL) {
             return $this->content;
         }
 
+        $course  = $this->page->course;
+
         // Create empty content
-        $this->content = new stdClass;
+        $this->content = new stdClass();
 
         // Can edit settings?
-        $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $this->page->course->id));
+        $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id));
 
         // Get course completion data
-        $info = new completion_info($this->page->course);
+        $info = new completion_info($course);
 
         // Don't display if completion isn't enabled!
         if (!completion_info::is_enabled_for_site()) {
@@ -84,9 +85,9 @@ class block_completionstatus extends block_base {
         // Check this user is enroled
         if (!$info->is_tracked_user($USER->id)) {
             // If not enrolled, but are can view the report:
-            if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $COURSE->id))) {
-                $this->content->text = '<a href="'.$CFG->wwwroot.'/report/completion/index.php?course='.$COURSE->id.
-                                       '">'.get_string('viewcoursereport', 'completion').'</a>';
+            if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $course->id))) {
+                $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
+                $this->content->text = '<a href="'.$report->out().'">'.get_string('viewcoursereport', 'completion').'</a>';
                 return $this->content;
             }
 
@@ -187,7 +188,7 @@ class block_completionstatus extends block_base {
         // Load course completion
         $params = array(
             'userid' => $USER->id,
-            'course' => $COURSE->id
+            'course' => $course->id
         );
         $ccompletion = new completion_completion($params);
 
@@ -221,7 +222,8 @@ class block_completionstatus extends block_base {
         $this->content->text .= $shtml.'</tbody></table>';
 
         // Display link to detailed view
-        $this->content->footer = '<br><a href="'.$CFG->wwwroot.'/blocks/completionstatus/details.php?course='.$COURSE->id.'">'.get_string('moredetails', 'completion').'</a>';
+        $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+        $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
 
         return $this->content;
     }
diff --git a/blocks/completionstatus/details.php b/blocks/completionstatus/details.php
index a1ac771..84406e3 100644
--- a/blocks/completionstatus/details.php
+++ b/blocks/completionstatus/details.php
@@ -19,27 +19,23 @@
  *
  * @package    block
  * @subpackage completion
- * @copyright  2009 Catalyst IT Ltd
+ * @copyright  2009-2012 Catalyst IT Ltd
  * @author     Aaron Barnes <aaronb@catalyst.net.nz>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-require_once('../../config.php');
-require_once($CFG->libdir.'/completionlib.php');
-
-
-// TODO:  Make this page Moodle 2.0 compliant
+require_once(dirname(__FILE__).'/../../config.php');
+require_once("{$CFG->libdir}/completionlib.php");
 
 
 ///
 /// Load data
 ///
 $id = required_param('course', PARAM_INT);
-// User id
 $userid = optional_param('user', 0, PARAM_INT);
 
 // Load course
-$course = $DB->get_record('course', array('id' => $id));
+$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
 
 // Load user
 if ($userid) {
@@ -76,21 +72,13 @@ if (!$can_view) {
 // Load completion data
 $info = new completion_info($course);
 
-$returnurl = "{$CFG->wwwroot}/course/view.php?id={$id}";
+$returnurl = new moodle_url('/course/view.php', array('id' => $id));
 
 // Don't display if completion isn't enabled!
 if (!$info->is_enabled()) {
     print_error('completionnotenabled', 'completion', $returnurl);
 }
 
-// Load criteria to display
-$completions = $info->get_completions($user->id);
-
-// Check if this course has any criteria
-if (empty($completions)) {
-    print_error('nocriteriaset', 'completion', $returnurl);
-}
-
 // Check this user is enroled
 if (!$info->is_tracked_user($user->id)) {
     if ($USER->id == $user->id) {
@@ -104,6 +92,7 @@ if (!$info->is_tracked_user($user->id)) {
 ///
 /// Display page
 ///
+$PAGE->set_context(context_course::instance($course->id));
 
 // Print header
 $page = get_string('completionprogressdetails', 'block_completionstatus');
@@ -111,7 +100,7 @@ $title = format_string($course->fullname) . ': ' . $page;
 
 $PAGE->navbar->add($page);
 $PAGE->set_pagelayout('standard');
-$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id));
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($title);
 echo $OUTPUT->header();
@@ -135,122 +124,148 @@ $coursecomplete = $info->is_course_complete($user->id);
 // Has this user completed any criteria?
 $criteriacomplete = $info->count_course_user_data($user->id);
 
+// Load course completion
+$params = array(
+    'userid' => $user->id,
+    'course' => $course->id,
+);
+$ccompletion = new completion_completion($params);
+
 if ($coursecomplete) {
     echo get_string('complete');
-} else if (!$criteriacomplete) {
+} else if (!$criteriacomplete && !$ccompletion->timestarted) {
     echo '<i>'.get_string('notyetstarted', 'completion').'</i>';
 } else {
     echo '<i>'.get_string('inprogress','completion').'</i>';
 }
 
 echo '</td></tr>';
-echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
 
-// Get overall aggregation method
-$overall = $info->get_aggregation_method();
+// Load criteria to display
+$completions = $info->get_completions($user->id);
 
-if ($overall == COMPLETION_AGGREGATION_ALL) {
-    echo get_string('criteriarequiredall', 'completion');
+// Check if this course has any criteria
+if (empty($completions)) {
+    echo '<tr><td colspan="2"><br />';
+    echo $OUTPUT->box(get_string('err_nocriteria', 'completion'), 'noticebox');
+    echo '</td></tr></tbody></table>';
 } else {
-    echo get_string('criteriarequiredany', 'completion');
-}
+    echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
 
-echo '</td></tr></tbody></table>';
-
-// Generate markup for criteria statuses
-echo '<table class="generalbox boxaligncenter" cellpadding="3"><tbody>';
-echo '<tr class="ccheader">';
-echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
-echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
-echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
-echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
-echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
-echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
-echo '</tr>';
-
-// Save row data
-$rows = array();
-
-global $COMPLETION_CRITERIA_TYPES;
-
-// Loop through course criteria
-foreach ($completions as $completion) {
-    $criteria = $completion->get_criteria();
-    $complete = $completion->is_complete();
-
-    $row = array();
-    $row['type'] = $criteria->criteriatype;
-    $row['title'] = $criteria->get_title();
-    $row['status'] = $completion->get_status();
-    $row['timecompleted'] = $completion->timecompleted;
-    $row['details'] = $criteria->get_details($completion);
-    $rows[] = $row;
-}
+    // Get overall aggregation method
+    $overall = $info->get_aggregation_method();
 
-// Print table
-$last_type = '';
-$agg_type = false;
+    if ($overall == COMPLETION_AGGREGATION_ALL) {
+        echo get_string('criteriarequiredall', 'completion');
+    } else {
+        echo get_string('criteriarequiredany', 'completion');
+    }
+
+    echo '</td></tr></tbody></table>';
+
+    // Generate markup for criteria statuses
+    echo '<table class="generalbox logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
+    echo '<tr class="ccheader">';
+    echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
+    echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
+    echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
+    echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
+    echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
+    echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
+    echo '</tr>';
 
-foreach ($rows as $row) {
+    // Save row data
+    $rows = array();
+
+    // Loop through course criteria
+    foreach ($completions as $completion) {
+        $criteria = $completion->get_criteria();
+
+        $row = array();
+        $row['type'] = $criteria->criteriatype;
+        $row['title'] = $criteria->get_title();
+        $row['status'] = $completion->get_status();
+        $row['complete'] = $completion->is_complete();
+        $row['timecompleted'] = $completion->timecompleted;
+        $row['details'] = $criteria->get_details($completion);
+        $rows[] = $row;
+    }
 
-    // Criteria group
-    echo '<td class="c0">';
-    if ($last_type !== $row['details']['type']) {
-        $last_type = $row['details']['type'];
-        echo $last_type;
+    // Print table
+    $last_type = '';
+    $agg_type = false;
+    $oddeven = 0;
 
-        // Reset agg type
-        $agg_type = true;
-    } else {
-        // Display aggregation type
-        if ($agg_type) {
-            $agg = $info->get_aggregation_method($row['type']);
+    foreach ($rows as $row) {
 
-            echo '(<i>';
+        echo '<tr class="r' . $oddeven . '">';
 
-            if ($agg == COMPLETION_AGGREGATION_ALL) {
-                echo strtolower(get_string('all', 'completion'));
-            } else {
-                echo strtolower(get_string('any', 'completion'));
-            }
+        // Criteria group
+        echo '<td class="cell c0">';
+        if ($last_type !== $row['details']['type']) {
+            $last_type = $row['details']['type'];
+            echo $last_type;
+
+            // Reset agg type
+            $agg_type = true;
+        } else {
+            // Display aggregation type
+            if ($agg_type) {
+                $agg = $info->get_aggregation_method($row['type']);
 
-            echo '</i> '.strtolower(get_string('required')).')';
-            $agg_type = false;
+                echo '(<i>';
+
+                if ($agg == COMPLETION_AGGREGATION_ALL) {
+                    echo strtolower(get_string('aggregateall', 'completion'));
+                } else {
+                    echo strtolower(get_string('aggregateany', 'completion'));
+                }
+
+                echo '</i> '.strtolower(get_string('required')).')';
+                $agg_type = false;
+            }
         }
+        echo '</td>';
+
+        // Criteria title
+        echo '<td class="cell c1">';
+        echo $row['details']['criteria'];
+        echo '</td>';
+
+        // Requirement
+        echo '<td class="cell c2">';
+        echo $row['details']['requirement'];
+        echo '</td>';
+
+        // Status
+        echo '<td class="cell c3">';
+        echo $row['details']['status'];
+        echo '</td>';
+
+        // Is complete
+        echo '<td class="cell c4">';
+        echo $row['complete'] ? get_string('yes') : get_string('no');
+        echo '</td>';
+
+        // Completion data
+        echo '<td class="cell c5">';
+        if ($row['timecompleted']) {
+            echo userdate($row['timecompleted'], get_string('strftimedate', 'langconfig'));
+        } else {
+            echo '-';
+        }
+        echo '</td>';
+        echo '</tr>';
+        // for row striping
+        $oddeven = $oddeven ? 0 : 1;
     }
-    echo '</td>';
-
-    // Criteria title
-    echo '<td class="c1">';
-    echo $row['details']['criteria'];
-    echo '</td>';
-
-    // Requirement
-    echo '<td class="c2">';
-    echo $row['details']['requirement'];
-    echo '</td>';
-
-    // Status
-    echo '<td class="c3">';
-    echo $row['details']['status'];
-    echo '</td>';
-
-    // Is complete
-    echo '<td class="c4">';
-    echo ($row['status'] === get_string('yes')) ? get_string('yes') : get_string('no');
-    echo '</td>';
-
-    // Completion data
-    echo '<td class="c5">';
-    if ($row['timecompleted']) {
-        echo userdate($row['timecompleted'], '%e %B %G');
-    } else {
-        echo '-';
-    }
-    echo '</td>';
-    echo '</tr>';
+
+    echo '</tbody></table>';
 }
 
-echo '</tbody></table>';
+echo '<div class="buttons">';
+$courseurl = new moodle_url("/course/view.php", array('id' => $course->id));
+echo $OUTPUT->single_button($courseurl, get_string('returntocourse', 'block_completionstatus'), 'get');
+echo '</div>';
 
 echo $OUTPUT->footer();
diff --git a/blocks/completionstatus/lang/en/block_completionstatus.php b/blocks/completionstatus/lang/en/block_completionstatus.php
index fcc965a..6658c17 100644
--- a/blocks/completionstatus/lang/en/block_completionstatus.php
+++ b/blocks/completionstatus/lang/en/block_completionstatus.php
@@ -5,3 +5,4 @@ $string['criteriagroup'] = 'Criteria group';
 $string['firstofsecond'] = '{$a->first} of {$a->second}';
 $string['pluginname'] = 'Course completion status';
 $string['requirement'] = 'Requirement';
+$string['returntocourse'] = 'Return to course';
-- 
1.7.9.5


From b884cf2a745abccc1f300b58e0ee324a5a547956 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 28 Aug 2012 01:38:09 +0200
Subject: [PATCH 504/903] MDL-35089 conditionals: detected one place missing
 sectioncache

Thanks to MDL-34936 and unit tests this was discovered like 2 new
places calling to get_fast_modinfo() without the sectioncache
column contents. Potential performance problem, leading to
reseting and recalculation of caches all the time.
---
 lib/conditionlib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/conditionlib.php b/lib/conditionlib.php
index 0d8b3cb..550d49a 100644
--- a/lib/conditionlib.php
+++ b/lib/conditionlib.php
@@ -596,7 +596,7 @@ abstract class condition_info_base {
                 $course = $COURSE;
             } else {
                 $course = $DB->get_record('course', array('id' => $this->item->course),
-                        'id, enablecompletion, modinfo', MUST_EXIST);
+                        'id, enablecompletion, modinfo, sectioncache', MUST_EXIST);
             }
             foreach ($this->item->conditionscompletion as $cmid => $expectedcompletion) {
                 if (!$modinfo) {
@@ -747,7 +747,7 @@ abstract class condition_info_base {
                 $course = $COURSE;
             } else {
                 $course = $DB->get_record('course', array('id' => $this->item->course),
-                        'id, enablecompletion, modinfo', MUST_EXIST);
+                        'id, enablecompletion, modinfo, sectioncache', MUST_EXIST);
             }
 
             $completion = new completion_info($course);
-- 
1.7.9.5


From 339057063c310aff02b513a24d810d0c0854d07b Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Tue, 28 Aug 2012 15:54:01 +0800
Subject: [PATCH 505/903] MDL-34318 - blog - Removal of blog associations from
 the database on delete. Thanks to Erik Lundberg for
 this patch.

---
 blog/locallib.php |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/blog/locallib.php b/blog/locallib.php
index 6ac8944..a0d394e 100644
--- a/blog/locallib.php
+++ b/blog/locallib.php
@@ -405,11 +405,10 @@ class blog_entry {
      * @return void
      */
     public function delete() {
-        global $DB, $USER;
-
-        $returnurl = '';
+        global $DB;
 
         $this->delete_attachments();
+        $this->remove_associations();
 
         $DB->delete_records('post', array('id' => $this->id));
         tag_set('post', $this->id, array());
-- 
1.7.9.5


From d8e6e58ec5c4751a9f4c43b6c65fa565966c4a98 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 28 Aug 2012 14:16:15 +0200
Subject: [PATCH 506/903] MDL-34192 mod_assign: prevent ambiguous column use
 for Oracle.

Credit goes to Raymond Antonio from NetSpot.
---
 mod/assign/gradingtable.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index fb5e4ff..40bed66 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -88,7 +88,7 @@ class assign_grading_table extends table_sql implements renderable {
         $params['assignmentid1'] = (int)$this->assignment->get_instance()->id;
         $params['assignmentid2'] = (int)$this->assignment->get_instance()->id;
 
-        $fields = user_picture::fields('u') . ', u.id as userid, u.firstname as firstname, u.lastname as lastname, ';
+        $fields = user_picture::fields('u') . ', u.id as userid, ';
         $fields .= 's.status as status, s.id as submissionid, s.timecreated as firstsubmission, s.timemodified as timesubmitted, ';
         $fields .= 'g.id as gradeid, g.grade as grade, g.timemodified as timemarked, g.timecreated as firstmarked, g.mailed as mailed, g.locked as locked';
         $from = '{user} u LEFT JOIN {assign_submission} s ON u.id = s.userid AND s.assignment = :assignmentid1' .
-- 
1.7.9.5


From 56c5e1db1b2b65d67f2e24acdb0e8d028b1c487c Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 28 Aug 2012 20:15:18 +0200
Subject: [PATCH 507/903] MDL-25492 bb6 import: bump version after big
 changes.

---
 question/format/blackboard_six/version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/format/blackboard_six/version.php b/question/format/blackboard_six/version.php
index c413d77..a4048f4 100644
--- a/question/format/blackboard_six/version.php
+++ b/question/format/blackboard_six/version.php
@@ -25,7 +25,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component = 'qformat_blackboard_six';
-$plugin->version   = 2012061700;
+$plugin->version   = 2012061701;
 
 $plugin->requires  = 2012061700;
 
-- 
1.7.9.5


From ffbe597ef1e2299913c15e0ed0f882fd7d950f86 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 28 Aug 2012 20:37:46 +0200
Subject: [PATCH 508/903] MDL-34250 navigation: Always look for correct parent
 context.

Conflicts:
	lib/navigationlib.php
---
 lib/navigationlib.php |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 92f9029..84ca77f 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -1131,7 +1131,13 @@ class global_navigation extends navigation_node {
                     $addedcategories[$category->id] = $categoryparent->add($category->name, $url, self::TYPE_CATEGORY, $category->name, $category->id);
 
                     if (!$category->visible) {
-                        if (!has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_COURSECAT, $category->parent))) {
+                        // Let's decide the context where viewhidden cap checks will happen.
+                        if ($category->parent == '0') {
+                            $contexttocheck = context_system::instance();
+                        } else {
+                            $contexttocheck = context_coursecat::instance($category->parent);
+                        }
+                        if (!has_capability('moodle/category:viewhiddencategories', $contexttocheck)) {
                             $addedcategories[$category->id]->display = false;
                         } else {
                             $addedcategories[$category->id]->hidden = true;
-- 
1.7.9.5


From b0e5b3b63b53cd53ff07f156e91c28564c68aa8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Tue, 28 Aug 2012 22:52:31 +0200
Subject: [PATCH 509/903] MDL-35109 Improve unittests for cron based fetching
 of available updates

The expected behaviour is as follows:

* If the recently fetched data is older than 48 hours, it is considered
  as outdated and the new fetch is executed
* else, if the recently fetched data is younger than 24 hours, it is
  considered as fresh enough and no fetch is executed
* else, if the current time is after 01:00 AM plus a certain offset
  (which is randomly generated for each site), the fetch is
  executed.
---
 lib/tests/pluginlib_test.php |   47 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 38 insertions(+), 9 deletions(-)

diff --git a/lib/tests/pluginlib_test.php b/lib/tests/pluginlib_test.php
index eb29268..2ec4d0d 100644
--- a/lib/tests/pluginlib_test.php
+++ b/lib/tests/pluginlib_test.php
@@ -103,7 +103,7 @@ class available_update_checker_test extends advanced_testcase {
      */
     public function test_cron_has_fresh_fetch() {
         $provider = testable_available_update_checker::instance();
-        $provider->fakerecentfetch = time() - 59 * MINSECS; // fetched an hour ago
+        $provider->fakerecentfetch = time() - 23 * HOURSECS; // fetched 23 hours ago
         $provider->fakecurrenttimestamp = -1;
         $provider->cron();
         $this->assertTrue(true); // we should get here with no exception thrown
@@ -127,23 +127,52 @@ class available_update_checker_test extends advanced_testcase {
      */
     public function test_cron_offset_execution_not_yet() {
         $provider = testable_available_update_checker::instance();
-        $provider->fakerecentfetch = time() - 24 * HOURSECS;
-        $provider->fakecurrenttimestamp = mktime(1, 40, 02); // 01:40:02 AM
+        $provider->fakecurrenttimestamp = mktime(1, 40, 02); // 01:40:02 AM today
+        $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS;
         $provider->cron();
         $this->assertTrue(true); // we should get here with no exception thrown
     }
 
     /**
-     * The first cron after 01:42 AM today should fetch the data
+     * The first cron after 01:42 AM today should fetch the data and then
+     * it is supposed to wait next 24 hours.
      *
      * @see testable_available_update_checker::cron_execution_offset()
      */
     public function test_cron_offset_execution() {
         $provider = testable_available_update_checker::instance();
-        $provider->fakerecentfetch = time() - 24 * HOURSECS;
-        $provider->fakecurrenttimestamp = mktime(1, 45, 02); // 01:45:02 AM
-        $this->setExpectedException('testable_available_update_checker_cron_executed');
-        $provider->cron();
+
+        // the cron at 01:45 should fetch the data
+        $provider->fakecurrenttimestamp = mktime(1, 45, 02); // 01:45:02 AM today
+        $provider->fakerecentfetch = $provider->fakecurrenttimestamp - 24 * HOURSECS - 1;
+        $executed = false;
+        try {
+            $provider->cron();
+        } catch (testable_available_update_checker_cron_executed $e) {
+            $executed = true;
+        }
+        $this->assertTrue($executed, 'Cron should be executed at 01:45:02 but it was not.');
+
+        // another cron at 06:45 should still consider data as fresh enough
+        $provider->fakerecentfetch = $provider->fakecurrenttimestamp;
+        $provider->fakecurrenttimestamp = mktime(6, 45, 03); // 06:45:03 AM
+        $executed = false;
+        try {
+            $provider->cron();
+        } catch (testable_available_update_checker_cron_executed $e) {
+            $executed = true;
+        }
+        $this->assertFalse($executed, 'Cron should not be executed at 06:45:03 but it was.');
+
+        // the next scheduled execution should happen the next day
+        $provider->fakecurrenttimestamp = $provider->fakerecentfetch + 24 * HOURSECS + 1;
+        $executed = false;
+        try {
+            $provider->cron();
+        } catch (testable_available_update_checker_cron_executed $e) {
+            $executed = true;
+        }
+        $this->assertTrue($executed, 'Cron should be executed the next night but it was not.');
     }
 
     public function test_compare_responses_both_empty() {
@@ -503,7 +532,7 @@ class testable_available_update_checker extends available_update_checker {
     }
 
     protected function cron_execute() {
-        throw new testable_available_update_checker_cron_executed('Cron executed but it should not!');
+        throw new testable_available_update_checker_cron_executed('Cron executed!');
     }
 }
 
-- 
1.7.9.5


From 903d13c0c28148d8327bfc5857f6de655b727098 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Tue, 28 Aug 2012 22:56:18 +0200
Subject: [PATCH 510/903] MDL-35109 Fix
 available_update_checker::cron_has_fresh_fetch()

For the purpose of cron based fetching, recently fetched data are valid
for 24 hours.
---
 lib/pluginlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index 43de510..65e1c35 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -1064,7 +1064,7 @@ class available_update_checker {
             return true;
         }
 
-        if ($now - $recent > HOURSECS) {
+        if ($now - $recent > 24 * HOURSECS) {
             return false;
         }
 
-- 
1.7.9.5


From 2e0b5fef480f72c9a3e845c0b76502689be68ed9 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 08:51:27 +0800
Subject: [PATCH 511/903] MDL-34290 curl class: add functions to return error
 code and to download one file

---
 lib/filelib.php |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/lib/filelib.php b/lib/filelib.php
index 4f60f3c..17525b4 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -2752,6 +2752,8 @@ class curl {
     public  $info;
     /** @var string error */
     public  $error;
+    /** @var int error code */
+    public  $errno;
 
     /** @var array cURL options */
     private $options;
@@ -2895,6 +2897,7 @@ class curl {
         unset($this->options['CURLOPT_INFILE']);
         unset($this->options['CURLOPT_INFILESIZE']);
         unset($this->options['CURLOPT_CUSTOMREQUEST']);
+        unset($this->options['CURLOPT_FILE']);
     }
 
     /**
@@ -3119,6 +3122,7 @@ class curl {
 
         $this->info  = curl_getinfo($curl);
         $this->error = curl_error($curl);
+        $this->errno = curl_errno($curl);
 
         if ($this->debug){
             echo '<h1>Return Data</h1>';
@@ -3203,6 +3207,62 @@ class curl {
     }
 
     /**
+     * Downloads one file and writes it to the specified file handler
+     *
+     * <code>
+     * $c = new curl();
+     * $file = fopen('savepath', 'w');
+     * $result = $c->download_one('http://localhost/', null,
+     *   array('file' => $file, 'timeout' => 5, 'followlocation' => true, 'maxredirs' => 3));
+     * fclose($file);
+     * $download_info = $c->get_info();
+     * if ($result === true) {
+     *   // file downloaded successfully
+     * } else {
+     *   $error_text = $result;
+     *   $error_code = $c->get_errno();
+     * }
+     * </code>
+     *
+     * <code>
+     * $c = new curl();
+     * $result = $c->download_one('http://localhost/', null,
+     *   array('filepath' => 'savepath', 'timeout' => 5, 'followlocation' => true, 'maxredirs' => 3));
+     * // ... see above, no need to close handle and remove file if unsuccessful
+     * </code>
+     *
+     * @param string $url
+     * @param array|null $params key-value pairs to be added to $url as query string
+     * @param array $options request options. Must include either 'file' or 'filepath'
+     * @return bool|string true on success or error string on failure
+     */
+    public function download_one($url, $params, $options = array()) {
+        $options['CURLOPT_HTTPGET'] = 1;
+        $options['CURLOPT_BINARYTRANSFER'] = true;
+        if (!empty($params)){
+            $url .= (stripos($url, '?') !== false) ? '&' : '?';
+            $url .= http_build_query($params, '', '&');
+        }
+        if (!empty($options['filepath']) && empty($options['file'])) {
+            // open file
+            if (!($options['file'] = fopen($options['filepath'], 'w'))) {
+                $this->errno = 100;
+                return get_string('cannotwritefile', 'error', $options['filepath']);
+            }
+            $filepath = $options['filepath'];
+        }
+        unset($options['filepath']);
+        $result = $this->request($url, $options);
+        if (isset($filepath)) {
+            fclose($options['file']);
+            if ($result !== true) {
+                unlink($filepath);
+            }
+        }
+        return $result;
+    }
+
+    /**
      * HTTP PUT method
      *
      * @param string $url
@@ -3279,6 +3339,15 @@ class curl {
     public function get_info() {
         return $this->info;
     }
+
+    /**
+     * Get curl error code
+     *
+     * @return int
+     */
+    public function get_errno() {
+        return $this->errno;
+    }
 }
 
 /**
-- 
1.7.9.5


From 26aaa7e8357507bea997fe09e9f5e52c90123a24 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 09:02:13 +0800
Subject: [PATCH 512/903] MDL-34290 update all references after the source is
 changed

- When several records in {files} have the same record in {files_reference} and the synchronisation is performed, we need to update
all records in {files} so all files know if source is changed and that sync was performed;
- also when local moodle file content is changed we immediately update all files referencing to it (therefore sync of references
to the local files is unnecessary);
---
 lib/filelib.php                  |   16 ++++-----
 lib/filestorage/file_storage.php |   69 ++++++++++++++++++++++++++++++++++++++
 lib/filestorage/stored_file.php  |   46 ++++++++++++++-----------
 3 files changed, 103 insertions(+), 28 deletions(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index 17525b4..7666044 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -804,10 +804,6 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
                 continue;
             }
 
-            // Replaced file content
-            if ($oldfile->get_contenthash() != $newfile->get_contenthash()) {
-                $oldfile->replace_content_with($newfile);
-            }
             // Updated author
             if ($oldfile->get_author() != $newfile->get_author()) {
                 $oldfile->set_author($newfile->get_author());
@@ -827,16 +823,18 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
                 $oldfile->set_sortorder($newfile->get_sortorder());
             }
 
-            // Update file size
-            if ($oldfile->get_filesize() != $newfile->get_filesize()) {
-                $oldfile->set_filesize($newfile->get_filesize());
-            }
-
             // Update file timemodified
             if ($oldfile->get_timemodified() != $newfile->get_timemodified()) {
                 $oldfile->set_timemodified($newfile->get_timemodified());
             }
 
+            // Replaced file content
+            if ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) {
+                $oldfile->replace_content_with($newfile);
+                // push changes to all local files that are referencing this file
+                $fs->update_references_to_storedfile($this);
+            }
+
             // unchanged file or directory - we keep it as is
             unset($newhashes[$oldhash]);
             if (!$oldfile->is_directory()) {
diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index 2b248d1..94cdf33 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -1806,6 +1806,39 @@ class file_storage {
     }
 
     /**
+     * Updates all files that are referencing this file with the new contenthash
+     * and filesize
+     *
+     * @param stored_file $storedfile
+     */
+    public function update_references_to_storedfile(stored_file $storedfile) {
+        global $CFG;
+        $params = array();
+        $params['contextid'] = $storedfile->get_contextid();
+        $params['component'] = $storedfile->get_component();
+        $params['filearea']  = $storedfile->get_filearea();
+        $params['itemid']    = $storedfile->get_itemid();
+        $params['filename']  = $storedfile->get_filename();
+        $params['filepath']  = $storedfile->get_filepath();
+        $reference = self::pack_reference($params);
+        $referencehash = sha1($reference);
+
+        $sql = "SELECT repositoryid, id FROM {files_reference}
+                 WHERE referencehash = ? and reference = ?";
+        $rs = $DB->get_recordset_sql($sql, array($referencehash, $reference));
+
+        $now = time();
+        foreach ($rs as $record) {
+            require_once($CFG->dirroot.'/repository/lib.php');
+            $repo = repository::get_instance($record->repositoryid);
+            $lifetime = $repo->get_reference_file_lifetime($reference);
+            $this->update_references($record->id, $now, $lifetime,
+                    $storedfile->get_contenthash(), $storedfile->get_filesize(), 0);
+        }
+        $rs->close();
+    }
+
+    /**
      * Convert file alias to local file
      *
      * @param stored_file $storedfile a stored_file instances
@@ -1997,4 +2030,40 @@ class file_storage {
         return $DB->get_field('files_reference', 'id',
             array('repositoryid' => $repositoryid, 'referencehash' => sha1($reference)), $strictness);
     }
+
+    /**
+     * Updates a reference to the external resource and all files that use it
+     *
+     * This function is called after synchronisation of an external file and updates the
+     * contenthash, filesize and status of all files that reference this external file
+     * as well as time last synchronised and sync lifetime (how long we don't need to call
+     * synchronisation for this reference).
+     *
+     * @param int $referencefileid
+     * @param int $lastsync
+     * @param int $lifetime
+     * @param string $contenthash
+     * @param int $filesize
+     * @param int $status 0 if ok or 666 if source is missing
+     */
+    public function update_references($referencefileid, $lastsync, $lifetime, $contenthash, $filesize, $status) {
+        global $DB;
+        $referencefileid = clean_param($referencefileid, PARAM_INT);
+        $lastsync = clean_param($lastsync, PARAM_INT);
+        $lifetime = clean_param($lifetime, PARAM_INT);
+        validate_param($contenthash, PARAM_TEXT, NULL_NOT_ALLOWED);
+        $filesize = clean_param($filesize, PARAM_INT);
+        $status = clean_param($status, PARAM_INT);
+        $params = array('contenthash' => $contenthash,
+                    'filesize' => $filesize,
+                    'status' => $status,
+                    'referencefileid' => $referencefileid,
+                    'lastsync' => $lastsync,
+                    'lifetime' => $lifetime);
+        $DB->execute('UPDATE {files} SET contenthash = :contenthash, filesize = :filesize,
+            status = :status, referencelastsync = :lastsync, referencelifetime = :lifetime
+            WHERE referencefileid = :referencefileid', $params);
+        $data = array('id' => $referencefileid, 'lastsync' => $lastsync, 'lifetime' => $lifetime);
+        $DB->update_record('files_reference', (object)$data);
+    }
 }
diff --git a/lib/filestorage/stored_file.php b/lib/filestorage/stored_file.php
index e9410bd..4c5cd0c 100644
--- a/lib/filestorage/stored_file.php
+++ b/lib/filestorage/stored_file.php
@@ -195,6 +195,7 @@ class stored_file {
     public function replace_content_with(stored_file $storedfile) {
         $contenthash = $storedfile->get_contenthash();
         $this->set_contenthash($contenthash);
+        $this->set_filesize($storedfile->get_filesize());
     }
 
     /**
@@ -877,36 +878,43 @@ class stored_file {
      * We update contenthash, filesize and status in files table if changed
      * and we always update lastsync in files_reference table
      *
-     * @param type $contenthash
-     * @param type $filesize
+     * @param string $contenthash
+     * @param int $filesize
+     * @param int $status
+     * @param int $lifetime the life time of this synchronisation results
      */
-    public function set_synchronized($contenthash, $filesize, $status = 0) {
+    public function set_synchronized($contenthash, $filesize, $status = 0, $lifetime = null) {
         global $DB;
         if (!$this->is_external_file()) {
             return;
         }
         $now = time();
-        $filerecord = new stdClass();
-        if ($this->get_contenthash() !== $contenthash) {
-            $filerecord->contenthash = $contenthash;
+        if ($contenthash != $this->file_record->contenthash) {
+            $oldcontenthash = $this->file_record->contenthash;
         }
-        if ($this->get_filesize() != $filesize) {
-            $filerecord->filesize = $filesize;
+        if ($lifetime === null) {
+            $lifetime = $this->file_record->referencelifetime;
         }
-        if ($this->get_status() != $status) {
-            $filerecord->status = $status;
-        }
-        $filerecord->referencelastsync = $now; // TODO MDL-33416 remove this
-        if (!empty($filerecord)) {
-            $this->update($filerecord);
+        // this will update all entries in {files} that have the same filereference id
+        $this->fs->update_references($this->file_record->referencefileid, $now, $lifetime, $contenthash, $filesize, $status);
+        // we don't need to call update() for this object, just set the values of changed fields
+        $this->file_record->contenthash = $contenthash;
+        $this->file_record->filesize = $filesize;
+        $this->file_record->status = $status;
+        $this->file_record->referencelastsync = $now;
+        $this->file_record->referencelifetime = $lifetime;
+        if (isset($oldcontenthash)) {
+            $this->fs->deleted_file_cleanup($oldcontenthash);
         }
-
-        $DB->set_field('files_reference', 'lastsync', $now, array('id'=>$this->get_referencefileid()));
-        // $this->file_record->lastsync = $now; // TODO MDL-33416 uncomment or remove
     }
 
-    public function set_missingsource() {
-        $this->set_synchronized($this->get_contenthash(), 0, 666);
+    /**
+     * Sets the error status for a file that could not be synchronised
+     *
+     * @param int $lifetime the life time of this synchronisation results
+     */
+    public function set_missingsource($lifetime = null) {
+        $this->set_synchronized($this->get_contenthash(), $this->get_filesize(), 666, $lifetime);
     }
 
     /**
-- 
1.7.9.5


From 3af509d6d4dff37e7d602f0c1f7680bf292e2aa7 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 09:11:11 +0800
Subject: [PATCH 513/903] MDL-34290 class oauth_helper, added API to pass
 options to curl (such as timeout)

---
 lib/oauthlib.php |   18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/lib/oauthlib.php b/lib/oauthlib.php
index 587ba19..ed29777 100644
--- a/lib/oauthlib.php
+++ b/lib/oauthlib.php
@@ -59,6 +59,8 @@ class oauth_helper {
     protected $access_token_api;
     /** @var curl */
     protected $http;
+    /** @var array options to pass to the next curl request */
+    protected $http_options;
 
     /**
      * Contructor for oauth_helper.
@@ -106,6 +108,7 @@ class oauth_helper {
             $this->access_token_secret = $args['access_token_secret'];
         }
         $this->http = new curl(array('debug'=>false));
+        $this->http_options = array();
     }
 
     /**
@@ -203,6 +206,15 @@ class oauth_helper {
     }
 
     /**
+     * Sets the options for the next curl request
+     *
+     * @param array $options
+     */
+    public function setup_oauth_http_options($options) {
+        $this->http_options = $options;
+    }
+
+    /**
      * Request token for authentication
      * This is the first step to use OAuth, it will return oauth_token and oauth_token_secret
      * @return array
@@ -210,7 +222,7 @@ class oauth_helper {
     public function request_token() {
         $this->sign_secret = $this->consumer_secret.'&';
         $params = $this->prepare_oauth_parameters($this->request_token_api, array(), 'GET');
-        $content = $this->http->get($this->request_token_api, $params);
+        $content = $this->http->get($this->request_token_api, $params, $this->http_options);
         // Including:
         //     oauth_token
         //     oauth_token_secret
@@ -252,7 +264,7 @@ class oauth_helper {
         $this->sign_secret = $this->consumer_secret.'&'.$secret;
         $params = $this->prepare_oauth_parameters($this->access_token_api, array('oauth_token'=>$token, 'oauth_verifier'=>$verifier), 'POST');
         $this->setup_oauth_http_header($params);
-        $content = $this->http->post($this->access_token_api, $params);
+        $content = $this->http->post($this->access_token_api, $params, $this->http_options);
         $keys = $this->parse_result($content);
         $this->set_access_token($keys['oauth_token'], $keys['oauth_token_secret']);
         return $keys;
@@ -276,7 +288,7 @@ class oauth_helper {
         $this->sign_secret = $this->consumer_secret.'&'.$secret;
         $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method);
         $this->setup_oauth_http_header($oauth_params);
-        $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params));
+        $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params, $this->http_options));
         return $content;
     }
 
-- 
1.7.9.5


From c9fa5b1c05d76695f5be96f2ab23d12d21017030 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 09:55:33 +0800
Subject: [PATCH 514/903] MDL-34290 repository API: allow
 get_file_by_reference return only filesize

we want to allow repositories to perform quick synchronisation, without downloading the file. In this case they return
only filesize, without the contenthash
---
 repository/lib.php |   48 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/repository/lib.php b/repository/lib.php
index 3818cc9..404e597 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -1213,14 +1213,27 @@ abstract class repository {
 
     /**
      * Returns information about file in this repository by reference
-     * {@link repository::get_file_reference()}
-     * {@link repository::get_file()}
      *
-     * Returns null if file not found or is not readable
+     * This function must be implemented for repositories supporting FILE_REFERENCE, it is called
+     * for existing aliases when the lifetime of the previous syncronisation has expired.
+     *
+     * Returns null if file not found or is not readable or timeout occured during request.
+     * Note that this function may be run for EACH file that needs to be synchronised at the
+     * moment. If anything is being downloaded or requested from external sources there
+     * should be a small timeout. The synchronisation is performed to update the size of
+     * the file and/or to update image and re-generated image preview. There is nothing
+     * fatal if syncronisation fails but it is fatal if syncronisation takes too long
+     * and hangs the script generating a page.
      *
-     * @param stdClass $reference file reference db record
+     * If get_file_by_reference() returns filesize just the record in {files} table is being updated.
+     * If filepath, handle or content are returned - the file is also stored in moodle filepool
+     * (recommended for images to generate the thumbnails). For non-image files it is not
+     * recommended to download them to moodle during syncronisation since it may take
+     * unnecessary long time.
+     *
+     * @param stdClass $reference record from DB table {files_reference}
      * @return stdClass|null contains one of the following:
-     *   - 'contenthash' and 'filesize'
+     *   - 'filesize' and optionally 'contenthash'
      *   - 'filepath'
      *   - 'handle'
      *   - 'content'
@@ -2257,7 +2270,7 @@ abstract class repository {
     }
 
     /**
-     * Call to request proxy file sync with repository source.
+     * Performs synchronisation of reference to an external file if the previous one has expired.
      *
      * @param stored_file $file
      * @param bool $resetsynchistory whether to reset all history of sync (used by phpunit)
@@ -2300,20 +2313,31 @@ abstract class repository {
             return false;
         }
 
+        $lifetime = $repository->get_reference_file_lifetime($reference);
         $fileinfo = $repository->get_file_by_reference($reference);
         if ($fileinfo === null) {
             // does not exist any more - set status to missing
-            $file->set_missingsource();
-            //TODO: purge content from pool if we set some other content hash and it is no used any more
+            $file->set_missingsource($lifetime);
             $synchronized[$file->get_id()] = true;
             return true;
         }
 
         $contenthash = null;
         $filesize = null;
-        if (!empty($fileinfo->contenthash)) {
-            // contenthash returned, file already in moodle
-            $contenthash = $fileinfo->contenthash;
+        if (!empty($fileinfo->filesize)) {
+            // filesize returned
+            if (!empty($fileinfo->contenthash) && $fs->content_exists($fileinfo->contenthash)) {
+                // contenthash is specified and valid
+                $contenthash = $fileinfo->contenthash;
+            } else if ($fileinfo->filesize == $file->get_filesize()) {
+                // we don't know the new contenthash but the filesize did not change,
+                // assume the contenthash did not change either
+                $contenthash = $file->get_contenthash();
+            } else {
+                // we can't save empty contenthash so generate contenthash from empty string
+                $fs->add_string_to_pool('');
+                $contenthash = sha1('');
+            }
             $filesize = $fileinfo->filesize;
         } else if (!empty($fileinfo->filepath)) {
             // File path returned
@@ -2336,7 +2360,7 @@ abstract class repository {
         }
 
         // update files table
-        $file->set_synchronized($contenthash, $filesize);
+        $file->set_synchronized($contenthash, $filesize, 0, $lifetime);
         $synchronized[$file->get_id()] = true;
         return true;
     }
-- 
1.7.9.5


From 56e7d14f26b476ae6fb7e8bfba61052dca711ad6 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:17:07 +0800
Subject: [PATCH 515/903] MDL-34290 repository API: do not confuse source and
 reference

make sure that repository function get_file_source_info receives as argument the source of the file,
and get_file receives a reference;
reference is a value of DB field files_reference.reference and result of get_file_reference(source).
Fix dropbox as the only repository that have different values in those fields;
also added information about user in dropbox reference and original
---
 repository/dropbox/lib.php     |   49 +++++++++++++++++++++++++---------------
 repository/filepicker.php      |   17 ++++++++------
 repository/lib.php             |   20 +++++++++++-----
 repository/repository_ajax.php |   19 +++++++++-------
 4 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index 186e63b..9d73e35 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -281,15 +281,22 @@ class repository_dropbox extends repository {
     }
 
     /**
+     * Downloads a file from external repository and saves it in temp dir
      *
-     * @param string $photo_id
-     * @param string $file
-     * @return string
+     * @throws moodle_exception when file could not be downloaded
+     *
+     * @param string $reference the content of files.reference field
+     * @param string $filename filename (without path) to save the downloaded file in the
+     * temporary directory, if omitted or file already exists the new filename will be generated
+     * @return array with elements:
+     *   path: internal location of the file
+     *   url: URL to the source (from parameters)
      */
-    public function get_file($filepath, $saveas = '') {
-        $this->dropbox->set_access_token($this->access_key, $this->access_secret);
+    public function get_file($reference, $saveas = '') {
+        $reference = unserialize($reference);
+        $this->dropbox->set_access_token($reference->access_key, $reference->access_secret);
         $saveas = $this->prepare_file($saveas);
-        return $this->dropbox->get_file($filepath, $saveas);
+        return $this->dropbox->get_file($reference->path, $saveas);
     }
     /**
      * Add Plugin settings input to Moodle form
@@ -354,10 +361,13 @@ class repository_dropbox extends repository {
      * @return string file referece
      */
     public function get_file_reference($source) {
+        global $USER;
         $reference = new stdClass;
         $reference->path = $source;
         $reference->access_key = get_user_preferences($this->setting.'_access_key', '');
         $reference->access_secret = get_user_preferences($this->setting.'_access_secret', '');
+        $reference->userid = $USER->id;
+        $reference->username = fullname($USER);
         return serialize($reference);
     }
 
@@ -380,13 +390,13 @@ class repository_dropbox extends repository {
             $this->set_access_secret($reference->access_secret);
             $path = $this->get_file($reference->path);
             $cachedfilepath = cache_file::create_from_file($reference, $path['path']);
-        }
+                }
         if ($cachedfilepath && is_readable($cachedfilepath)) {
             return (object)array('filepath' => $cachedfilepath);
         } else {
             return null;
         }
-    }
+        }
 
     /**
      * Get file from external repository by reference
@@ -399,8 +409,8 @@ class repository_dropbox extends repository {
      */
     public function cache_file_by_reference($reference, $storedfile) {
         $reference  = unserialize($reference);
-        $path = $this->get_file($reference->path);
-        cache_file::create_from_file($reference, $path['path']);
+        $path = $this->get_file($reference);
+        cache_file::create_from_file($reference->path, $path['path']);
     }
 
     /**
@@ -412,8 +422,12 @@ class repository_dropbox extends repository {
      * @return string
      */
     public function get_reference_details($reference, $filestatus = 0) {
+        global $USER;
         $ref  = unserialize($reference);
         $details = $this->get_name();
+        if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) {
+            $details .= ' ('.$ref->username.')';
+        }
         if (isset($ref->path)) {
             $details .=  ': '. $ref->path;
         }
@@ -428,11 +442,12 @@ class repository_dropbox extends repository {
     /**
      * Return the source information
      *
-     * @param stdClass $filepath
-     * @return string|null
+     * @param string $source
+     * @return string
      */
-    public function get_file_source_info($filepath) {
-        return 'Dropbox: ' . $filepath;
+    public function get_file_source_info($source) {
+        global $USER;
+        return 'Dropbox ('.fullname($USER).'): ' . $source;
     }
 
     /**
@@ -471,10 +486,8 @@ class repository_dropbox extends repository {
             $cachedfile = cache_file::get($reference);
             if ($cachedfile === false) {
                 // Re-fetch resource.
-                $this->set_access_key($reference->access_key);
-                $this->set_access_secret($reference->access_secret);
-                $path = $this->get_file($reference->path);
-                cache_file::create_from_file($reference, $path['path']);
+                $path = $this->get_file($reference);
+                cache_file::create_from_file($reference->path, $path['path']);
             }
         }
     }
diff --git a/repository/filepicker.php b/repository/filepicker.php
index fd16e66..1b67331 100644
--- a/repository/filepicker.php
+++ b/repository/filepicker.php
@@ -282,6 +282,11 @@ case 'download':
     if (!$repo->file_is_accessible($fileurl)) {
         print_error('storedfilecannotread');
     }
+    $record = new stdClass();
+    $reference = $repo->get_file_reference($fileurl);
+
+    $sourcefield = $repo->get_file_source_info($fileurl);
+    $record->source = repository::build_source_field($sourcefield);
 
     // If file is already a reference, set $fileurl = file source, $repo = file repository
     // note that in this case user may not have permission to access the source file directly
@@ -289,13 +294,14 @@ case 'download':
     if ($repo->has_moodle_files()) {
         $file = repository::get_moodle_file($fileurl);
         if ($file && $file->is_external_file()) {
-            $fileurl = $file->get_reference();
+            $sourcefield = $file->get_source(); // remember the original source
+            $record->source = $repo::build_source_field($sourcefield);
+            $reference = $file->get_reference();
             $repo_id = $file->get_repository_id();
             $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
         }
     }
 
-    $record = new stdClass();
     $record->filepath = $savepath;
     $record->filename = $filename;
     $record->component = 'user';
@@ -311,14 +317,11 @@ case 'download':
     $record->contextid = $user_context->id;
     $record->sortorder = 0;
 
-    $sourcefield = $repo->get_file_source_info($fileurl);
-    $record->source = repository::build_source_field($sourcefield);
-
     if ($repo->has_moodle_files()) {
-        $fileinfo = $repo->copy_to_area($fileurl, $record, $maxbytes);
+        $fileinfo = $repo->copy_to_area($reference, $record, $maxbytes);
         redirect($home_url, get_string('downloadsucc', 'repository'));
     } else {
-        $thefile = $repo->get_file($fileurl, $filename);
+        $thefile = $repo->get_file($reference, $filename);
         if (!empty($thefile['path'])) {
             $filesize = filesize($thefile['path']);
             if ($maxbytes != -1 && $filesize>$maxbytes) {
diff --git a/repository/lib.php b/repository/lib.php
index 404e597..bdf3d0d 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -1164,9 +1164,8 @@ abstract class repository {
 
     /**
      * Return human readable reference information
-     * {@link stored_file::get_reference()}
      *
-     * @param string $reference
+     * @param string $reference value of DB field files_reference.reference
      * @param int $filestatus status of the file, 0 - ok, 666 - source missing
      * @return string
      */
@@ -1258,14 +1257,23 @@ abstract class repository {
     /**
      * Return the source information
      *
-     * @param stdClass $url
+     * The result of the function is stored in files.source field. It may be analysed
+     * when the source file is lost or repository may use it to display human-readable
+     * location of reference original.
+     *
+     * This method is called when file is picked for the first time only. When file
+     * (either copy or a reference) is already in moodle and it is being picked
+     * again to another file area (also as a copy or as a reference), the value of
+     * files.source is copied.
+     *
+     * @param string $source the value that repository returned in listing as 'source'
      * @return string|null
      */
-    public function get_file_source_info($url) {
+    public function get_file_source_info($source) {
         if ($this->has_moodle_files()) {
-            return $this->get_reference_details($url, 0);
+            return $this->get_reference_details($source, 0);
         }
-        return $url;
+        return $source;
     }
 
     /**
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index 98701a5..14f16d5 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -220,24 +220,27 @@ switch ($action) {
                 throw new file_exception('storedfilecannotread');
             }
 
+            // {@link repository::build_source_field()}
+            $sourcefield = $repo->get_file_source_info($source);
+            $record->source = $repo::build_source_field($sourcefield);
+
+            $reference = $repo->get_file_reference($source);
+
             // If file is already a reference, set $source = file source, $repo = file repository
             // note that in this case user may not have permission to access the source file directly
             // so no file_browser/file_info can be used below
             if ($repo->has_moodle_files()) {
                 $file = repository::get_moodle_file($source);
                 if ($file && $file->is_external_file()) {
-                    $source = $file->get_reference();
+                    $sourcefield = $file->get_source(); // remember the original source
+                    $record->source = $repo::build_source_field($sourcefield);
+                    $reference = $file->get_reference();
                     $repo_id = $file->get_repository_id();
                     $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
                 }
             }
 
-            // {@link repository::build_source_field()}
-            $sourcefield = $repo->get_file_source_info($source);
-            $record->source = $repo::build_source_field($sourcefield);
-
             if ($usefilereference) {
-                $reference = $repo->get_file_reference($source);
                 // get reference life time from repo
                 $record->referencelifetime = $repo->get_reference_file_lifetime($reference);
                 // Check if file exists.
@@ -281,13 +284,13 @@ switch ($action) {
 
                 // If the moodle file is an alias we copy this alias, otherwise we copy the file
                 // {@link repository::copy_to_area()}.
-                $fileinfo = $repo->copy_to_area($source, $record, $maxbytes);
+                $fileinfo = $repo->copy_to_area($reference, $record, $maxbytes);
 
                 echo json_encode($fileinfo);
                 die;
             } else {
                 // Download file to moodle.
-                $downloadedfile = $repo->get_file($source, $saveas_filename);
+                $downloadedfile = $repo->get_file($reference, $saveas_filename);
                 if (empty($downloadedfile['path'])) {
                     $err->error = get_string('cannotdownload', 'repository');
                     die(json_encode($err));
-- 
1.7.9.5


From e53394ba0b8f769fa9d208de4316a3d229003fa5 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:31:36 +0800
Subject: [PATCH 516/903] MDL-34290 repository API: add timeout to get_file
 and throw exception

- get_file should have a request timeout and throw an exception with the details (i.e. timeout reached) if download can
not be completed
- corrected phpdocs
---
 lang/en/repository.php           |    1 +
 repository/alfresco/lib.php      |    7 +---
 repository/equella/lib.php       |   34 ++++++++++-------
 repository/flickr/lib.php        |    9 +----
 repository/flickr_public/lib.php |    8 +---
 repository/lib.php               |   75 ++++++++++++++++++++------------------
 6 files changed, 65 insertions(+), 69 deletions(-)

diff --git a/lang/en/repository.php b/lang/en/repository.php
index 1245426..8682378 100644
--- a/lang/en/repository.php
+++ b/lang/en/repository.php
@@ -100,6 +100,7 @@ $string['error'] = 'An unknown error occurred!';
 $string['errornotyourfile'] = 'You cannot pick file which is not added by your';
 $string['erroruniquename'] = 'Repository instance name should be unique';
 $string['errorpostmaxsize'] = 'The uploaded file may exceed max_post_size directive in php.ini.';
+$string['errorwhiledownload'] = 'An error occured while downloading the file: {$a}';
 $string['existingrepository'] = 'This repository already exists';
 $string['federatedsearch'] = 'Federated search';
 $string['fileexists'] = 'File name already being used, please use another name';
diff --git a/repository/alfresco/lib.php b/repository/alfresco/lib.php
index b5a871f..dcd957b 100644
--- a/repository/alfresco/lib.php
+++ b/repository/alfresco/lib.php
@@ -202,12 +202,7 @@ class repository_alfresco extends repository {
     public function get_file($uuid, $file = '') {
         $node = $this->user_session->getNode($this->store, $uuid);
         $url = $this->get_url($node);
-        $path = $this->prepare_file($file);
-        $fp = fopen($path, 'w');
-        $c = new curl;
-        $c->download(array(array('url'=>$url, 'file'=>$fp)));
-        fclose($fp);
-        return array('path'=>$path, 'url'=>$url);
+        return parent::get_file($url, $file);
     }
 
     /**
diff --git a/repository/equella/lib.php b/repository/equella/lib.php
index d520a2c..afab067 100644
--- a/repository/equella/lib.php
+++ b/repository/equella/lib.php
@@ -125,23 +125,31 @@ class repository_equella extends repository {
     /**
      * Download a file, this function can be overridden by subclass. {@link curl}
      *
-     * @param string $url the url of file
-     * @param string $filename save location
-     * @return string the location of the file
+     * @param string $reference the source of the file
+     * @param string $filename filename (without path) to save the downloaded file in the
+     * temporary directory
+     * @return null|array null if download failed or array with elements:
+     *   path: internal location of the file
+     *   url: URL to the source (from parameters)
      */
-    public function get_file($url, $filename = '') {
+    public function get_file($reference, $filename = '') {
         global $USER;
-        $cookiename = uniqid('', true) . '.cookie';
-        $dir = make_temp_directory('repository/equella/' . $USER->id);
-        $cookiepathname = $dir . '/' . $cookiename;
+        $ref = @unserialize(base64_decode($reference));
+        if (!isset($ref->url) || !($url = $this->appendtoken($ref->url))) {
+            // Occurs when the user isn't known..
+            return null;
+        }
         $path = $this->prepare_file($filename);
-        $fp = fopen($path, 'w');
+        $cookiepathname = $this->prepare_file($USER->id. '_'. uniqid('', true). '.cookie');
         $c = new curl(array('cookie'=>$cookiepathname));
-        $c->download(array(array('url'=>$url, 'file'=>$fp)), array('CURLOPT_FOLLOWLOCATION'=>true));
-        // Close file handler.
-        fclose($fp);
+        $result = $c->download_one($url, null, array('filepath' => $path, 'followlocation' => true, 'timeout' => self::GETFILE_TIMEOUT));
         // Delete cookie jar.
-        unlink($cookiepathname);
+        if (file_exists($cookiepathname)) {
+            unlink($cookiepathname);
+        }
+        if ($result !== true) {
+            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
+        }
         return array('path'=>$path, 'url'=>$url);
     }
 
@@ -170,7 +178,7 @@ class repository_equella extends repository {
             // Cache the file.
             $path = $this->get_file($url);
             $cachedfilepath = cache_file::create_from_file($url, $path['path']);
-        }
+            }
 
         if ($cachedfilepath && is_readable($cachedfilepath)) {
             return (object)array('filepath' => $cachedfilepath);
diff --git a/repository/flickr/lib.php b/repository/flickr/lib.php
index da01736..478e53b 100644
--- a/repository/flickr/lib.php
+++ b/repository/flickr/lib.php
@@ -252,14 +252,7 @@ class repository_flickr extends repository {
      */
     public function get_file($photoid, $file = '') {
         $url = $this->build_photo_url($photoid);
-        $path = $this->prepare_file($file);
-        $fp = fopen($path, 'w');
-        $c = new curl;
-        $c->download(array(
-            array('url'=>$url, 'file'=>$fp)
-        ));
-        fclose($fp);
-        return array('path'=>$path, 'url'=>$url);
+        return parent::get_file($url, $file);
     }
 
     /**
diff --git a/repository/flickr_public/lib.php b/repository/flickr_public/lib.php
index 083e4c7..b31adaf 100644
--- a/repository/flickr_public/lib.php
+++ b/repository/flickr_public/lib.php
@@ -449,12 +449,8 @@ class repository_flickr_public extends repository {
             $source = $result[2]['source'];
             $url = $result[2]['url'];
         }
-        $path = $this->prepare_file($file);
-        $fp = fopen($path, 'w');
-        $c = new curl;
-        $c->download(array(array('url'=>$source, 'file'=>$fp)));
-        // must close file handler, otherwise gd lib will fail to process it
-        fclose($fp);
+        $result = parent::get_file($source, $file);
+        $path = $result['path'];
         if (!empty($this->usewatermarks)) {
             $img = new moodle_image($path);
             $img->watermark($copyright, array(10,10), array('ttf'=>true, 'fontsize'=>12))->saveas($path);
diff --git a/repository/lib.php b/repository/lib.php
index bdf3d0d..f2340c2 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -16,10 +16,9 @@
 
 /**
  * This file contains classes used to manage the repository plugins in Moodle
- * and was introduced as part of the changes occuring in Moodle 2.0
  *
  * @since 2.0
- * @package   repository
+ * @package   core_repository
  * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -49,7 +48,7 @@ define('RENAME_SUFFIX', '_2');
  * - When you create a type for a plugin that can't have multiple instances, a
  *   instance is automatically created.
  *
- * @package   repository
+ * @package   core_repository
  * @copyright 2009 Jerome Mouneyrac
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -460,12 +459,18 @@ class repository_type {
  * To create repository plugin, see: {@link http://docs.moodle.org/dev/Repository_plugins}
  * See an example: {@link repository_boxnet}
  *
- * @package   repository
- * @category  repository
+ * @package   core_repository
  * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 abstract class repository {
+    /** Timeout in seconds for downloading the external file into moodle */
+    const GETFILE_TIMEOUT = 30;
+    /** Timeout in seconds for syncronising the external file size */
+    const SYNCFILE_TIMEOUT = 1;
+    /** Timeout in seconds for downloading an image file from external repository during syncronisation */
+    const SYNCIMAGE_TIMEOUT = 3;
+
     // $disabled can be set to true to disable a plugin by force
     // example: self::$disabled = true
     /** @var bool force disable repository instance */
@@ -1342,8 +1347,7 @@ abstract class repository {
      * @param string $search searched string
      * @param bool $dynamicmode no recursive call is done when in dynamic mode
      * @param array $list the array containing the files under the passed $fileinfo
-     * @returns int the number of files found
-     *
+     * @return int the number of files found
      */
     public static function build_tree($fileinfo, $search, $dynamicmode, &$list) {
         global $CFG, $OUTPUT;
@@ -1559,6 +1563,7 @@ abstract class repository {
         }
         return $source;
     }
+
     /**
      * Decide where to save the file, can be overwriten by subclass
      *
@@ -1567,17 +1572,9 @@ abstract class repository {
      */
     public function prepare_file($filename) {
         global $CFG;
-        if (!file_exists($CFG->tempdir.'/download')) {
-            mkdir($CFG->tempdir.'/download/', $CFG->directorypermissions, true);
-        }
-        if (is_dir($CFG->tempdir.'/download')) {
-            $dir = $CFG->tempdir.'/download/';
-        }
-        if (empty($filename)) {
-            $filename = uniqid('repo', true).'_'.time().'.tmp';
-        }
-        if (file_exists($dir.$filename)) {
-            $filename = uniqid('m').$filename;
+        $dir = make_temp_directory('download/'.get_class($this).'/');
+        while (empty($filename) || file_exists($dir.$filename)) {
+            $filename = uniqid('', true).'_'.time().'.tmp';
         }
         return $dir.$filename;
     }
@@ -1604,25 +1601,33 @@ abstract class repository {
     }
 
     /**
-     * Download a file, this function can be overridden by subclass. {@link curl}
+     * Downloads a file from external repository and saves it in temp dir
      *
-     * @param string $url the url of file
-     * @param string $filename save location
+     * Function get_file() must be implemented by repositories that support returntypes
+     * FILE_INTERNAL or FILE_REFERENCE. It is invoked to pick up the file and copy it
+     * to moodle. This function is not called for moodle repositories, the function
+     * {@link repository::copy_to_area()} is used instead.
+     *
+     * This function can be overridden by subclass if the files.reference field contains
+     * not just URL or if request should be done differently.
+     *
+     * @see curl
+     * @throws file_exception when error occured
+     *
+     * @param string $url the content of files.reference field, in this implementaion
+     * it is asssumed that it contains the string with URL of the file
+     * @param string $filename filename (without path) to save the downloaded file in the
+     * temporary directory, if omitted or file already exists the new filename will be generated
      * @return array with elements:
      *   path: internal location of the file
      *   url: URL to the source (from parameters)
      */
     public function get_file($url, $filename = '') {
-        global $CFG;
         $path = $this->prepare_file($filename);
-        $fp = fopen($path, 'w');
         $c = new curl;
-        $result = $c->download(array(array('url'=>$url, 'file'=>$fp)));
-        // Close file handler.
-        fclose($fp);
-        if (empty($result)) {
-            unlink($path);
-            return null;
+        $result = $c->download_one($url, null, array('filepath' => $path, 'timeout' => self::GETFILE_TIMEOUT));
+        if ($result !== true) {
+            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
         }
         return array('path'=>$path, 'url'=>$url);
     }
@@ -2042,7 +2047,7 @@ abstract class repository {
      *
      * @param string $search_text search key word
      * @param int $page page
-     * @return mixed {@see repository::get_listing}
+     * @return mixed see {@link repository::get_listing()}
      */
     public function search($search_text, $page = 0) {
         $list = array();
@@ -2397,8 +2402,7 @@ abstract class repository {
  * Exception class for repository api
  *
  * @since 2.0
- * @package   repository
- * @category  repository
+ * @package   core_repository
  * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -2409,8 +2413,7 @@ class repository_exception extends moodle_exception {
  * This is a class used to define a repository instance form
  *
  * @since 2.0
- * @package   repository
- * @category  repository
+ * @package   core_repository
  * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -2524,8 +2527,7 @@ final class repository_instance_form extends moodleform {
  * This is a class used to define a repository type setting form
  *
  * @since 2.0
- * @package   repository
- * @category  repository
+ * @package   core_repository
  * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -2739,6 +2741,7 @@ function initialise_filepicker($args) {
     }
     return $return;
 }
+
 /**
  * Small function to walk an array to attach repository ID
  *
-- 
1.7.9.5


From 22fa5d9a7cc7e78ba1d320163cf0aebf4a1b5131 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:40:31 +0800
Subject: [PATCH 517/903] MDL-34290 repository_filesystem add original info
 function and reduce ref lifetime

---
 repository/filesystem/lib.php |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/repository/filesystem/lib.php b/repository/filesystem/lib.php
index 6eb3b3b..fc7cd9e 100644
--- a/repository/filesystem/lib.php
+++ b/repository/filesystem/lib.php
@@ -245,6 +245,33 @@ class repository_filesystem extends repository {
     }
 
     /**
+     * Return reference file life time
+     *
+     * @param string $ref
+     * @return int
+     */
+    public function get_reference_file_lifetime($ref) {
+        // Does not cost us much to synchronise within our own filesystem, set to 1 minute
+        return 60;
+    }
+
+    /**
+     * Return human readable reference information
+     *
+     * @param string $reference value of DB field files_reference.reference
+     * @param int $filestatus status of the file, 0 - ok, 666 - source missing
+     * @return string
+     */
+    public function get_reference_details($reference, $filestatus = 0) {
+        $details = $this->get_name().': '.$reference;
+        if ($filestatus) {
+            return get_string('lostsource', 'repository', $details);
+        } else {
+            return $details;
+        }
+    }
+
+    /**
      * Returns information about file in this repository by reference
      * {@link repository::get_file_reference()}
      * {@link repository::get_file()}
-- 
1.7.9.5


From 9001c7242e1ffdc658366a6a14e16123be1d9a06 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:50:05 +0800
Subject: [PATCH 518/903] MDL-34290 repository API: add repository function to
 import referenced file

it must be independed from sync_external_file because sync often does not actually download contents, it is used just to retrieve
the size of the file. Besides the timeouts for get_file and sync requests are very different.

Also add option to send_stored_file() to ignore reference and send cached contents
---
 lib/filelib.php                  |    2 +-
 lib/filestorage/file_storage.php |   10 +++---
 lib/filestorage/stored_file.php  |   12 +++++++
 repository/lib.php               |   71 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index 7666044..da23796 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -2326,7 +2326,7 @@ function send_stored_file($stored_file, $lifetime=86400 , $filter=0, $forcedownl
     }
 
     // handle external resource
-    if ($stored_file && $stored_file->is_external_file()) {
+    if ($stored_file && $stored_file->is_external_file() && !isset($options['sendcachedexternalfile'])) {
         $stored_file->send_file($lifetime, $filter, $forcedownload, $options);
         die;
     }
diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index 94cdf33..71c8fc8 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -1841,15 +1841,15 @@ class file_storage {
     /**
      * Convert file alias to local file
      *
+     * @throws moodle_exception if file could not be downloaded
+     *
      * @param stored_file $storedfile a stored_file instances
+     * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit)
      * @return stored_file stored_file
      */
-    public function import_external_file(stored_file $storedfile) {
+    public function import_external_file(stored_file $storedfile, $maxbytes = 0) {
         global $CFG;
-        require_once($CFG->dirroot.'/repository/lib.php');
-        // sync external file
-        repository::sync_external_file($storedfile);
-        // Remove file references
+        $storedfile->import_external_file_contents($maxbytes);
         $storedfile->delete_reference();
         return $storedfile;
     }
diff --git a/lib/filestorage/stored_file.php b/lib/filestorage/stored_file.php
index 4c5cd0c..ea8a8cd 100644
--- a/lib/filestorage/stored_file.php
+++ b/lib/filestorage/stored_file.php
@@ -928,4 +928,16 @@ class stored_file {
     public function send_file($lifetime, $filter, $forcedownload, $options) {
         $this->repository->send_file($this, $lifetime, $filter, $forcedownload, $options);
     }
+
+    /**
+     * Imports the contents of an external file into moodle filepool.
+     *
+     * @throws moodle_exception if file could not be downloaded or is too big
+     * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit)
+     */
+    public function import_external_file_contents($maxbytes = 0) {
+        if ($this->repository) {
+            $this->repository->import_external_file_contents($this, $maxbytes);
+        }
+    }
 }
diff --git a/repository/lib.php b/repository/lib.php
index f2340c2..10f3081 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -1633,6 +1633,77 @@ abstract class repository {
     }
 
     /**
+     * Downloads the file from external repository and saves it in moodle filepool.
+     * This function is different from {@link repository::sync_external_file()} because it has
+     * bigger request timeout and always downloads the content.
+     *
+     * This function is invoked when we try to unlink the file from the source and convert
+     * a reference into a true copy.
+     *
+     * @throws exception when file could not be imported
+     *
+     * @param stored_file $file
+     * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit)
+     */
+    public function import_external_file_contents(stored_file $file, $maxbytes = 0) {
+        if (!$file->is_external_file()) {
+            // nothing to import if the file is not a reference
+            return;
+        } else if ($file->get_repository_id() != $this->id) {
+            // error
+            debugging('Repository instance id does not match');
+            return;
+        } else if ($this->has_moodle_files()) {
+            // files that are references to local files are already in moodle filepool
+            // just validate the size
+            if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) {
+                throw new file_exception('maxbytes');
+            }
+            return;
+        } else {
+            if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) {
+                // note that stored_file::get_filesize() also calls synchronisation
+                throw new file_exception('maxbytes');
+            }
+            $fs = get_file_storage();
+            $contentexists = $fs->content_exists($file->get_contenthash());
+            if ($contentexists && $file->get_filesize() && $file->get_contenthash() === sha1('')) {
+                // even when 'file_storage::content_exists()' returns true this may be an empty
+                // content for the file that was not actually downloaded
+                $contentexists = false;
+            }
+            $now = time();
+            if ($file->get_referencelastsync() + $file->get_referencelifetime() >= $now &&
+                        !$file->get_status() &&
+                        $contentexists) {
+                // we already have the content in moodle filepool and it was synchronised recently.
+                // Repositories may overwrite it if they want to force synchronisation anyway!
+                return;
+            } else {
+                // attempt to get a file
+                try {
+                    $fileinfo = $this->get_file($file->get_reference());
+                    if (isset($fileinfo['path'])) {
+                        list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($fileinfo['path']);
+                        // set this file and other similar aliases synchronised
+                        $lifetime = $this->get_reference_file_lifetime($file->get_reference());
+                        $file->set_synchronized($contenthash, $filesize, 0, $lifetime);
+                    } else {
+                        throw new moodle_exception('errorwhiledownload', 'repository', '', '');
+                    }
+                } catch (Exception $e) {
+                    if ($contentexists) {
+                        // better something than nothing. We have a copy of file. It's sync time
+                        // has expired but it is still very likely that it is the last version
+                    } else {
+                        throw($e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Return size of a file in bytes.
      *
      * @param string $source encoded and serialized data of file
-- 
1.7.9.5


From a5fe04b62bf48126646841fb8bd03ccf6f31864e Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:54:48 +0800
Subject: [PATCH 519/903] MDL-34290 repository_boxnet, boxlib use request
 timeouts

boxlib receives additional argument as request timeout
repository_boxnet::get_file_by_reference respects request timeouts and downloads file into moodle only if it is image
also some improvements to repository_boxnet source display functions;
also do not cache result of request in retrieving of listing, user is unable to see the new files he added to box.
---
 lib/boxlib.php            |   22 ++++++++++++----------
 repository/boxnet/lib.php |   39 ++++++++++++++++++++++++++-------------
 2 files changed, 38 insertions(+), 23 deletions(-)

diff --git a/lib/boxlib.php b/lib/boxlib.php
index 0cee0da..974124f 100644
--- a/lib/boxlib.php
+++ b/lib/boxlib.php
@@ -176,7 +176,7 @@ class boxclient {
         $params['action']     = 'get_account_tree';
         $params['onelevel']   = 1;
         $params['params[]']   = 'nozip';
-        $c = new curl(array('debug'=>$this->debug, 'cache'=>true, 'module_cache'=>'repository'));
+        $c = new curl(array('debug'=>$this->debug));
         $c->setopt(array('CURLOPT_FOLLOWLOCATION'=>1));
         try {
             $args = array();
@@ -196,23 +196,25 @@ class boxclient {
      * Get box.net file info
      *
      * @param string $fileid
-     * @return string|null
+     * @param int $timeout request timeout in seconds
+     * @return stdClass|null
      */
-    function get_file_info($fileid) {
+    function get_file_info($fileid, $timeout = 0) {
         $this->_clearErrors();
         $params = array();
         $params['action']     = 'get_file_info';
         $params['file_id']    = $fileid;
         $params['auth_token'] = $this->auth_token;
         $params['api_key']    = $this->api_key;
-        $http = new curl(array('debug'=>$this->debug, 'cache'=>true, 'module_cache'=>'repository'));
-        $xml = $http->get($this->_box_api_url, $params);
-        $o = simplexml_load_string(trim($xml));
-        if ($o->status == 's_get_file_info') {
-            return $o->info;
-        } else {
-            return null;
+        $http = new curl(array('debug'=>$this->debug));
+        $xml = $http->get($this->_box_api_url, $params, array('timeout' => $timeout));
+        if (!$http->get_errno()) {
+            $o = simplexml_load_string(trim($xml));
+            if ($o->status == 's_get_file_info') {
+                return $o->info;
+            }
         }
+        return null;
     }
 
     /**
diff --git a/repository/boxnet/lib.php b/repository/boxnet/lib.php
index a60b1f4..7a19ec9 100644
--- a/repository/boxnet/lib.php
+++ b/repository/boxnet/lib.php
@@ -277,12 +277,21 @@ class repository_boxnet extends repository {
      * @return null|stdClass with attribute 'filepath'
      */
     public function get_file_by_reference($reference) {
-        $boxnetfile = $this->get_file($reference->reference);
-        // Please note that here we will ALWAYS receive a file
-        // If source file has been removed from external server, box.com still returns
-        // a plain/text file with content 'no such file' (filesize will be 12 bytes)
-        if (!empty($boxnetfile['path'])) {
-            return (object)array('filepath' => $boxnetfile['path']);
+        $array = explode('/', $reference->reference);
+        $fileid = array_pop($array);
+        $fileinfo = $this->boxclient->get_file_info($fileid, self::SYNCFILE_TIMEOUT);
+        if ($fileinfo) {
+            $size = (int)$fileinfo->size;
+            if (file_extension_in_typegroup($fileinfo->file_name, 'web_image')) {
+                // this is an image - download it to moodle
+                $path = $this->prepare_file('');
+                $c = new curl;
+                $result = $c->download_one($reference->reference, null, array('filepath' => $path, 'timeout' => self::SYNCIMAGE_TIMEOUT));
+                if ($result === true) {
+                    return (object)array('filepath' => $path);
+                }
+            }
+            return (object)array('filesize' => $size);
         }
         return null;
     }
@@ -297,13 +306,16 @@ class repository_boxnet extends repository {
      */
     public function get_reference_details($reference, $filestatus = 0) {
         // Indicate it's from box.net repository + secure URL
+        $array = explode('/', $reference);
+        $fileid = array_pop($array);
+        $fileinfo = $this->boxclient->get_file_info($fileid, self::SYNCFILE_TIMEOUT);
+        if (!empty($fileinfo)) {
+            $reference = (string)$fileinfo->file_name;
+        }
         $details = $this->get_name() . ': ' . $reference;
-        if (!$filestatus) {
+        if (!empty($fileinfo)) {
             return $details;
         } else {
-            // at the moment for box.net files we never can be sure that source is missing
-            // because box.com never returns 404 error.
-            // So we never change the status and actually this part is unreachable
             return get_string('lostsource', 'repository', $details);
         }
     }
@@ -315,13 +327,14 @@ class repository_boxnet extends repository {
      * @return string|null
      */
     public function get_file_source_info($url) {
+        global $USER;
         $array = explode('/', $url);
         $fileid = array_pop($array);
-        $fileinfo = $this->boxclient->get_file_info($fileid);
+        $fileinfo = $this->boxclient->get_file_info($fileid, self::SYNCFILE_TIMEOUT);
         if (!empty($fileinfo)) {
-            return 'Box: ' . (string)$fileinfo->file_name;
+            return 'Box ('. fullname($USER). '): '. (string)$fileinfo->file_name. ': '. $url;
         } else {
-            return $url;
+            return 'Box: '. $url;
         }
     }
 
-- 
1.7.9.5


From 120300fb99dafaa47d028001167a061bd5707f92 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 10:57:54 +0800
Subject: [PATCH 520/903] MDL-34290 repository_equella: do not download files
 when not needed

repository_equella::get_file_by_reference respects request timeouts, downloads only images (for thumbnail generation),
does not use cache_file class (content is cached in moodle filepool if needed);
also repository_equella has counter of unsuccessfull connect attempts and do not perform any more if 3 failed
(within one request)
---
 repository/equella/lib.php |   90 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 74 insertions(+), 16 deletions(-)

diff --git a/repository/equella/lib.php b/repository/equella/lib.php
index afab067..14afc6e 100644
--- a/repository/equella/lib.php
+++ b/repository/equella/lib.php
@@ -123,6 +123,49 @@ class repository_equella extends repository {
     }
 
     /**
+     * Counts the number of failed connections.
+     *
+     * If we received the connection timeout more than 3 times in a row, we don't attemt to
+     * connect to the server any more during this request.
+     *
+     * This function is used by {@link repository_equella::get_file_by_reference()} that
+     * synchronises the file size of referenced files.
+     *
+     * @param int $errno omit if we just want to know the return value, the last curl_errno otherwise
+     * @return bool true if we had less than 3 failed connections, false if no more connections
+     * attempts recommended
+     */
+    private function connection_result($errno = null) {
+        static $countfailures = array();
+        $sess = sesskey();
+        if (!array_key_exists($sess, $countfailures)) {
+            $countfailures[$sess] = 0;
+        }
+        if ($errno !== null) {
+            if ($errno == 0) {
+                // reset count of failed connections
+                $countfailures[$sess] = 0;
+            } else if ($errno == 7 /*CURLE_COULDNT_CONNECT*/ || $errno == 9 /*CURLE_REMOTE_ACCESS_DENIED*/) {
+                // problems with server
+                $countfailures[$sess]++;
+            }
+        }
+        return ($countfailures[$sess] < 3);
+    }
+
+    /**
+     * Decide whether or not the file should be synced
+     *
+     * @param stored_file $storedfile
+     * @return bool
+     */
+    public function sync_individual_file(stored_file $storedfile) {
+        // if we had several unsuccessfull attempts to connect to server - do not try any more
+        return $this->connection_result();
+    }
+
+
+    /**
      * Download a file, this function can be overridden by subclass. {@link curl}
      *
      * @param string $reference the source of the file
@@ -155,35 +198,50 @@ class repository_equella extends repository {
 
     /**
      * Returns information about file in this repository by reference
-     * {@link repository::get_file_reference()}
-     * {@link repository::get_file()}
      *
+     * If the file is an image we download the contents and save it in our filesystem
+     * so we can generate thumbnails. Otherwise we just request the file size.
      * Returns null if file not found or can not be accessed
      *
      * @param stdClass $reference file reference db record
-     * @return null|stdClass containing attribute 'filepath'
+     * @return stdClass|null contains one of the following:
+     *   - 'filesize' (for non-image files or files we failed to retrieve fully because of timeout)
+     *   - 'filepath' (for image files that we retrieived and saved)
      */
     public function get_file_by_reference($reference) {
-        $ref = unserialize(base64_decode($reference->reference));
-        $url = $this->appendtoken($ref->url);
-
-        if (!$url) {
+        global $USER;
+        $ref = @unserialize(base64_decode($reference->reference));
+        if (!isset($ref->url) || !($url = $this->appendtoken($ref->url))) {
             // Occurs when the user isn't known..
             return null;
         }
 
-        // We use this cache to get the correct file size.
-        $cachedfilepath = cache_file::get($url, array('ttl' => 0));
-        if ($cachedfilepath === false) {
-            // Cache the file.
-            $path = $this->get_file($url);
-            $cachedfilepath = cache_file::create_from_file($url, $path['path']);
+        $return = null;
+        $cookiepathname = $this->prepare_file($USER->id. '_'. uniqid('', true). '.cookie');
+        $c = new curl(array('cookie' => $cookiepathname));
+        if (file_extension_in_typegroup($ref->filename, 'web_image')) {
+            $path = $this->prepare_file('');
+            $result = $c->download_one($url, null, array('filepath' => $path, 'followlocation' => true, 'timeout' => self::SYNCIMAGE_TIMEOUT));
+            if ($result === true) {
+                $return = (object)array('filepath' => $path);
             }
+        } else {
+            $result = $c->head($url, array('followlocation' => true, 'timeout' => self::SYNCFILE_TIMEOUT));
+        }
+        // Delete cookie jar.
+        if (file_exists($cookiepathname)) {
+            unlink($cookiepathname);
+        }
 
-        if ($cachedfilepath && is_readable($cachedfilepath)) {
-            return (object)array('filepath' => $cachedfilepath);
+        $this->connection_result($c->get_errno());
+        $curlinfo = $c->get_info();
+        if ($return === null && isset($curlinfo['http_code']) && $curlinfo['http_code'] == 200
+                && array_key_exists('download_content_length', $curlinfo)
+                && $curlinfo['download_content_length'] >= 0) {
+            // we received a correct header and at least can tell the file size
+            $return = (object)array('filesize' => $curlinfo['download_content_length']);
         }
-        return null;
+        return $return;
     }
 
     /**
-- 
1.7.9.5


From a6b0ac536291ff7aeff60de8e015a89f2b52b736 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 7 Aug 2012 11:35:51 +0800
Subject: [PATCH 521/903] MDL-34290 Allow to have several requests to the same
 instance of oauth_helper

---
 lib/filelib.php  |    7 +++++++
 lib/oauthlib.php |    3 +++
 2 files changed, 10 insertions(+)

diff --git a/lib/filelib.php b/lib/filelib.php
index da23796..f7487c3 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -2899,6 +2899,13 @@ class curl {
     }
 
     /**
+     * Resets the HTTP Request headers (to prepare for the new request)
+     */
+    public function resetHeader() {
+        $this->header = array();
+    }
+
+    /**
      * Set HTTP Request Header
      *
      * @param array $header
diff --git a/lib/oauthlib.php b/lib/oauthlib.php
index ed29777..bc198b9 100644
--- a/lib/oauthlib.php
+++ b/lib/oauthlib.php
@@ -289,6 +289,9 @@ class oauth_helper {
         $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method);
         $this->setup_oauth_http_header($oauth_params);
         $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params, $this->http_options));
+        // reset http header and options to prepare for the next request
+        $this->http->resetHeader();
+        // return request return value
         return $content;
     }
 
-- 
1.7.9.5


From 1d168fbd5f787d89bf2a614e1649c109f5d86678 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 7 Aug 2012 11:10:24 +0800
Subject: [PATCH 522/903] MDL-34290 oauthlib_helper support for POST request

---
 lib/oauthlib.php |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/oauthlib.php b/lib/oauthlib.php
index bc198b9..7f5ea64 100644
--- a/lib/oauthlib.php
+++ b/lib/oauthlib.php
@@ -286,7 +286,11 @@ class oauth_helper {
         }
         // to access protected resource, sign_secret will alwasy be consumer_secret+token_secret
         $this->sign_secret = $this->consumer_secret.'&'.$secret;
-        $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method);
+        if (strtolower($method) === 'post' && !empty($params)) {
+            $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token) + $params, $method);
+        } else {
+            $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method);
+        }
         $this->setup_oauth_http_header($oauth_params);
         $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params, $this->http_options));
         // reset http header and options to prepare for the next request
-- 
1.7.9.5


From 56e41718da8164f2e7354658d0c09886e4021d72 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 7 Aug 2012 11:26:19 +0800
Subject: [PATCH 523/903] MDL-34290 repository_dropbox reference handling

- When Dropbox file is inserted by reference, the shared link is created and stored
- Added a function to fix old references (containing access_key/secret) with the proper ones
- Added support for external links in Dropbox (FILE_EXTERNAL), using the shared link API
- Make sure that repository::get_link() receives reference and not source (other repositories than Dropbox have those fields identical)
- Function get_file_by_reference respects request timeouts, downloads only images (for thumbnail generation),
- Function get_file respects request timeout
- do not use cache_file class (content is cached in moodle filepool if needed)
- added parameter for maximum size of files to cache
- added 'Manage' link for Filepicker
- added user name to
- added user name (if different from current) to 'Original' field
- added/corrected phpdocs
---
 repository/dropbox/db/upgrade.php                 |   39 +++
 repository/dropbox/lang/en/repository_dropbox.php |    4 +-
 repository/dropbox/lib.php                        |  290 +++++++++++++++++----
 repository/dropbox/locallib.php                   |  101 +++++--
 repository/dropbox/version.php                    |    5 +-
 repository/repository_ajax.php                    |    6 +-
 6 files changed, 360 insertions(+), 85 deletions(-)
 create mode 100644 repository/dropbox/db/upgrade.php

diff --git a/repository/dropbox/db/upgrade.php b/repository/dropbox/db/upgrade.php
new file mode 100644
index 0000000..f562cf4
--- /dev/null
+++ b/repository/dropbox/db/upgrade.php
@@ -0,0 +1,39 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @param int $oldversion the version we are upgrading from
+ * @return bool result
+ */
+function xmldb_repository_dropbox_upgrade($oldversion) {
+    global $CFG, $DB;
+
+    $dbman = $DB->get_manager();
+
+    // Moodle v2.3.0 release upgrade line
+    // Put any upgrade step following this
+
+    if ($oldversion < 2012080702) {
+        // Set the default value for dropbox_cachelimit
+        $value = get_config('dropbox', 'dropbox_cachelimit');
+        if (empty($value)) {
+            set_config('dropbox_cachelimit', 1024*1024, 'dropbox');
+        }
+        upgrade_plugin_savepoint(true, 2012080702, 'repository', 'dropbox');
+    }
+
+    return true;
+}
diff --git a/repository/dropbox/lang/en/repository_dropbox.php b/repository/dropbox/lang/en/repository_dropbox.php
index 4cda0af..4937c13 100644
--- a/repository/dropbox/lang/en/repository_dropbox.php
+++ b/repository/dropbox/lang/en/repository_dropbox.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -31,4 +30,7 @@ $string['apikey'] = 'Dropbox API key';
 $string['dropbox'] = 'Dropbox';
 $string['secret'] = 'Dropbox secret';
 $string['instruction'] = 'You can get your API Key and secret from <a href="http://www.dropbox.com/developers/apps">Dropbox developers</a>. When setting up your key please select "Full Dropbox" as the "Access level".';
+$string['cachelimit'] = 'Cache limit';
+$string['cachelimit_info'] = 'Enter the maximum size of files (in bytes) to be cached on server for Dropbox aliases/shortcuts. Cached files will be served when the source is no longer available. Empty value or zero mean caching of all files regardless of size.';
+$string['error_cachelimit'] = 'Must be a positive integer or empty value';
 $string['dropbox:view'] = 'View a Dropbox folder';
diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index 9d73e35..008b566 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -19,12 +19,20 @@
  *
  * @since 2.0
  * @package    repository_dropbox
+ * @copyright  2012 Marina Glancy
  * @copyright  2010 Dongsheng Cai {@link http://dongsheng.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 require_once($CFG->dirroot . '/repository/lib.php');
 require_once(dirname(__FILE__).'/locallib.php');
 
+/**
+ * Repository to access Dropbox files
+ *
+ * @package    repository_dropbox
+ * @copyright  2010 Dongsheng Cai
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
 class repository_dropbox extends repository {
     /** @var dropbox the instance of dropbox client */
     private $dropbox;
@@ -32,6 +40,8 @@ class repository_dropbox extends repository {
     public $files;
     /** @var bool flag of login status */
     public $logged=false;
+    /** @var int maximum size of file to cache in moodle filepool */
+    public $cachelimit=null;
 
     /** @var int cached file ttl */
     private $cachedfilettl = null;
@@ -166,7 +176,7 @@ class repository_dropbox extends repository {
 
         $list = array();
         $list['list'] = array();
-        $list['manage'] = false;
+        $list['manage'] = 'https://www.dropbox.com/home';
         $list['dynload'] = true;
         $list['nosearch'] = true;
         // process breadcrumb trail
@@ -256,8 +266,13 @@ class repository_dropbox extends repository {
         if (!empty($options['dropbox_secret'])) {
             set_config('dropbox_secret', trim($options['dropbox_secret']), 'dropbox');
         }
+        if (!empty($options['dropbox_cachelimit'])) {
+            $this->cachelimit = (int)trim($options['dropbox_cachelimit']);
+            set_config('dropbox_cachelimit', $this->cachelimit, 'dropbox');
+        }
         unset($options['dropbox_key']);
         unset($options['dropbox_secret']);
+        unset($options['dropbox_cachelimit']);
         $ret = parent::set_option($options);
         return $ret;
     }
@@ -272,36 +287,118 @@ class repository_dropbox extends repository {
             return trim(get_config('dropbox', 'dropbox_key'));
         } elseif ($config==='dropbox_secret') {
             return trim(get_config('dropbox', 'dropbox_secret'));
+        } elseif ($config==='dropbox_cachelimit') {
+            return $this->max_cache_bytes();
         } else {
+            $options = parent::get_option();
             $options['dropbox_key'] = trim(get_config('dropbox', 'dropbox_key'));
             $options['dropbox_secret'] = trim(get_config('dropbox', 'dropbox_secret'));
+            $options['dropbox_cachelimit'] = $this->max_cache_bytes();
         }
-        $options = parent::get_option($config);
         return $options;
     }
 
     /**
+     * Fixes references in DB that contains user credentials
+     *
+     * @param string $reference contents of DB field files_reference.reference
+     */
+    public function fix_old_style_reference($reference) {
+        $ref = unserialize($reference);
+        if (!isset($ref->url)) {
+            $this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
+            $ref->url = $this->dropbox->get_file_share_link($ref->path, self::GETFILE_TIMEOUT);
+            if (!$ref->url) {
+                // some error occurred, do not fix reference for now
+                return $reference;
+            }
+        }
+        unset($ref->access_key);
+        unset($ref->access_secret);
+        $newreference = serialize($ref);
+        if ($newreference !== $reference) {
+            // we need to update references in the database
+            global $DB;
+            $params = array(
+                'newreference' => $newreference,
+                'newhash' => sha1($newreference),
+                'reference' => $reference,
+                'hash' => sha1($reference),
+                'repoid' => $this->id
+            );
+            $refid = $DB->get_field_sql('SELECT id FROM {files_reference}
+                WHERE reference = :reference AND referencehash = :hash
+                AND repositoryid = :repoid', $params);
+            if (!$refid) {
+                return $newreference;
+            }
+            $existingrefid = $DB->get_field_sql('SELECT id FROM {files_reference}
+                    WHERE reference = :newreference AND referencehash = :newhash
+                    AND repositoryid = :repoid', $params);
+            if ($existingrefid) {
+                // the same reference already exists, we unlink all files from it,
+                // link them to the current reference and remove the old one
+                $DB->execute('UPDATE {files} SET referencefileid = :refid
+                    WHERE referencefileid = :existingrefid',
+                    array('refid' => $refid, 'existingrefid' => $existingrefid));
+                $DB->delete_records('files_reference', array('id' => $existingrefid));
+            }
+            // update the reference
+            $params['refid'] = $refid;
+            $DB->execute('UPDATE {files_reference}
+                SET reference = :newreference, referencehash = :newhash
+                WHERE id = :refid', $params);
+        }
+        return $newreference;
+    }
+
+    /**
+     * Converts a URL received from dropbox API function 'shares' into URL that
+     * can be used to download/access file directly
+     *
+     * @param string $sharedurl
+     * @return string
+     */
+    private function get_file_download_link($sharedurl) {
+        return preg_replace('|^(\w*://)www(.dropbox.com)|','\1dl\2',$sharedurl);
+    }
+
+    /**
      * Downloads a file from external repository and saves it in temp dir
      *
      * @throws moodle_exception when file could not be downloaded
      *
-     * @param string $reference the content of files.reference field
-     * @param string $filename filename (without path) to save the downloaded file in the
+     * @param string $reference the content of files.reference field or result of
+     * function {@link repository_dropbox::get_file_reference()}
+     * @param string $saveas filename (without path) to save the downloaded file in the
      * temporary directory, if omitted or file already exists the new filename will be generated
      * @return array with elements:
      *   path: internal location of the file
      *   url: URL to the source (from parameters)
      */
     public function get_file($reference, $saveas = '') {
-        $reference = unserialize($reference);
-        $this->dropbox->set_access_token($reference->access_key, $reference->access_secret);
+        $ref = unserialize($reference);
         $saveas = $this->prepare_file($saveas);
-        return $this->dropbox->get_file($reference->path, $saveas);
+        if (isset($ref->access_key) && isset($ref->access_secret) && isset($ref->path)) {
+            $this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
+            return $this->dropbox->get_file($ref->path, $saveas, self::GETFILE_TIMEOUT);
+        } else if (isset($ref->url)) {
+            $c = new curl;
+            $url = $this->get_file_download_link($ref->url);
+            $result = $c->download_one($url, null, array('filepath' => $saveas, 'timeout' => self::GETFILE_TIMEOUT, 'followlocation' => true));
+            $info = $c->get_info();
+            if ($result !== true || !isset($info['http_code']) || $info['http_code'] != 200) {
+                throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
+            }
+            return array('path'=>$saveas, 'url'=>$url);
+        }
+        throw new moodle_exception('cannotdownload', 'repository');
     }
     /**
      * Add Plugin settings input to Moodle form
      *
-     * @param object $mform
+     * @param moodleform $mform Moodle form (passed by reference)
+     * @param string $classname repository class name
      */
     public static function type_config_form($mform, $classname = 'repository') {
         global $CFG;
@@ -325,6 +422,25 @@ class repository_dropbox extends repository {
         $mform->addRule('dropbox_secret', $strrequired, 'required', null, 'client');
         $str_getkey = get_string('instruction', 'repository_dropbox');
         $mform->addElement('static', null, '',  $str_getkey);
+
+        $mform->addElement('text', 'dropbox_cachelimit', get_string('cachelimit', 'repository_dropbox'), array('size' => '40'));
+        $mform->addElement('static', 'dropbox_cachelimit_info', '',  get_string('cachelimit_info', 'repository_dropbox'));
+    }
+
+    /**
+     * Validate Admin Settings Moodle form
+     *
+     * @param moodleform $mform Moodle form (passed by reference)
+     * @param array $data array of ("fieldname"=>value) of submitted data
+     * @param array $errors array of ("fieldname"=>errormessage) of errors
+     * @return array array of errors
+     */
+    public static function type_form_validation($mform, $data, $errors) {
+        if (!empty($data['dropbox_cachelimit']) && (!is_number($data['dropbox_cachelimit']) ||
+                (int)$data['dropbox_cachelimit']<0)) {
+            $errors['dropbox_cachelimit'] = get_string('error_cachelimit', 'repository_dropbox');
+        }
+        return $errors;
     }
 
     /**
@@ -333,7 +449,7 @@ class repository_dropbox extends repository {
      * @return array
      */
     public static function get_type_option_names() {
-        return array('dropbox_key', 'dropbox_secret', 'pluginname');
+        return array('dropbox_key', 'dropbox_secret', 'pluginname', 'dropbox_cachelimit');
     }
 
     /**
@@ -351,7 +467,18 @@ class repository_dropbox extends repository {
      * @return int
      */
     public function supported_returntypes() {
-        return FILE_INTERNAL | FILE_REFERENCE;
+        return FILE_INTERNAL | FILE_REFERENCE | FILE_EXTERNAL;
+    }
+
+    /**
+     * Return file URL for external link
+     *
+     * @param string $reference the result of get_file_reference()
+     * @return string
+     */
+    public function get_link($reference) {
+        $ref = unserialize($reference);
+        return $this->get_file_download_link($ref->url);
     }
 
     /**
@@ -364,10 +491,24 @@ class repository_dropbox extends repository {
         global $USER;
         $reference = new stdClass;
         $reference->path = $source;
-        $reference->access_key = get_user_preferences($this->setting.'_access_key', '');
-        $reference->access_secret = get_user_preferences($this->setting.'_access_secret', '');
         $reference->userid = $USER->id;
         $reference->username = fullname($USER);
+        $reference->access_key = get_user_preferences($this->setting.'_access_key', '');
+        $reference->access_secret = get_user_preferences($this->setting.'_access_secret', '');
+
+        // by API we don't know if we need this reference to just download a file from dropbox
+        // into moodle filepool or create a reference. Since we need to create a shared link
+        // only in case of reference we analyze the script parameter
+        $usefilereference = optional_param('usefilereference', false, PARAM_BOOL);
+        if ($usefilereference) {
+            $this->dropbox->set_access_token($reference->access_key, $reference->access_secret);
+            $url = $this->dropbox->get_file_share_link($source, self::GETFILE_TIMEOUT);
+            if ($url) {
+                unset($reference->access_key);
+                unset($reference->access_secret);
+                $reference->url = $url;
+            }
+        }
         return serialize($reference);
     }
 
@@ -382,35 +523,51 @@ class repository_dropbox extends repository {
      * @return null|stdClass that has 'filepath' property
      */
     public function get_file_by_reference($reference) {
-        $reference  = unserialize($reference->reference);
-        $cachedfilepath = cache_file::get($reference, array('ttl' => $this->cachedfilettl));
-        if ($cachedfilepath === false) {
-            // Cache the file.
-            $this->set_access_key($reference->access_key);
-            $this->set_access_secret($reference->access_secret);
-            $path = $this->get_file($reference->path);
-            $cachedfilepath = cache_file::create_from_file($reference, $path['path']);
-                }
-        if ($cachedfilepath && is_readable($cachedfilepath)) {
-            return (object)array('filepath' => $cachedfilepath);
-        } else {
+        global $USER;
+        $ref = unserialize($reference->reference);
+        if (!isset($ref->url)) {
+            // this is an old-style reference in DB. We need to fix it
+            $ref = unserialize($this->fix_old_style_reference($reference->reference));
+        }
+        if (!isset($ref->url)) {
             return null;
         }
+        $c = new curl;
+        $url = $this->get_file_download_link($ref->url);
+        if (file_extension_in_typegroup($ref->path, 'web_image')) {
+            $saveas = $this->prepare_file('');
+            try {
+                $result = $c->download_one($url, array(), array('filepath' => $saveas, 'timeout' => self::SYNCIMAGE_TIMEOUT, 'followlocation' => true));
+                $info = $c->get_info();
+                if ($result === true && isset($info['http_code']) && $info['http_code'] == 200) {
+                    return (object)array('filepath' => $saveas);
+                }
+            } catch (Exception $e) {}
         }
+        $c->get($url, null, array('timeout' => self::SYNCIMAGE_TIMEOUT, 'followlocation' => true, 'nobody' => true));
+        $info = $c->get_info();
+        if (isset($info['http_code']) && $info['http_code'] == 200 &&
+                array_key_exists('download_content_length', $info) &&
+                $info['download_content_length'] >= 0) {
+            return (object)array('filesize' => (int)$info['download_content_length']);
+        }
+        return null;
+    }
 
     /**
-     * Get file from external repository by reference
-     * {@link repository::get_file_reference()}
-     * {@link repository::get_file()}
+     * Cache file from external repository by reference
+     *
+     * Dropbox repository regularly caches all external files that are smaller than
+     * {@link repository_dropbox::max_cache_bytes()}
      *
      * @param string $reference this reference is generated by
      *                          repository::get_file_reference()
      * @param stored_file $storedfile created file reference
      */
     public function cache_file_by_reference($reference, $storedfile) {
-        $reference  = unserialize($reference);
-        $path = $this->get_file($reference);
-        cache_file::create_from_file($reference->path, $path['path']);
+        try {
+            $this->import_external_file_contents($storedfile, $this->max_cache_bytes());
+        } catch (Exception $e) {}
     }
 
     /**
@@ -424,17 +581,21 @@ class repository_dropbox extends repository {
     public function get_reference_details($reference, $filestatus = 0) {
         global $USER;
         $ref  = unserialize($reference);
-        $details = $this->get_name();
+        $detailsprefix = $this->get_name();
         if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) {
-            $details .= ' ('.$ref->username.')';
+            $detailsprefix .= ' ('.$ref->username.')';
         }
+        $details = $detailsprefix;
         if (isset($ref->path)) {
-            $details .=  ': '. $ref->path;
+            $details .= ': '. $ref->path;
         }
         if (isset($ref->path) && !$filestatus) {
             // Indicate this is from dropbox with path
             return $details;
         } else {
+            if (isset($ref->url)) {
+                $details = $detailsprefix. ': '. $ref->url;
+            }
             return get_string('lostsource', 'repository', $details);
         }
     }
@@ -451,6 +612,24 @@ class repository_dropbox extends repository {
     }
 
     /**
+     * Returns the maximum size of the Dropbox files to cache in moodle
+     *
+     * Note that {@link repository_dropbox::get_file_by_reference()} called by
+     * {@link repository::sync_external_file()} will try to cache images even
+     * when they are bigger in order to generate thumbnails. However there is
+     * a small timeout for downloading images for synchronisation and it will
+     * probably fail if the image is too big.
+     *
+     * @return int
+     */
+    public function max_cache_bytes() {
+        if ($this->cachelimit === null) {
+            $this->cachelimit = (int)get_config('dropbox', 'dropbox_cachelimit');
+        }
+        return $this->cachelimit;
+    }
+
+    /**
      * Repository method to serve the referenced file
      *
      * This method is ivoked from {@link send_stored_file()}.
@@ -464,31 +643,42 @@ class repository_dropbox extends repository {
      * @param array $options additional options affecting the file serving
      */
     public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {
-        $fileinfo = $this->get_file_by_reference((object)array('reference' => $storedfile->get_reference()));
-        if ($fileinfo && !empty($fileinfo->filepath) && is_readable($fileinfo->filepath)) {
-            $filename = $storedfile->get_filename();
-            if ($options && isset($options['filename'])) {
-                $filename = $options['filename'];
+        $ref = unserialize($storedfile->get_reference());
+        if ($storedfile->get_filesize() > $this->max_cache_bytes()) {
+            header('Location: '.$this->get_file_download_link($ref->url));
+            die;
+        }
+        try {
+            $this->import_external_file_contents($storedfile, $this->max_cache_bytes());
+            if (!is_array($options)) {
+                $options = array();
             }
-            $dontdie = ($options && isset($options['dontdie']));
-            send_file($fileinfo->filepath, $filename, $lifetime , $filter, false, $forcedownload, '', $dontdie);
-        } else {
-            send_file_not_found();
+            $options['sendcachedexternalfile'] = true;
+            send_stored_file($storedfile, $lifetime, $filter, $forcedownload, $options);
+        } catch (moodle_exception $e) {
+            // redirect to Dropbox, it will show the error.
+            // We redirect to Dropbox shared link, not to download link here!
+            header('Location: '.$ref->url);
+            die;
         }
     }
 
+    /**
+     * Caches all references to Dropbox files in moodle filepool
+     *
+     * Invoked by {@link repository_dropbox_cron()}. Only files smaller than
+     * {@link repository_dropbox::max_cache_bytes()} and only files which
+     * synchronisation timeout have not expired are cached.
+     */
     public function cron() {
         $fs = get_file_storage();
         $files = $fs->get_external_files($this->id);
         foreach ($files as $file) {
-            $reference = unserialize($file->get_reference());
-
-            $cachedfile = cache_file::get($reference);
-            if ($cachedfile === false) {
-                // Re-fetch resource.
-                $path = $this->get_file($reference);
-                cache_file::create_from_file($reference->path, $path['path']);
-            }
+            try {
+                // This call will cache all files that are smaller than max_cache_bytes()
+                // and synchronise file size of all others
+                $this->import_external_file_contents($file, $this->max_cache_bytes());
+            } catch (moodle_exception $e) {}
         }
     }
 }
diff --git a/repository/dropbox/locallib.php b/repository/dropbox/locallib.php
index 2fb322a..89c7e73 100644
--- a/repository/dropbox/locallib.php
+++ b/repository/dropbox/locallib.php
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,34 +15,50 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * dropbox class
  * A helper class to access dropbox resources
  *
  * @since 2.0
- * @package    repository
- * @subpackage dropbox
+ * @package    repository_dropbox
+ * @copyright  2012 Marina Glancy
  * @copyright  2010 Dongsheng Cai
  * @author     Dongsheng Cai <dongsheng@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
 require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
 require_once($CFG->libdir.'/oauthlib.php');
 
+/**
+ * Authentication class to access Dropbox API
+ *
+ * @package    repository_dropbox
+ * @copyright  2010 Dongsheng Cai
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
 class dropbox extends oauth_helper {
-    /** dropbox access type, can be dropbox or sandbox */
+    /** @var string dropbox access type, can be dropbox or sandbox */
     private $mode = 'dropbox';
-    /** dropbox api url*/
+    /** @var string dropbox api url*/
     private $dropbox_api = 'https://api.dropbox.com/1';
-    /** dropbox content api url*/
+    /** @var string dropbox content api url*/
     private $dropbox_content_api = 'https://api-content.dropbox.com/1';
 
+    /**
+     * Constructor for dropbox class
+     *
+     * @param array $args
+     */
     function __construct($args) {
         parent::__construct($args);
     }
+
     /**
      * Get file listing from dropbox
+     *
+     * @param string $path
+     * @param string $token
+     * @param string $secret
+     * @return array
      */
     public function get_listing($path='/', $token='', $secret='') {
         $url = $this->dropbox_api.'/metadata/'.$this->mode.$path;
@@ -53,9 +68,12 @@ class dropbox extends oauth_helper {
     }
 
     /**
-     * Download a file
+     * Prepares the filename to pass to Dropbox API as part of URL
+     *
+     * @param string $filepath
+     * @return string
      */
-    public function get_file($filepath, $saveas = '') {
+    protected function prepare_filepath($filepath) {
         $info = pathinfo($filepath);
         $dirname = $info['dirname'];
         $basename = $info['basename'];
@@ -64,33 +82,60 @@ class dropbox extends oauth_helper {
             $filepath = $dirname . '/' . $basename;
             $filepath = str_replace("%2F", "/", rawurlencode($filepath));
         }
-
-        $url = $this->dropbox_content_api.'/files/'.$this->mode.$filepath;
-        $content = $this->get($url, array());
-        file_put_contents($saveas, $content);
-        return array('path'=>$saveas, 'url'=>$url);
+        return $filepath;
     }
 
     /**
-     * Get file url
+     * Downloads a file from Dropbox and saves it locally
      *
-     * @param string $filepath file path
-     * @return string file url
+     * @throws moodle_exception when file could not be downloaded
+     *
+     * @param string $filepath local path in Dropbox
+     * @param string $saveas path to file to save the result
+     * @param int $timeout request timeout in seconds, 0 means no timeout
+     * @return array with attributes 'path' and 'url'
      */
-    public function get_file_url($filepath) {
-        $info = pathinfo($filepath);
-        $dirname = $info['dirname'];
-        $basename = $info['basename'];
-        $filepath = $dirname . rawurlencode($basename);
-        if ($dirname != '/') {
-            $filepath = $dirname . '/' . $basename;
-            $filepath = str_replace("%2F", "/", rawurlencode($filepath));
+    public function get_file($filepath, $saveas, $timeout = 0) {
+        $url = $this->dropbox_content_api.'/files/'.$this->mode.$this->prepare_filepath($filepath);
+        if (!($fp = fopen($saveas, 'w'))) {
+            throw new moodle_exception('cannotwritefile', 'error', '', $saveas);
         }
+        $this->setup_oauth_http_options(array('timeout' => $timeout, 'file' => $fp, 'BINARYTRANSFER' => true));
+        $result = $this->get($url);
+        fclose($fp);
+        if ($result === true) {
+            return array('path'=>$saveas, 'url'=>$url);
+        } else {
+            unlink($saveas);
+            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
+        }
+    }
 
-        $url = $this->dropbox_content_api.'/files/'.$this->mode.$filepath;
-        return $url;
+    /**
+     * Returns direct link to Dropbox file
+     *
+     * @param string $filepath local path in Dropbox
+     * @param int $timeout request timeout in seconds, 0 means no timeout
+     * @return string|null information object or null if request failed with an error
+     */
+    public function get_file_share_link($filepath, $timeout = 0) {
+        $url = $this->dropbox_api.'/shares/'.$this->mode.$this->prepare_filepath($filepath);
+        $this->setup_oauth_http_options(array('timeout' => $timeout));
+        $result = $this->post($url, array('short_url'=>0));
+        if (!$this->http->get_errno()) {
+            $data = json_decode($result);
+            if (isset($data->url)) {
+                return $data->url;
+            }
+        }
+        return null;
     }
 
+    /**
+     * Sets Dropbox API mode (dropbox or sandbox, default dropbox)
+     *
+     * @param string $mode
+     */
     public function set_mode($mode) {
         $this->mode = $mode;
     }
diff --git a/repository/dropbox/version.php b/repository/dropbox/version.php
index ac70aab..2df0544 100644
--- a/repository/dropbox/version.php
+++ b/repository/dropbox/version.php
@@ -17,8 +17,7 @@
 /**
  * Version details
  *
- * @package    repository
- * @subpackage dropbox
+ * @package    repository_dropbox
  * @copyright  2010 Dongsheng Cai
  * @author     Dongsheng Cai <dongsheng@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -26,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012061700;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012080702;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012061700;        // Requires this Moodle version
 $plugin->component = 'repository_dropbox'; // Full name of the plugin (used for diagnostics)
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index 14f16d5..acc2e39 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -180,10 +180,12 @@ switch ($action) {
         // allow external links in url element all the time
         $allowexternallink = ($allowexternallink || ($env == 'url'));
 
+        $reference = $repo->get_file_reference($source);
+
         // Use link of the files
         if ($allowexternallink and $linkexternal === 'yes' and ($repo->supported_returntypes() & FILE_EXTERNAL)) {
             // use external link
-            $link = $repo->get_link($source);
+            $link = $repo->get_link($reference);
             $info = array();
             $info['file'] = $saveas_filename;
             $info['type'] = 'link';
@@ -224,8 +226,6 @@ switch ($action) {
             $sourcefield = $repo->get_file_source_info($source);
             $record->source = $repo::build_source_field($sourcefield);
 
-            $reference = $repo->get_file_reference($source);
-
             // If file is already a reference, set $source = file source, $repo = file repository
             // note that in this case user may not have permission to access the source file directly
             // so no file_browser/file_info can be used below
-- 
1.7.9.5


From f8dea58be9e05b625336e9f498c7dd797ce34586 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 11:08:25 +0800
Subject: [PATCH 524/903] MDL-34290 remove class cache_file as not used

in fact we have moodle filepool that can work perfectly for caching files, no need to create new class and storage
---
 lib/cronlib.php |    4 --
 lib/filelib.php |  167 -------------------------------------------------------
 2 files changed, 171 deletions(-)

diff --git a/lib/cronlib.php b/lib/cronlib.php
index 1e8b1c8..6562052 100644
--- a/lib/cronlib.php
+++ b/lib/cronlib.php
@@ -466,10 +466,6 @@ function cron_run() {
     $fs = get_file_storage();
     $fs->cron();
 
-    mtrace("Clean up cached external files");
-    // 1 week
-    cache_file::cleanup(array(), 60 * 60 * 24 * 7);
-
     mtrace("Cron script completed correctly");
 
     $difftime = microtime_diff($starttime, microtime());
diff --git a/lib/filelib.php b/lib/filelib.php
index f7487c3..df23d91 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -4271,170 +4271,3 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) {
     }
 
 }
-
-/**
- * Universe file cacheing class
- *
- * @package    core_files
- * @category   files
- * @copyright  2012 Dongsheng Cai {@link http://dongsheng.org}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class cache_file {
-    /** @var string */
-    public $cachedir = '';
-
-    /**
-     * static method to create cache_file class instance
-     *
-     * @param array $options caching ooptions
-     */
-    public static function get_instance($options = array()) {
-        return new cache_file($options);
-    }
-
-    /**
-     * Constructor
-     *
-     * @param array $options
-     */
-    private function __construct($options = array()) {
-        global $CFG;
-
-        // Path to file caches.
-        if (isset($options['cachedir'])) {
-            $this->cachedir = $options['cachedir'];
-        } else {
-            $this->cachedir = $CFG->cachedir . '/filedir';
-        }
-
-        // Create cache directory.
-        if (!file_exists($this->cachedir)) {
-            mkdir($this->cachedir, $CFG->directorypermissions, true);
-        }
-
-        // When use cache_file::get, it will check ttl.
-        if (isset($options['ttl']) && is_numeric($options['ttl'])) {
-            $this->ttl = $options['ttl'];
-        } else {
-            // One day.
-            $this->ttl = 60 * 60 * 24;
-        }
-    }
-
-    /**
-     * Get cached file, false if file expires
-     *
-     * @param mixed $param
-     * @param array $options caching options
-     * @return bool|string
-     */
-    public static function get($param, $options = array()) {
-        $instance = self::get_instance($options);
-        $filepath = $instance->generate_filepath($param);
-        if (file_exists($filepath)) {
-            $lasttime = filemtime($filepath);
-            if (time() - $lasttime > $instance->ttl) {
-                // Remove cache file.
-                unlink($filepath);
-                return false;
-            } else {
-                return $filepath;
-            }
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Static method to create cache from a file
-     *
-     * @param mixed $ref
-     * @param string $srcfile
-     * @param array $options
-     * @return string cached file path
-     */
-    public static function create_from_file($ref, $srcfile, $options = array()) {
-        $instance = self::get_instance($options);
-        $cachedfilepath = $instance->generate_filepath($ref);
-        copy($srcfile, $cachedfilepath);
-        return $cachedfilepath;
-    }
-
-    /**
-     * Static method to create cache from url
-     *
-     * @param mixed $ref file reference
-     * @param string $url file url
-     * @param array $options options
-     * @return string cached file path
-     */
-    public static function create_from_url($ref, $url, $options = array()) {
-        $instance = self::get_instance($options);
-        $cachedfilepath = $instance->generate_filepath($ref);
-        $fp = fopen($cachedfilepath, 'w');
-        $curl = new curl;
-        $curl->download(array(array('url'=>$url, 'file'=>$fp)));
-        // Must close file handler.
-        fclose($fp);
-        return $cachedfilepath;
-    }
-
-    /**
-     * Static method to create cache from string
-     *
-     * @param mixed $ref file reference
-     * @param string $url file url
-     * @param array $options options
-     * @return string cached file path
-     */
-    public static function create_from_string($ref, $string, $options = array()) {
-        $instance = self::get_instance($options);
-        $cachedfilepath = $instance->generate_filepath($ref);
-        $fp = fopen($cachedfilepath, 'w');
-        fwrite($fp, $string);
-        // Must close file handler.
-        fclose($fp);
-        return $cachedfilepath;
-    }
-
-    /**
-     * Build path to cache file
-     *
-     * @param mixed $ref
-     * @return string
-     */
-    private function generate_filepath($ref) {
-        global $CFG;
-        $hash = sha1(serialize($ref));
-        $l1 = $hash[0].$hash[1];
-        $l2 = $hash[2].$hash[3];
-        $dir = $this->cachedir . "/$l1/$l2";
-        if (!file_exists($dir)) {
-            mkdir($dir, $CFG->directorypermissions, true);
-        }
-        return "$dir/$hash";
-    }
-
-    /**
-     * Remove cache files
-     *
-     * @param array $options options
-     * @param int $expire The number of seconds before expiry
-     */
-    public static function cleanup($options = array(), $expire) {
-        global $CFG;
-        $instance = self::get_instance($options);
-        if ($dir = opendir($instance->cachedir)) {
-            while (($file = readdir($dir)) !== false) {
-                if (!is_dir($file) && $file != '.' && $file != '..') {
-                    $lasttime = @filemtime($instance->cachedir . $file);
-                    if(time() - $lasttime > $expire){
-                        @unlink($instance->cachedir . $file);
-                    }
-                }
-            }
-            closedir($dir);
-        }
-    }
-}
-- 
1.7.9.5


From a7f53f09f33aed1eed41a68bb4e89a1bfc097372 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 1 Aug 2012 15:01:38 +0800
Subject: [PATCH 525/903] MDL-34665 Dropbox displays thumbnails and return
 info about file size and date last modified

---
 repository/dropbox/lib.php       |   56 ++++++++++++++++++++++++++++++++------
 repository/dropbox/locallib.php  |   26 ++++++++++++++++++
 repository/dropbox/thumbnail.php |   44 ++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+), 8 deletions(-)
 create mode 100644 repository/dropbox/thumbnail.php

diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index 008b566..c0edef3 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -220,28 +220,68 @@ class repository_dropbox extends repository {
             return $list;
         }
         $files = $result->contents;
+        $dirslist = array();
+        $fileslist = array();
         foreach ($files as $file) {
             if ($file->is_dir) {
-                $list['list'][] = array(
+                $dirslist[] = array(
                     'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
                     'path' => file_correct_filepath($file->path),
-                    'size' => $file->size,
-                    'date' => $file->modified,
-                    'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
+                    'date' => strtotime($file->modified),
+                    'thumbnail' => $OUTPUT->pix_url(file_folder_icon(64))->out(false),
+                    'thumbnail_height' => 64,
+                    'thumbnail_width' => 64,
                     'children' => array(),
                 );
             } else {
-                $list['list'][] = array(
+                $thumbnail = null;
+                if ($file->thumb_exists) {
+                    $thumburl = new moodle_url('/repository/dropbox/thumbnail.php',
+                            array('repo_id' => $this->id,
+                                'ctx_id' => $this->context->id,
+                                'source' => $file->path,
+                                'rev' => $file->rev // include revision to avoid cache problems
+                            ));
+                    $thumbnail = $thumburl->out(false);
+                }
+                $fileslist[] = array(
                     'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
                     'source' => $file->path,
-                    'size' => $file->size,
-                    'date' => $file->modified,
-                    'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 90))->out(false)
+                    'size' => $file->bytes,
+                    'date' => strtotime($file->modified),
+                    'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 64))->out(false),
+                    'realthumbnail' => $thumbnail,
+                    'thumbnail_height' => 64,
+                    'thumbnail_width' => 64,
                 );
             }
         }
+        $fileslist = array_filter($fileslist, array($this, 'filter'));
+        $list['list'] = array_merge($dirslist, array_values($fileslist));
         return $list;
     }
+
+    /**
+     * Displays a thumbnail for current user's dropbox file
+     *
+     * @param string $string
+     */
+    public function send_thumbnail($source) {
+        $saveas = $this->prepare_file('');
+        try {
+            $access_key = get_user_preferences($this->setting.'_access_key', '');
+            $access_secret = get_user_preferences($this->setting.'_access_secret', '');
+            $this->dropbox->set_access_token($access_key, $access_secret);
+            $this->dropbox->get_thumbnail($source, $saveas, self::SYNCIMAGE_TIMEOUT);
+            $content = file_get_contents($saveas);
+            unlink($saveas);
+            // set 30 days lifetime for the image. If the image is changed in dropbox it will have
+            // different revision number and URL will be different. It is completely safe
+            // to cache thumbnail in the browser for a long time
+            send_file($content, basename($source), 30*24*60*60, 0, true);
+        } catch (Exception $e) {}
+    }
+
     /**
      * Logout from dropbox
      * @return array
diff --git a/repository/dropbox/locallib.php b/repository/dropbox/locallib.php
index 89c7e73..ea83d36 100644
--- a/repository/dropbox/locallib.php
+++ b/repository/dropbox/locallib.php
@@ -86,6 +86,32 @@ class dropbox extends oauth_helper {
     }
 
     /**
+     * Retrieves the default (64x64) thumbnail for dropbox file
+     *
+     * @throws moodle_exception when file could not be downloaded
+     *
+     * @param string $filepath local path in Dropbox
+     * @param string $saveas path to file to save the result
+     * @param int $timeout request timeout in seconds, 0 means no timeout
+     * @return array with attributes 'path' and 'url'
+     */
+    public function get_thumbnail($filepath, $saveas, $timeout = 0) {
+        $url = $this->dropbox_content_api.'/thumbnails/'.$this->mode.$this->prepare_filepath($filepath);
+        if (!($fp = fopen($saveas, 'w'))) {
+            throw new moodle_exception('cannotwritefile', 'error', '', $saveas);
+        }
+        $this->setup_oauth_http_options(array('timeout' => $timeout, 'file' => $fp, 'BINARYTRANSFER' => true));
+        $result = $this->get($url);
+        fclose($fp);
+        if ($result === true) {
+            return array('path'=>$saveas, 'url'=>$url);
+        } else {
+            unlink($saveas);
+            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
+        }
+    }
+
+    /**
      * Downloads a file from Dropbox and saves it locally
      *
      * @throws moodle_exception when file could not be downloaded
diff --git a/repository/dropbox/thumbnail.php b/repository/dropbox/thumbnail.php
new file mode 100644
index 0000000..6a4887e
--- /dev/null
+++ b/repository/dropbox/thumbnail.php
@@ -0,0 +1,44 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This script displays one thumbnail of the image in current user's dropbox.
+ * If {@link repository_dropbox::send_thumbnail()} can not display image
+ * the default 64x64 filetype icon is returned
+ *
+ * @package    repository_dropbox
+ * @copyright  2012 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once(dirname(__FILE__).'/lib.php');
+
+$repo_id   = optional_param('repo_id', 0, PARAM_INT);           // Repository ID
+$contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID
+$source    = optional_param('source', '', PARAM_TEXT);          // File path in current user's dropbox
+
+if (isloggedin() && $repo_id && $source
+        && ($repo = repository::get_repository_by_id($repo_id, $contextid))
+        && method_exists($repo, 'send_thumbnail')) {
+    // try requesting thumbnail and outputting it. This function exits if thumbnail was retrieved
+    $repo->send_thumbnail($source);
+}
+
+// send default icon for the file type
+$fileicon = file_extension_icon($source, 64);
+send_file($CFG->dirroot.'/pix/'.$fileicon.'.png', basename($fileicon).'.png');
-- 
1.7.9.5


From 29ea4e9c56e47280753502de8bc5620642736672 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 9 Aug 2012 13:50:42 +0800
Subject: [PATCH 526/903] MDL-34290 Auto synchronise newly created references
 when possible

---
 lib/filestorage/file_storage.php |   29 +++++++++++++++++++++++------
 repository/repository_ajax.php   |    9 +++++++--
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index 71c8fc8..b18105b 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -1266,22 +1266,39 @@ class file_storage {
         $transaction = $DB->start_delegated_transaction();
 
         try {
-            $filerecord->referencefileid = $this->get_or_create_referencefileid($repositoryid, $reference,
-                $filerecord->referencelastsync, $filerecord->referencelifetime);
+            $filerecord->referencefileid = $this->get_or_create_referencefileid($repositoryid, $reference);
         } catch (Exception $e) {
             throw new file_reference_exception($repositoryid, $reference, null, null, $e->getMessage());
         }
 
-        // External file doesn't have content in moodle.
-        // So we create an empty file for it.
-        list($filerecord->contenthash, $filerecord->filesize, $newfile) = $this->add_string_to_pool(null);
+        if (isset($filerecord->contenthash) && $this->content_exists($filerecord->contenthash)) {
+            // there was specified the contenthash for a file already stored in moodle filepool
+            if (empty($filerecord->filesize)) {
+                $filepathname = $this->path_from_hash($filerecord->contenthash) . '/' . $filerecord->contenthash;
+                $filerecord->filesize = filesize($filepathname);
+            } else {
+                $filerecord->filesize = clean_param($filerecord->filesize, PARAM_INT);
+            }
+        } else {
+            // atempt to get the result of last synchronisation for this reference
+            $lastcontent = $DB->get_record('files', array('referencefileid' => $filerecord->referencefileid),
+                    'id, contenthash, filesize', IGNORE_MULTIPLE);
+            if ($lastcontent) {
+                $filerecord->contenthash = $lastcontent->contenthash;
+                $filerecord->filesize = $lastcontent->filesize;
+            } else {
+                // External file doesn't have content in moodle.
+                // So we create an empty file for it.
+                list($filerecord->contenthash, $filerecord->filesize, $newfile) = $this->add_string_to_pool(null);
+            }
+        }
 
         $filerecord->pathnamehash = $this->get_pathname_hash($filerecord->contextid, $filerecord->component, $filerecord->filearea, $filerecord->itemid, $filerecord->filepath, $filerecord->filename);
 
         try {
             $filerecord->id = $DB->insert_record('files', $filerecord);
         } catch (dml_exception $e) {
-            if ($newfile) {
+            if (!empty($newfile)) {
                 $this->deleted_file_cleanup($filerecord->contenthash);
             }
             throw new stored_file_creation_exception($filerecord->contextid, $filerecord->component, $filerecord->filearea, $filerecord->itemid,
diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php
index acc2e39..06df8f3 100644
--- a/repository/repository_ajax.php
+++ b/repository/repository_ajax.php
@@ -234,6 +234,8 @@ switch ($action) {
                 if ($file && $file->is_external_file()) {
                     $sourcefield = $file->get_source(); // remember the original source
                     $record->source = $repo::build_source_field($sourcefield);
+                    $record->contenthash = $file->get_contenthash();
+                    $record->filesize = $file->get_filesize();
                     $reference = $file->get_reference();
                     $repo_id = $file->get_repository_id();
                     $repo = repository::get_repository_by_id($repo_id, $contextid, $repooptions);
@@ -241,8 +243,11 @@ switch ($action) {
             }
 
             if ($usefilereference) {
-                // get reference life time from repo
-                $record->referencelifetime = $repo->get_reference_file_lifetime($reference);
+                if ($repo->has_moodle_files()) {
+                    $sourcefile = repository::get_moodle_file($reference);
+                    $record->contenthash = $sourcefile->get_contenthash();
+                    $record->filesize = $sourcefile->get_filesize();
+                }
                 // Check if file exists.
                 if (repository::draftfile_exists($itemid, $saveas_path, $saveas_filename)) {
                     // File name being used, rename it.
-- 
1.7.9.5


From 3dce698981e55489ed07d04dccdc14daf3c55068 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Fri, 10 Aug 2012 12:26:19 +0800
Subject: [PATCH 527/903] MDL-34290, MDL-33416 prepare to deprecate fields
 files.referencelastsync and referencelifetime

---
 lib/filestorage/file_storage.php |   32 +++++++++++++-------------------
 lib/filestorage/stored_file.php  |   16 +++++++++++++---
 2 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index b18105b..ae8df9c 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -976,10 +976,6 @@ class file_storage {
             $filerecord->sortorder = 0;
         }
 
-        $filerecord->referencefileid   = !isset($filerecord->referencefileid) ? 0 : $filerecord->referencefileid;
-        $filerecord->referencelastsync = !isset($filerecord->referencelastsync) ? 0 : $filerecord->referencelastsync;
-        $filerecord->referencelifetime = !isset($filerecord->referencelifetime) ? 0 : $filerecord->referencelifetime;
-
         $filerecord->filepath = clean_param($filerecord->filepath, PARAM_PATH);
         if (strpos($filerecord->filepath, '/') !== 0 or strrpos($filerecord->filepath, '/') !== strlen($filerecord->filepath)-1) {
             // path must start and end with '/'
@@ -1094,9 +1090,6 @@ class file_storage {
         } else {
             $filerecord->sortorder = 0;
         }
-        $filerecord->referencefileid   = !isset($filerecord->referencefileid) ? 0 : $filerecord->referencefileid;
-        $filerecord->referencelastsync = !isset($filerecord->referencelastsync) ? 0 : $filerecord->referencelastsync;
-        $filerecord->referencelifetime = !isset($filerecord->referencelifetime) ? 0 : $filerecord->referencelifetime;
 
         $filerecord->filepath = clean_param($filerecord->filepath, PARAM_PATH);
         if (strpos($filerecord->filepath, '/') !== 0 or strrpos($filerecord->filepath, '/') !== strlen($filerecord->filepath)-1) {
@@ -1217,9 +1210,10 @@ class file_storage {
             $filerecord->sortorder = 0;
         }
 
-        $filerecord->referencefileid   = empty($filerecord->referencefileid) ? 0 : $filerecord->referencefileid;
-        $filerecord->referencelastsync = empty($filerecord->referencelastsync) ? 0 : $filerecord->referencelastsync;
-        $filerecord->referencelifetime = empty($filerecord->referencelifetime) ? 0 : $filerecord->referencelifetime;
+        // TODO MDL-33416 [2.4] fields referencelastsync and referencelifetime to be removed from {files} table completely
+        unset($filerecord->referencelastsync);
+        unset($filerecord->referencelifetime);
+
         $filerecord->mimetype          = empty($filerecord->mimetype) ? $this->mimetype($filerecord->filename) : $filerecord->mimetype;
         $filerecord->userid            = empty($filerecord->userid) ? null : $filerecord->userid;
         $filerecord->source            = empty($filerecord->source) ? null : $filerecord->source;
@@ -1309,10 +1303,8 @@ class file_storage {
 
         $transaction->allow_commit();
 
-        // Adding repositoryid and reference to file record to create stored_file instance
-        $filerecord->repositoryid = $repositoryid;
-        $filerecord->reference = $reference;
-        return $this->get_file_instance($filerecord);
+        // this will retrieve all reference information from DB as well
+        return $this->get_file_by_id($filerecord->id);
     }
 
     /**
@@ -1973,10 +1965,12 @@ class file_storage {
         // else problems like MDL-33172 occur.
         $filefields = array('contenthash', 'pathnamehash', 'contextid', 'component', 'filearea',
             'itemid', 'filepath', 'filename', 'userid', 'filesize', 'mimetype', 'status', 'source',
-            'author', 'license', 'timecreated', 'timemodified', 'sortorder', 'referencefileid',
-            'referencelastsync', 'referencelifetime');
+            'author', 'license', 'timecreated', 'timemodified', 'sortorder', 'referencefileid');
 
-        $referencefields = array('repositoryid', 'reference');
+        $referencefields = array('repositoryid' => 'repositoryid',
+            'reference' => 'reference',
+            'lastsync' => 'referencelastsync',
+            'lifetime' => 'referencelifetime');
 
         // id is specifically named to prevent overlaping between the two tables.
         $fields = array();
@@ -1985,8 +1979,8 @@ class file_storage {
             $fields[] = "{$filesprefix}.{$field}";
         }
 
-        foreach ($referencefields as $field) {
-            $fields[] = "{$filesreferenceprefix}.{$field}";
+        foreach ($referencefields as $field => $alias) {
+            $fields[] = "{$filesreferenceprefix}.{$field} AS {$alias}";
         }
 
         return implode(', ', $fields);
diff --git a/lib/filestorage/stored_file.php b/lib/filestorage/stored_file.php
index ea8a8cd..fee7bfa 100644
--- a/lib/filestorage/stored_file.php
+++ b/lib/filestorage/stored_file.php
@@ -70,6 +70,12 @@ class stored_file {
         } else {
             $this->repository = null;
         }
+        // make sure all reference fields exist in file_record even when it is not a reference
+        foreach (array('referencelastsync', 'referencelifetime', 'referencefileid', 'reference', 'repositoryid') as $key) {
+            if (empty($this->file_record->$key)) {
+                $this->file_record->$key = null;
+            }
+        }
     }
 
     /**
@@ -142,12 +148,18 @@ class stored_file {
                     }
                 }
 
-                if ($field === 'referencefileid' or $field === 'referencelastsync' or $field === 'referencelifetime') {
+                if ($field === 'referencefileid') {
                     if (!is_null($value) and !is_number($value)) {
                         throw new file_exception('storedfileproblem', 'Invalid reference info');
                     }
                 }
 
+                if ($field === 'referencelastsync' or $field === 'referencelifetime') {
+                    // do not update those fields
+                    // TODO MDL-33416 [2.4] fields referencelastsync and referencelifetime to be removed from {files} table completely
+                    continue;
+                }
+
                 // adding the field
                 $this->file_record->$field = $value;
             } else {
@@ -226,8 +238,6 @@ class stored_file {
         // Update the underlying record in the database.
         $update = new stdClass();
         $update->referencefileid = null;
-        $update->referencelastsync = null;
-        $update->referencelifetime = null;
         $this->update($update);
 
         $transaction->allow_commit();
-- 
1.7.9.5


From 0707372b0332634478578083a2721d827693f82c Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 31 Jul 2012 11:09:35 +0800
Subject: [PATCH 528/903] MDL-34290 Added timeout to googledocs request to
 download a file

---
 lib/googleapi.php             |   17 +++++++++++++----
 repository/googledocs/lib.php |    2 +-
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/lib/googleapi.php b/lib/googleapi.php
index fe2b933..c2d529f 100644
--- a/lib/googleapi.php
+++ b/lib/googleapi.php
@@ -185,12 +185,21 @@ class google_docs {
      *
      * @param string $url url of file
      * @param string $path path to save file to
+     * @param int $timeout request timeout, default 0 which means no timeout
      * @return array stucture for repository download_file
      */
-    public function download_file($url, $path) {
-        $content = $this->googleoauth->get($url);
-        file_put_contents($path, $content);
-        return array('path'=>$path, 'url'=>$url);
+    public function download_file($url, $path, $timeout = 0) {
+        $result = $this->googleoauth->download_one($url, null, array('filepath' => $path, 'timeout' => $timeout));
+        if ($result === true) {
+            $info = $this->googleoauth->get_info();
+            if (isset($info['http_code']) && $info['http_code'] == 200) {
+                return array('path'=>$path, 'url'=>$url);
+            } else {
+                throw new moodle_exception('cannotdownload', 'repository');
+            }
+        } else {
+            throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
+        }
     }
 }
 
diff --git a/repository/googledocs/lib.php b/repository/googledocs/lib.php
index c3a00e1..38299de 100644
--- a/repository/googledocs/lib.php
+++ b/repository/googledocs/lib.php
@@ -95,7 +95,7 @@ class repository_googledocs extends repository {
         $gdocs = new google_docs($this->googleoauth);
 
         $path = $this->prepare_file($file);
-        return $gdocs->download_file($url, $path);
+        return $gdocs->download_file($url, $path, self::GETFILE_TIMEOUT);
     }
 
     public function supported_filetypes() {
-- 
1.7.9.5


From 7fa4cd1617d9c367a64f450d4fdbd751e0e73967 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 14 Aug 2012 10:49:20 +0800
Subject: [PATCH 529/903] MDL-34290 using moodleform cast to int in dropbox
 repository settings

---
 repository/dropbox/lang/en/repository_dropbox.php |    1 -
 repository/dropbox/lib.php                        |   18 ++----------------
 2 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/repository/dropbox/lang/en/repository_dropbox.php b/repository/dropbox/lang/en/repository_dropbox.php
index 4937c13..abf16c1 100644
--- a/repository/dropbox/lang/en/repository_dropbox.php
+++ b/repository/dropbox/lang/en/repository_dropbox.php
@@ -32,5 +32,4 @@ $string['secret'] = 'Dropbox secret';
 $string['instruction'] = 'You can get your API Key and secret from <a href="http://www.dropbox.com/developers/apps">Dropbox developers</a>. When setting up your key please select "Full Dropbox" as the "Access level".';
 $string['cachelimit'] = 'Cache limit';
 $string['cachelimit_info'] = 'Enter the maximum size of files (in bytes) to be cached on server for Dropbox aliases/shortcuts. Cached files will be served when the source is no longer available. Empty value or zero mean caching of all files regardless of size.';
-$string['error_cachelimit'] = 'Must be a positive integer or empty value';
 $string['dropbox:view'] = 'View a Dropbox folder';
diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index c0edef3..a0af82f 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -464,26 +464,12 @@ class repository_dropbox extends repository {
         $mform->addElement('static', null, '',  $str_getkey);
 
         $mform->addElement('text', 'dropbox_cachelimit', get_string('cachelimit', 'repository_dropbox'), array('size' => '40'));
+        $mform->addRule('dropbox_cachelimit', null, 'numeric', null, 'client');
+        $mform->setType('dropbox_cachelimit', PARAM_INT);
         $mform->addElement('static', 'dropbox_cachelimit_info', '',  get_string('cachelimit_info', 'repository_dropbox'));
     }
 
     /**
-     * Validate Admin Settings Moodle form
-     *
-     * @param moodleform $mform Moodle form (passed by reference)
-     * @param array $data array of ("fieldname"=>value) of submitted data
-     * @param array $errors array of ("fieldname"=>errormessage) of errors
-     * @return array array of errors
-     */
-    public static function type_form_validation($mform, $data, $errors) {
-        if (!empty($data['dropbox_cachelimit']) && (!is_number($data['dropbox_cachelimit']) ||
-                (int)$data['dropbox_cachelimit']<0)) {
-            $errors['dropbox_cachelimit'] = get_string('error_cachelimit', 'repository_dropbox');
-        }
-        return $errors;
-    }
-
-    /**
      * Option names of dropbox plugin
      *
      * @return array
-- 
1.7.9.5


From 074455a6f596c9d03c1e0f10df7715046329f59e Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 28 Aug 2012 12:03:43 +0800
Subject: [PATCH 530/903] MDL-34290 repository_filesystem: do not store files
 in moodle filepool unless images

---
 repository/filesystem/lib.php |   19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/repository/filesystem/lib.php b/repository/filesystem/lib.php
index fc7cd9e..432e79d 100644
--- a/repository/filesystem/lib.php
+++ b/repository/filesystem/lib.php
@@ -273,17 +273,13 @@ class repository_filesystem extends repository {
 
     /**
      * Returns information about file in this repository by reference
-     * {@link repository::get_file_reference()}
-     * {@link repository::get_file()}
      *
      * Returns null if file not found or is not readable
      *
      * @param stdClass $reference file reference db record
      * @return stdClass|null contains one of the following:
-     *   - 'contenthash' and 'filesize'
-     *   - 'filepath'
-     *   - 'handle'
-     *   - 'content'
+     *   - 'filesize' if file should not be copied to moodle filepool
+     *   - 'filepath' if file should be copied to moodle filepool
      */
     public function get_file_by_reference($reference) {
         $ref = $reference->reference;
@@ -293,7 +289,16 @@ class repository_filesystem extends repository {
             $filepath = $this->root_path.$ref;
         }
         if (file_exists($filepath) && is_readable($filepath)) {
-            return (object)array('filepath' => $filepath);
+            if (file_extension_in_typegroup($filepath, 'web_image')) {
+                // return path to image files so it will be copied into moodle filepool
+                // we need the file in filepool to generate an image thumbnail
+                return (object)array('filepath' => $filepath);
+            } else {
+                // return just the file size so file will NOT be copied into moodle filepool
+                return (object)array(
+                    'filesize' => filesize($filepath)
+                );
+            }
         } else {
             return null;
         }
-- 
1.7.9.5


From 160133ce2411babe26fff535f64677061a0f67b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Wed, 29 Aug 2012 15:33:22 +0200
Subject: [PATCH 531/903] MDL-34725 Make the signatures of
 process_legacy_element() method consistent

The patch fixes the missing parameter type declaration in all subclasses
of the moodle1_workshopform_handler class.
---
 mod/workshop/form/comments/backup/moodle1/lib.php  |    7 ++++++-
 mod/workshop/form/numerrors/backup/moodle1/lib.php |    5 ++++-
 mod/workshop/form/rubric/backup/moodle1/lib.php    |    5 ++++-
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/mod/workshop/form/comments/backup/moodle1/lib.php b/mod/workshop/form/comments/backup/moodle1/lib.php
index 5d557a4..2e9a0c0 100644
--- a/mod/workshop/form/comments/backup/moodle1/lib.php
+++ b/mod/workshop/form/comments/backup/moodle1/lib.php
@@ -32,8 +32,13 @@ class moodle1_workshopform_comments_handler extends moodle1_workshopform_handler
 
     /**
      * Converts <ELEMENT> into <workshopform_comments_dimension>
+     *
+     * @param array $data legacy element data
+     * @param array $raw raw element data
+     *
+     * @return array converted
      */
-    public function process_legacy_element($data, $raw) {
+    public function process_legacy_element(array $data, array $raw) {
         // prepare a fake record and re-use the upgrade logic
         $fakerecord = (object)$data;
         $converted = (array)workshopform_comments_upgrade_element($fakerecord, 12345678);
diff --git a/mod/workshop/form/numerrors/backup/moodle1/lib.php b/mod/workshop/form/numerrors/backup/moodle1/lib.php
index d2c6310..e18a2f2 100644
--- a/mod/workshop/form/numerrors/backup/moodle1/lib.php
+++ b/mod/workshop/form/numerrors/backup/moodle1/lib.php
@@ -49,9 +49,12 @@ class moodle1_workshopform_numerrors_handler extends moodle1_workshopform_handle
     /**
      * Converts <ELEMENT> into <workshopform_numerrors_dimension> and stores it for later writing
      *
+     * @param array $data legacy element data
+     * @param array $raw raw element data
+     *
      * @return array to be written to workshop.xml
      */
-    public function process_legacy_element($data, $raw) {
+    public function process_legacy_element(array $data, array $raw) {
 
         $workshop = $this->parenthandler->get_current_workshop();
 
diff --git a/mod/workshop/form/rubric/backup/moodle1/lib.php b/mod/workshop/form/rubric/backup/moodle1/lib.php
index be0a6c6..fe604f8 100644
--- a/mod/workshop/form/rubric/backup/moodle1/lib.php
+++ b/mod/workshop/form/rubric/backup/moodle1/lib.php
@@ -46,8 +46,11 @@ class moodle1_workshopform_rubric_handler extends moodle1_workshopform_handler {
 
     /**
      * Processes one <ELEMENT>
+     *
+     * @param array $data legacy element data
+     * @param array $raw raw element data
      */
-    public function process_legacy_element($data, $raw) {
+    public function process_legacy_element(array $data, array $raw) {
         $this->elements[] = $data;
         $this->rubrics[$data['id']] = array();
     }
-- 
1.7.9.5


From 3b5245cd6b32534e8a5ebd355a70f3f0492a376d Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 29 Aug 2012 17:42:53 +0100
Subject: [PATCH 532/903] MDL-33306 qtype multichoice: fix display of right
 answer.

Also, fix  higlighing of last edited question in the qeustion bank, when
it co-incides with a grey row.
---
 mod/quiz/styles.css                  |    1 +
 question/type/multichoice/styles.css |    3 +++
 2 files changed, 4 insertions(+)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 6361024..d07442b 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -178,6 +178,7 @@ table.quizreviewsummary td.cell {padding: 1px 1em 1px 0.5em;text-align: left;bac
 #page-mod-quiz-edit h2.main{display:inline;padding-right:1em;clear:left;}
 
 #categoryquestions .r1 {background: #e4e4e4;}
+#categoryquestions .r1.highlight {background-color:#AAFFAA;}
 #categoryquestions .header {text-align: center;padding: 0 2px;border: 0 none;}
 #categoryquestions th.modifiername .sorters,
 #categoryquestions th.creatorname .sorters {font-weight: normal;font-size: 0.8em;}
diff --git a/question/type/multichoice/styles.css b/question/type/multichoice/styles.css
index 3cadf62..4aa77fd 100644
--- a/question/type/multichoice/styles.css
+++ b/question/type/multichoice/styles.css
@@ -10,3 +10,6 @@
 .que.multichoice .answer div.r1 {
     padding: 0.3em;
 }
+.que.multichoice .feedback .rightanswer * {
+    display: inline;
+}
-- 
1.7.9.5


From c8f9a0b63a9c21039270bc3e2e752c2aa040ccce Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 29 Aug 2012 18:41:37 +0100
Subject: [PATCH 533/903] MDL-29662 quiz overrides: update dates during course
 reset.

Also, fix duplicate SQL clause in similar code in lib,
and fix error when saving overrides.
---
 lib/moodlelib.php |    2 +-
 mod/quiz/lib.php  |   18 +++++++++++++++++-
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 55cf4e8..01f1788 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -4767,7 +4767,7 @@ function shift_course_mod_dates($modname, $fields, $timeshift, $courseid) {
     foreach ($fields as $field) {
         $updatesql = "UPDATE {".$modname."}
                           SET $field = $field + ?
-                        WHERE course=? AND $field<>0 AND $field<>0";
+                        WHERE course=? AND $field<>0";
         $return = $DB->execute($updatesql, array($timeshift, $courseid)) && $return;
     }
 
diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 993ca98..4bb7494 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1150,8 +1150,14 @@ function quiz_update_events($quiz, $override = null) {
         $addopen  = empty($current->id) || !empty($current->timeopen);
         $addclose = empty($current->id) || !empty($current->timeclose);
 
+        if (!empty($quiz->coursemodule)) {
+            $cmid = $quiz->coursemodule;
+        } else {
+            $cmid = get_coursemodule_from_instance('quiz', $quiz->id, $courseid)->id;
+        }
+
         $event = new stdClass();
-        $event->description = format_module_intro('quiz', $quiz, $quiz->coursemodule);
+        $event->description = format_module_intro('quiz', $quiz, $cmid);
         // Events module won't show user events when the courseid is nonzero.
         $event->courseid    = ($userid) ? 0 : $quiz->course;
         $event->groupid     = $groupid;
@@ -1341,8 +1347,18 @@ function quiz_reset_userdata($data) {
 
     // Updating dates - shift may be negative too.
     if ($data->timeshift) {
+        $DB->execute("UPDATE {quiz_overrides}
+                         SET timeopen = timeopen + ?
+                       WHERE quiz IN (SELECT id FROM {quiz} WHERE course = ?)
+                         AND timeopen <> 0", array($data->timeshift, $data->courseid));
+        $DB->execute("UPDATE {quiz_overrides}
+                         SET timeclose = timeclose + ?
+                       WHERE quiz IN (SELECT id FROM {quiz} WHERE course = ?)
+                         AND timeclose <> 0", array($data->timeshift, $data->courseid));
+
         shift_course_mod_dates('quiz', array('timeopen', 'timeclose'),
                 $data->timeshift, $data->courseid);
+
         $status[] = array(
             'component' => $componentstr,
             'item' => get_string('openclosedatesupdated', 'quiz'),
-- 
1.7.9.5


From 130dd4213018e5553f6e166e8483ec6dc99615a2 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Thu, 30 Aug 2012 11:20:53 +1200
Subject: [PATCH 534/903] MDL-35134: course/format/weeks: remove trailing
 comma in object definition

IE doesn't like trailing commas in object (or array) definitions, and will cease processing JavaScript when it hits one.
---
 course/format/weeks/format.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/format/weeks/format.js b/course/format/weeks/format.js
index f410e07..28ec82a 100644
--- a/course/format/weeks/format.js
+++ b/course/format/weeks/format.js
@@ -36,7 +36,7 @@ M.course.format.get_config = function() {
 M.course.format.swap_sections = function(Y, node1, node2) {
     var CSS = {
         COURSECONTENT : 'course-content',
-        SECTIONADDMENUS : 'section_add_menus',
+        SECTIONADDMENUS : 'section_add_menus'
     };
 
     var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y));
-- 
1.7.9.5


From edd2686c8bc5d6e0c8be65241fc8a6ec082e57ba Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Tue, 14 Aug 2012 15:09:02 +0800
Subject: [PATCH 535/903] MDL-32108 - navigation - After logging in the user
 is directed to mysite instead of site home. Thanks
 to lurii Kucherov for this patch.

---
 login/index.php |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/login/index.php b/login/index.php
index 3f398a4..1847544 100644
--- a/login/index.php
+++ b/login/index.php
@@ -204,16 +204,16 @@ if ($frm and isset($frm->username)) {                             // Login WITH
             // no wantsurl stored or external - go to homepage
             $urltogo = $CFG->wwwroot.'/';
             unset($SESSION->wantsurl);
-        }
 
-    /// Go to my-moodle page instead of site homepage if defaulthomepage set to homepage_my
-        if (!empty($CFG->defaulthomepage) && $CFG->defaulthomepage == HOMEPAGE_MY && !is_siteadmin() && !isguestuser()) {
-            if ($urltogo == $CFG->wwwroot or $urltogo == $CFG->wwwroot.'/' or $urltogo == $CFG->wwwroot.'/index.php') {
-                $urltogo = $CFG->wwwroot.'/my/';
+            $home_page = get_home_page();
+            // Go to my-moodle page instead of site homepage if defaulthomepage set to homepage_my
+            if ($home_page == HOMEPAGE_MY && !is_siteadmin() && !isguestuser()) {
+                if ($urltogo == $CFG->wwwroot or $urltogo == $CFG->wwwroot.'/' or $urltogo == $CFG->wwwroot.'/index.php') {
+                    $urltogo = $CFG->wwwroot.'/my/';
+                }
             }
         }
 
-
     /// check if user password has expired
     /// Currently supported only for ldap-authentication module
         $userauth = get_auth_plugin($USER->auth);
-- 
1.7.9.5


From 21415acd5ae658db402d8457f6a18fcc3e119b1d Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Wed, 29 Aug 2012 15:01:40 +0800
Subject: [PATCH 536/903] MDL-35119 tool_assignmentupgrade Changing onsubmit
 form for onclick button

---
 admin/tool/assignmentupgrade/module.js |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/admin/tool/assignmentupgrade/module.js b/admin/tool/assignmentupgrade/module.js
index edee839..59df8c5 100644
--- a/admin/tool/assignmentupgrade/module.js
+++ b/admin/tool/assignmentupgrade/module.js
@@ -42,8 +42,8 @@ M.tool_assignmentupgrade = {
             }
         });
 
-        var batchform = Y.one('.tool_assignmentupgrade_batchform form');
-        batchform.on('submit', function(e) {
+        var upgradeselectedbutton = Y.one('#id_upgradeselected');
+        upgradeselectedbutton.on('click', function(e) {
             checkboxes = Y.all('td.c0 input');
             var selectedassignments = [];
             checkboxes.each(function(node) {
-- 
1.7.9.5


From 74c0b550298b7514c47e82edd6ca1d19cce87827 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 27 Aug 2012 14:23:17 +0800
Subject: [PATCH 537/903] MDL-26882 profile: Apllying the cap check
 site:viewuseridentity to user profile

---
 user/profile.php |   34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/user/profile.php b/user/profile.php
index 9dafdd9..30ca66f 100644
--- a/user/profile.php
+++ b/user/profile.php
@@ -118,6 +118,12 @@ if (has_capability('moodle/user:viewhiddendetails', $context)) {
     $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
 }
 
+if (has_capability('moodle/site:viewuseridentity', $context)) {
+    $identityfields = array_flip(explode(',', $CFG->showuseridentity));
+} else {
+    $identityfields = array();
+}
+
 // Start setting up the page
 $strpublicprofile = get_string('publicprofile');
 
@@ -247,16 +253,28 @@ if (! isset($hiddenfields['city']) && $user->city) {
     print_row(get_string('city') . ':', $user->city);
 }
 
-if (has_capability('moodle/user:viewhiddendetails', $context)) {
-    if ($user->address) {
-        print_row(get_string("address").":", "$user->address");
-    }
-    if ($user->phone1) {
+if (isset($identityfields['address']) && $user->address) {
+    print_row(get_string("address").":", "$user->address");
+}
+
+if (isset($identityfields['phone1']) && $user->phone1) {
         print_row(get_string("phone").":", "$user->phone1");
-    }
-    if ($user->phone2) {
+}
+
+if (isset($identityfields['phone2']) && $user->phone2) {
         print_row(get_string("phone2").":", "$user->phone2");
-    }
+}
+
+if (isset($identityfields['institution']) && $user->institution) {
+    print_row(get_string("institution").":", "$user->institution");
+}
+
+if (isset($identityfields['department']) && $user->department) {
+    print_row(get_string("department").":", "$user->department");
+}
+
+if (isset($identityfields['idnumber']) && $user->idnumber) {
+    print_row(get_string("idnumber").":", "$user->idnumber");
 }
 
 if ($currentuser
-- 
1.7.9.5


From 4d7a664ee73f6ea72dd9795f6926b1d5c69de1d5 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 27 Aug 2012 14:38:57 +0800
Subject: [PATCH 538/903] MDL-26882 profile: Applying cap check
 (site:viewuseridentity) to email field in user
 profile

---
 user/profile.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/user/profile.php b/user/profile.php
index 30ca66f..188f8c6 100644
--- a/user/profile.php
+++ b/user/profile.php
@@ -277,10 +277,11 @@ if (isset($identityfields['idnumber']) && $user->idnumber) {
     print_row(get_string("idnumber").":", "$user->idnumber");
 }
 
-if ($currentuser
+if (($currentuser
   or $user->maildisplay == 1
   or has_capability('moodle/course:useremail', $context)
-  or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER))) {
+  or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))
+  and isset($identityfields['email'])) {
 
     print_row(get_string("email").":", obfuscate_mailto($user->email, ''));
 }
-- 
1.7.9.5


From d6d63941d7e5f2ebcf9e8714a692884d52badac3 Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Thu, 30 Aug 2012 12:13:56 +0100
Subject: [PATCH 539/903] MDL-35141 Filelib: No icon for epub filetype

---
 lang/en/mimetypes.php |    1 +
 lib/filelib.php       |   13 +++++++++----
 pix/f/epub.png        |  Bin 0 -> 640 bytes
 3 files changed, 10 insertions(+), 4 deletions(-)
 create mode 100644 pix/f/epub.png

diff --git a/lang/en/mimetypes.php b/lang/en/mimetypes.php
index 9cb966d..64624fb 100644
--- a/lang/en/mimetypes.php
+++ b/lang/en/mimetypes.php
@@ -46,6 +46,7 @@ $string['application/vnd.openxmlformats-officedocument.presentationml.slideshow'
 $string['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] = 'Excel spreadsheet';
 $string['application/vnd.openxmlformats-officedocument.spreadsheetml.template'] = 'Excel template';
 $string['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] = 'Word document';
+$string['application/epub_zip'] = 'EPUB ebook';
 $string['archive'] = 'Archive ({$a->EXT})';
 $string['audio'] = 'Audio file ({$a->EXT})';
 $string['default'] = '{$a->mimetype}';
diff --git a/lib/filelib.php b/lib/filelib.php
index 4f60f3c..935354e 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -1406,6 +1406,7 @@ function &get_mimetypes_array() {
         'dir'  => array ('type'=>'application/x-director', 'icon'=>'flash'),
         'dxr'  => array ('type'=>'application/x-director', 'icon'=>'flash'),
         'eps'  => array ('type'=>'application/postscript', 'icon'=>'eps'),
+        'epub' => array ('type'=>'application/epub+zip', 'icon'=>'epub', 'groups'=>array('document')),
         'fdf'  => array ('type'=>'application/pdf', 'icon'=>'pdf'),
         'flv'  => array ('type'=>'video/x-flv', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
         'f4v'  => array ('type'=>'video/mp4', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
@@ -1819,10 +1820,14 @@ function get_mimetype_description($obj, $capitalise=false) {
         $a[strtoupper($key)] = strtoupper($value);
         $a[ucfirst($key)] = ucfirst($value);
     }
-    if (get_string_manager()->string_exists($mimetype, 'mimetypes')) {
-        $result = get_string($mimetype, 'mimetypes', (object)$a);
-    } else if (get_string_manager()->string_exists($mimetypestr, 'mimetypes')) {
-        $result = get_string($mimetypestr, 'mimetypes', (object)$a);
+
+    // MIME types may include + symbol but this is not permitted in string ids.
+    $safemimetype = str_replace('+', '_', $mimetype);
+    $safemimetypestr = str_replace('+', '_', $mimetypestr);
+    if (get_string_manager()->string_exists($safemimetype, 'mimetypes')) {
+        $result = get_string($safemimetype, 'mimetypes', (object)$a);
+    } else if (get_string_manager()->string_exists($safemimetypestr, 'mimetypes')) {
+        $result = get_string($safemimetypestr, 'mimetypes', (object)$a);
     } else if (get_string_manager()->string_exists('default', 'mimetypes')) {
         $result = get_string('default', 'mimetypes', (object)$a);
     } else {
diff --git a/pix/f/epub.png b/pix/f/epub.png
new file mode 100644
index 0000000000000000000000000000000000000000..a660c7311b9a08c4addae50562155d4921f7b029
GIT binary patch
literal 640
zcmV-`0)PF9P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru+z1{DIx5;5kKh0R03B&m
zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00HDlL_t(I%YBnEXw_g8
zg}+nUMFc7J&s!7`l;Y&l%|VLA#L3y>R1g(6*94a)9Tl8J+DXK29Xgnx*iD5xbg+Yy
zh#)kvjxG+zA$iZdSM}e1xQFlDbMJ-!yu1ugiz@n2RMExmugRLJ{->y-zIa{IE!(r;
zcX<`&v!rpq20;HHZ%A6f1_|3p`~+P}<9aVIgR-RY$iW18L(+<E46kk9lmu|h@HQ{Q
zg}xL0jcglWN8(BvH_ppwS@LrOLceU!XG!xpe|hpx1{31<(24;hU$;RB<1OGDKz8jr
z)4jk}x?Xqs;=BrP42zw3GmD!W07V&21GCD@@I=z>j{GW1nyYOt;W%i^cu5G`n_1F|
z^D@jx`eYbPOIqy67`BHk8O~vrI`WGwX_i}ZbOP7~&I*_^EJ-?OJJjQ%itYkrakD3J
z+4$K|oL6B6*hQT0Aca~>(H!!=&;ShRej3-0#+GbI?!>@@G_F^tiYg*Y>O;W-=AfJG
z!@P{{j3#uHyq3oGYEeb%90anYAuq!mqIJ@4;XPp8_@mGmdANY;-$5GJ6jeBd^#L(x
zY5pSX3~k73SzM<@6^-_LauY{RB<+I-?n*R4PUHIMHD*aen@MvBUI2Z?Mz|RET$Ew#
a@O}dpw*EQmo5_O!0000<MNUMnLSTZy5E*R%

literal 0
HcmV?d00001

-- 
1.7.9.5


From 5fe6d4124558772a9c8f79b75c43182d78c70352 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 30 Aug 2012 13:09:10 +0100
Subject: [PATCH 540/903] MDL-35147 lesson: fix regression from MDL-25492.

I really wish someone would fix lesson to use the question bank.
---
 mod/lesson/format.php |   87 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/mod/lesson/format.php b/mod/lesson/format.php
index 574bee1..4d8faf1 100644
--- a/mod/lesson/format.php
+++ b/mod/lesson/format.php
@@ -580,6 +580,93 @@ class qformat_default {
         return html_to_text(format_text($question->questiontext,
                 $question->questiontextformat, $formatoptions), 0, false);
     }
+
+    /**
+     * Since the lesson module tries to re-use the question bank import classes in
+     * a crazy way, this is necessary to stop things breaking.
+     */
+    protected function add_blank_combined_feedback($question) {
+        return $question;
+    }
 }
 
 
+/**
+ * Since the lesson module tries to re-use the question bank import classes in
+ * a crazy way, this is necessary to stop things breaking. This should be exactly
+ * the same as the class defined in question/format.php.
+ */
+class qformat_based_on_xml extends qformat_default {
+    /**
+     * A lot of imported files contain unwanted entities.
+     * This method tries to clean up all known problems.
+     * @param string str string to correct
+     * @return string the corrected string
+     */
+    public function cleaninput($str) {
+
+        $html_code_list = array(
+            "&#039;" => "'",
+            "&#8217;" => "'",
+            "&#8220;" => "\"",
+            "&#8221;" => "\"",
+            "&#8211;" => "-",
+            "&#8212;" => "-",
+        );
+        $str = strtr($str, $html_code_list);
+        // Use textlib entities_to_utf8 function to convert only numerical entities.
+        $str = textlib::entities_to_utf8($str, false);
+        return $str;
+    }
+
+    /**
+     * Return the array moodle is expecting
+     * for an HTML text. No processing is done on $text.
+     * qformat classes that want to process $text
+     * for instance to import external images files
+     * and recode urls in $text must overwrite this method.
+     * @param array $text some HTML text string
+     * @return array with keys text, format and files.
+     */
+    public function text_field($text) {
+        return array(
+            'text' => trim($text),
+            'format' => FORMAT_HTML,
+            'files' => array(),
+        );
+    }
+
+    /**
+     * Return the value of a node, given a path to the node
+     * if it doesn't exist return the default value.
+     * @param array xml data to read
+     * @param array path path to node expressed as array
+     * @param mixed default
+     * @param bool istext process as text
+     * @param string error if set value must exist, return false and issue message if not
+     * @return mixed value
+     */
+    public function getpath($xml, $path, $default, $istext=false, $error='') {
+        foreach ($path as $index) {
+            if (!isset($xml[$index])) {
+                if (!empty($error)) {
+                    $this->error($error);
+                    return false;
+                } else {
+                    return $default;
+                }
+            }
+
+            $xml = $xml[$index];
+        }
+
+        if ($istext) {
+            if (!is_string($xml)) {
+                $this->error(get_string('invalidxml', 'qformat_xml'));
+            }
+            $xml = trim($xml);
+        }
+
+        return $xml;
+    }
+}
-- 
1.7.9.5


From fd126f94aaee95a1d3ab8c14c0440769bba513e7 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 29 Aug 2012 22:25:28 +0100
Subject: [PATCH 541/903] MDL-35133 accesslib:
 context_module::get_context_name should
 format_string

Otherwise activites with multilang names are displayed badly.
---
 lib/accesslib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/accesslib.php b/lib/accesslib.php
index c62dae4..50a9ee4 100644
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -6537,7 +6537,7 @@ class context_module extends context {
                     if ($withprefix){
                         $name = get_string('modulename', $cm->modname).': ';
                     }
-                    $name .= $mod->name;
+                    $name .= format_string($mod->name, true, array('context' => $this));
                 }
             }
         return $name;
-- 
1.7.9.5


From 5d22b222747f7037b3a4ebb3b21a2286756e05e0 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 29 Aug 2012 22:43:28 +0100
Subject: [PATCH 542/903] MDL-27818 question bank: multilang category names
 don't work.

---
 lib/questionlib.php         |   12 +++++++-----
 question/category_class.php |    7 +++++--
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index a5f8822..c8aeacd 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -1117,16 +1117,18 @@ function question_category_options($contexts, $top = false, $currentcat = 0,
 
     // sort cats out into different contexts
     $categoriesarray = array();
-    foreach ($pcontexts as $pcontext) {
-        $contextstring = print_context_name(
-                get_context_instance_by_id($pcontext), true, true);
+    foreach ($pcontexts as $contextid) {
+        $context = context::instance_by_id($contextid);
+        $contextstring = $context->get_context_name(true, true);
         foreach ($categories as $category) {
-            if ($category->contextid == $pcontext) {
+            if ($category->contextid == $contextid) {
                 $cid = $category->id;
                 if ($currentcat != $cid || $currentcat == 0) {
                     $countstring = !empty($category->questioncount) ?
                             " ($category->questioncount)" : '';
-                    $categoriesarray[$contextstring][$cid] = $category->indentedname.$countstring;
+                    $categoriesarray[$contextstring][$cid] =
+                            format_string($category->indentedname, true,
+                                array('context' => $context)) . $countstring;
                 }
             }
         }
diff --git a/question/category_class.php b/question/category_class.php
index fd65dba..8103e96 100644
--- a/question/category_class.php
+++ b/question/category_class.php
@@ -102,9 +102,12 @@ class question_category_list_item extends list_item {
         /// Each section adds html to be displayed as part of this list item
         $questionbankurl = new moodle_url("/question/edit.php", ($this->parentlist->pageurl->params() + array('category'=>"$category->id,$category->contextid")));
         $catediturl = $this->parentlist->pageurl->out(true, array('edit' => $this->id));
-        $item = "<b><a title=\"{$str->edit}\" href=\"$catediturl\">".$category->name ."</a></b> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>';
+        $item = "<b><a title=\"{$str->edit}\" href=\"$catediturl\">" .
+                format_string($category->name, true, array('context' => $this->parentlist->context)) .
+                "</a></b> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>';
 
-        $item .= '&nbsp;'. $category->info;
+        $item .= '&nbsp;' . format_text($category->info, $category->infoformat,
+                array('context' => $this->parentlist->context, 'noclean' => true));
 
         // don't allow delete if this is the last category in this context.
         if (count($this->parentlist->records) != 1) {
-- 
1.7.9.5


From 4c6b8659f963b04f6c8aed91aca215e784086acc Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 30 Aug 2012 22:58:52 +0200
Subject: [PATCH 543/903] MDL-35147 lesson qformat import: Dirty hack to
 support array questiontext structures.

---
 mod/lesson/format.php |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mod/lesson/format.php b/mod/lesson/format.php
index 4d8faf1..95bb645 100644
--- a/mod/lesson/format.php
+++ b/mod/lesson/format.php
@@ -384,6 +384,15 @@ class qformat_default {
                         $newpage->title = "Page $count";
                     }
                     $newpage->contents = $question->questiontext;
+                    $newpage->contentsformat = isset($question->questionformat) ? $question->questionformat : FORMAT_HTML;
+
+                    // Sometimes, questiontext is not a simple text, but one array
+                    // containing both text and format, so we need to support here
+                    // that case with the following dirty patch. MDL-35147
+                    if (is_array($question->questiontext)) {
+                        $newpage->contents = isset($question->questiontext['text']) ? $question->questiontext['text'] : '';
+                        $newpage->contentsformat = isset($question->questiontext['format']) ? $question->questiontext['format'] : FORMAT_HTML;
+                    }
 
                     // set up page links
                     if ($pageid) {
-- 
1.7.9.5


From 98157832bffe0dbb719c25cd6bae46b7131bacff Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 31 Aug 2012 11:35:54 +0200
Subject: [PATCH 544/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 2f379da..13f2855 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.11;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.12;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120823)'; // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120831)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 0a898cbc4687bdc2892b990d6fb866e4f1a3abb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 28 Aug 2012 08:08:30 +0200
Subject: [PATCH 545/903] MDL-35077 fix stats report navigation links

---
 report/stats/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/report/stats/lib.php b/report/stats/lib.php
index c185fb3..1c191a4 100644
--- a/report/stats/lib.php
+++ b/report/stats/lib.php
@@ -36,7 +36,7 @@ defined('MOODLE_INTERNAL') || die;
  */
 function report_stats_extend_navigation_course($navigation, $course, $context) {
     global $CFG;
-    if (!empty($CFG->enablestats)) {
+    if (empty($CFG->enablestats)) {
         return;
     }
     if (has_capability('report/stats:view', $context)) {
@@ -54,7 +54,7 @@ function report_stats_extend_navigation_course($navigation, $course, $context) {
  */
 function report_stats_extend_navigation_user($navigation, $user, $course) {
     global $CFG;
-    if (!empty($CFG->enablestats)) {
+    if (empty($CFG->enablestats)) {
         return;
     }
     if (report_stats_can_access_user_report($user, $course)) {
-- 
1.7.9.5


From 58520c062df411301cbc2406df95c70ec006599a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 1 Sep 2012 12:39:59 +0200
Subject: [PATCH 546/903] MDL-35168 fix yui combo path disclosure

---
 theme/yui_combo.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/theme/yui_combo.php b/theme/yui_combo.php
index 2a77538..6f4f49e 100644
--- a/theme/yui_combo.php
+++ b/theme/yui_combo.php
@@ -109,7 +109,8 @@ foreach ($parts as $part) {
         $contentfile = "$CFG->libdir/yui/$part";
     }
     if (!file_exists($contentfile) or !is_file($contentfile)) {
-        $content .= "\n// Combo resource $part ($contentfile) not found!\n";
+        $location = '$CFG->dirroot'.preg_replace('/^'.preg_quote($CFG->dirroot, '/').'/', '', $contentfile);
+        $content .= "\n// Combo resource $part ($location) not found!\n";
         continue;
     }
     $filecontent = file_get_contents($contentfile);
-- 
1.7.9.5


From 3fe8ae9bb9041d1df58fd99628582fefdcd5875f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 1 Sep 2012 13:27:30 +0200
Subject: [PATCH 547/903] MDL-35145 add extra delete_user() parameter
 validation

We do not want to delete local admins and guest account, we need to validate the supplied parameter is valid $user record and refetch it from database.
---
 lib/moodlelib.php |   34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 58a6c59..0c2a693 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -3915,15 +3915,45 @@ function truncate_userinfo($info) {
  * Any plugin that needs to purge user data should register the 'user_deleted' event.
  *
  * @param stdClass $user full user object before delete
- * @return boolean always true
+ * @return boolean success
+ * @throws coding_exception if invalid $user parameter detected
  */
-function delete_user($user) {
+function delete_user(stdClass $user) {
     global $CFG, $DB;
     require_once($CFG->libdir.'/grouplib.php');
     require_once($CFG->libdir.'/gradelib.php');
     require_once($CFG->dirroot.'/message/lib.php');
     require_once($CFG->dirroot.'/tag/lib.php');
 
+    // Make sure nobody sends bogus record type as parameter.
+    if (!property_exists($user, 'id') or !property_exists($user, 'username')) {
+        throw new coding_exception('Invalid $user parameter in delete_user() detected');
+    }
+
+    // Better not trust the parameter and fetch the latest info,
+    // this will be very expensive anyway.
+    if (!$user = $DB->get_record('user', array('id'=>$user->id))) {
+        debugging('Attempt to delete unknown user account.');
+        return false;
+    }
+
+    // There must be always exactly one guest record,
+    // originally the guest account was identified by username only,
+    // now we use $CFG->siteguest for performance reasons.
+    if ($user->username === 'guest' or isguestuser($user)) {
+        debugging('Guest user account can not be deleted.');
+        return false;
+    }
+
+    // Admin can be theoretically from different auth plugin,
+    // but we want to prevent deletion of internal accoutns only,
+    // if anything goes wrong ppl may force somebody to be admin via
+    // config.php setting $CFG->siteadmins.
+    if ($user->auth === 'manual' and is_siteadmin($user)) {
+        debugging('Local administrator accounts can not be deleted.');
+        return false;
+    }
+
     // delete all grades - backup is kept in grade_grades_history table
     grade_user_delete($user->id);
 
-- 
1.7.9.5


From 45f9c2db5f48ea52d27fc43c9dcb39296ad8c949 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 1 Sep 2012 14:13:40 +0200
Subject: [PATCH 548/903] MDL-35145 add basic unit tests for delete_user()

---
 lib/tests/moodlelib_test.php |   60 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index dd9665a..1abdf80 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -1910,4 +1910,64 @@ class moodlelib_testcase extends advanced_testcase {
         $this->assertEquals('5.43000', format_float(5.43, 5, false));
         $this->assertEquals('5.43', format_float(5.43, 5, false, true));
     }
+
+    /**
+     * Test deleting of users.
+     */
+    public function test_delete_user() {
+        global $DB, $CFG;
+
+        $this->resetAfterTest();
+
+        $guest = $DB->get_record('user', array('id'=>$CFG->siteguest), '*', MUST_EXIST);
+        $admin = $DB->get_record('user', array('id'=>$CFG->siteadmins), '*', MUST_EXIST);
+        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
+
+        $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
+        $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
+
+        $result = delete_user($user);
+        $this->assertTrue($result);
+        $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
+        $this->assertEquals(1, $deluser->deleted);
+        $this->assertEquals(0, $deluser->picture);
+        $this->assertSame('', $deluser->idnumber);
+        $this->assertSame(md5($user->username), $deluser->email);
+        $this->assertRegExp('/^'.preg_quote($user->email, '/').'\.\d*$/', $deluser->username);
+
+        $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
+
+        // Try invalid params.
+
+        $record = new stdClass();
+        $record->grrr = 1;
+        try {
+            delete_user($record);
+            $this->fail('Expecting exception for invalid delete_user() $user parameter');
+        } catch (coding_exception $e) {
+            $this->assertTrue(true);
+        }
+        $record->id = 1;
+        try {
+            delete_user($record);
+            $this->fail('Expecting exception for invalid delete_user() $user parameter');
+        } catch (coding_exception $e) {
+            $this->assertTrue(true);
+        }
+
+        $CFG->debug = DEBUG_MINIMAL; // Prevent standard debug warnings.
+
+        $record = new stdClass();
+        $record->id = 666;
+        $record->username = 'xx';
+        $this->assertFalse($DB->record_exists('user', array('id'=>666))); // Any non-existent id is ok.
+        $result = delete_user($record);
+        $this->assertFalse($result);
+
+        $result = delete_user($guest);
+        $this->assertFalse($result);
+
+        $result = delete_user($admin);
+        $this->assertFalse($result);
+    }
 }
-- 
1.7.9.5


From e0b818cde01dcf2b17945c228ace5fe64c6507fc Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Sat, 1 Sep 2012 10:11:24 -0400
Subject: [PATCH 549/903] MDL-35171 formslib Updating date config array to fix
 problems with month jumping.

Based on https://bugs.php.net/bug.php?id=49115, if you request a month, but do not
specify a date, it will use your current date, which may be beyon a date in the month
requested, causing the return of the next month. This patch specifies the date (1st).
---
 lib/formslib.php |   28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/formslib.php b/lib/formslib.php
index 31a5419..216358b 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -80,26 +80,26 @@ function form_init_date_js() {
         $module   = 'moodle-form-dateselector';
         $function = 'M.form.dateselector.init_date_selectors';
         $config = array(array(
-            'firstdayofweek'    =>  get_string('firstdayofweek', 'langconfig'),
-            'mon'               => strftime('%a', strtotime("Monday")),      // 5th Jan 1970 at 12pm
+            'firstdayofweek'    => get_string('firstdayofweek', 'langconfig'),
+            'mon'               => strftime('%a', strtotime("Monday")),
             'tue'               => strftime('%a', strtotime("Tuesday")),
             'wed'               => strftime('%a', strtotime("Wednesday")),
             'thu'               => strftime('%a', strtotime("Thursday")),
             'fri'               => strftime('%a', strtotime("Friday")),
             'sat'               => strftime('%a', strtotime("Saturday")),
             'sun'               => strftime('%a', strtotime("Sunday")),
-            'january'           => strftime('%B', strtotime("January")),       // 1st Jan 1970 at 12pm
-            'february'          => strftime('%B', strtotime("February")),
-            'march'             => strftime('%B', strtotime("March")),
-            'april'             => strftime('%B', strtotime("April")),
-            'may'               => strftime('%B', strtotime("May")),
-            'june'              => strftime('%B', strtotime("June")),
-            'july'              => strftime('%B', strtotime("July")),
-            'august'            => strftime('%B', strtotime("August")),
-            'september'         => strftime('%B', strtotime("September")),
-            'october'           => strftime('%B', strtotime("October")),
-            'november'          => strftime('%B', strtotime("November")),
-            'december'          => strftime('%B', strtotime("December"))
+            'january'           => strftime('%B', strtotime("January 1")),
+            'february'          => strftime('%B', strtotime("February 1")),
+            'march'             => strftime('%B', strtotime("March 1")),
+            'april'             => strftime('%B', strtotime("April 1")),
+            'may'               => strftime('%B', strtotime("May 1")),
+            'june'              => strftime('%B', strtotime("June 1")),
+            'july'              => strftime('%B', strtotime("July 1")),
+            'august'            => strftime('%B', strtotime("August 1")),
+            'september'         => strftime('%B', strtotime("September 1")),
+            'october'           => strftime('%B', strtotime("October 1")),
+            'november'          => strftime('%B', strtotime("November 1")),
+            'december'          => strftime('%B', strtotime("December 1"))
         ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
-- 
1.7.9.5


From 9817f08400efd3742602325623ee93320e77e639 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 1 Sep 2012 15:37:41 +0200
Subject: [PATCH 550/903] MDL-35080 skip views and weird tables in mysql
 structure upgrades

---
 lib/db/upgradelib.php |   49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/lib/db/upgradelib.php b/lib/db/upgradelib.php
index 5103e0b..5247e49 100644
--- a/lib/db/upgradelib.php
+++ b/lib/db/upgradelib.php
@@ -30,6 +30,51 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+/**
+ * Returns all non-view and non-temp tables with sane names.
+ * Prints list of non-supported tables using $OUTPUT->notification()
+ *
+ * @return array
+ */
+function upgrade_mysql_get_supported_tables() {
+    global $OUTPUT, $DB;
+
+    $tables = array();
+    $patprefix = str_replace('_', '\\_', $DB->get_prefix());
+    $pregprefix = preg_quote($DB->get_prefix(), '/');
+
+    $sql = "SHOW FULL TABLES LIKE '$patprefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    foreach ($rs as $record) {
+        $record = array_change_key_case((array)$record, CASE_LOWER);
+        $type = $record['table_type'];
+        unset($record['table_type']);
+        $fullname = array_shift($record);
+
+        if ($pregprefix === '') {
+            $name = $fullname;
+        } else {
+            $count = null;
+            $name = preg_replace("/^$pregprefix/", '', $fullname, -1, $count);
+            if ($count !== 1) {
+                continue;
+            }
+        }
+
+        if (!preg_match("/^[a-z][a-z0-9_]*$/", $name)) {
+            echo $OUTPUT->notification("Database table with invalid name '$fullname' detected, skipping.", 'notifyproblem');
+            continue;
+        }
+        if ($type === 'VIEW') {
+            echo $OUTPUT->notification("Unsupported database table view '$fullname' detected, skipping.", 'notifyproblem');
+            continue;
+        }
+        $tables[$name] = $name;
+    }
+    $rs->close();
+
+    return $tables;
+}
 
 /**
  * Remove all signed numbers from current database - mysql only.
@@ -50,7 +95,7 @@ function upgrade_mysql_fix_unsigned_columns() {
     $pbar = new progress_bar('mysqlconvertunsigned', 500, true);
 
     $prefix = $DB->get_prefix();
-    $tables = $DB->get_tables();
+    $tables = upgrade_mysql_get_supported_tables();
 
     $tablecount = count($tables);
     $i = 0;
@@ -115,7 +160,7 @@ function upgrade_mysql_fix_lob_columns() {
     $pbar = new progress_bar('mysqlconvertlobs', 500, true);
 
     $prefix = $DB->get_prefix();
-    $tables = $DB->get_tables();
+    $tables = upgrade_mysql_get_supported_tables();
     asort($tables);
 
     $tablecount = count($tables);
-- 
1.7.9.5


From f4f8cf9a2d5cf48eb3a7fafedbe13e94f74ab366 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sat, 1 Sep 2012 23:04:08 +0100
Subject: [PATCH 551/903] MDL-35151 theme_anomaly: removed CSS selectors
 (.forumpost .content p) from style/general.php thus
 allowing YUI CSS to style paragraphs as normal.

---
 theme/anomaly/style/general.css |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/theme/anomaly/style/general.css b/theme/anomaly/style/general.css
index d420e1e..d695186 100644
--- a/theme/anomaly/style/general.css
+++ b/theme/anomaly/style/general.css
@@ -491,8 +491,7 @@ h1.headermain {
     padding-top: 10px;
 }
 
-.forumpost .content .shortenedpost a,
-.forumpost .content p {
+.forumpost .content .shortenedpost a {
     margin: 0 10px;
     padding: 0;
 }
-- 
1.7.9.5


From a49ea3065417a8ffb4fdc0258844543a40684834 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sun, 2 Sep 2012 00:32:45 +0000
Subject: [PATCH 552/903] Automatically generated installer lang files

---
 install/lang/ko/install.php |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/install/lang/ko/install.php b/install/lang/ko/install.php
index a395a57..5dfca0c 100644
--- a/install/lang/ko/install.php
+++ b/install/lang/ko/install.php
@@ -34,7 +34,8 @@ $string['admindirname'] = '관리 디렉토리';
 $string['availablelangs'] = '가능한 언어 목록';
 $string['chooselanguagehead'] = '언어를 선택하시오';
 $string['chooselanguagesub'] = '설치 과정에서 사용할 언어를 선택하십시오. 선택한 언어는 사이트의 기본 언어로 사용할 수 있으며, 추후 다른 언어로 바꿀 수도 있습니다.';
-$string['clialreadyinstalled'] = '이미 config.php 파일이 존재함. 사이트를 업데이트하려면 admin/cli/upgrade.php를 사용하십시오';
+$string['clialreadyconfigured'] = '만일 이 사이트를 설치하고 싶은데 이미 config.php파일이 있다면, admin/cli/install_database.php 를 이용하시기 바랍니다.';
+$string['clialreadyinstalled'] = '이미 config.php 파일이 존재함. 사이트를 업그레이드하려면 admin/cli/upgrade.php를 사용하시기 바랍니다.';
 $string['cliinstallheader'] = '무들 {$a} 명령 입력 설치 프로그램';
 $string['databasehost'] = '데이터베이스 호스트';
 $string['databasename'] = '데이터베이스 명칭';
@@ -83,10 +84,10 @@ $string['phpversionhelp'] = '<p>무들은 적어도 PHP4.3.0 혹은 5.1.0. 이
 <p>PHP를 업그레이드 하시거나 새버전을 제공하는 웹호스팅 업체로 이전하기를 권합니다!<br />(만일 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>무들</strong>이 그 속에서 동작하는 환경을 생성하기 위한 어플리케이션을 포함하고 있습니다.';
+$string['welcomep30'] = '<strong>{$a->installername}</strong> 판본은 <strong>무들</strong>이 동작하는 환경을 생성하기 위한 어플리케이션을 포함하고 있습니다.';
 $string['welcomep40'] = '이 패키지는 <strong>무들 {$a->moodlerelease} ({$a->moodleversion})</strong> 을 포함하고 있습니다.';
 $string['welcomep50'] = '이 패키지에 있는 모든 어플리케이션을 사용하는 것은 각각의 라이센스에의해 지배받습니다. 완전한<strong>{$a->installername}</strong> 패키지는
 <a href="http://www.opensource.org/docs/definition_plain.html">공개 소스이며 </a> <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 라이선스에 의해 배포됩니다.';
-$string['welcomep60'] = '다음 페이지들은 당신의 컴퓨터에 <strong>무들</strong>을 설정하고 설치하는 길라잡이 역할을 할 것입니다. 기본 설정을 선택하거나 목적에 맞게 선택적으로 수정할 수 있습니다.';
+$string['welcomep60'] = '다음 페이지들은 컴퓨터에 <strong>무들</strong>을 설치하고 설정하는 길라잡이 역할을 할 것입니다. 기본 설정을 선택하거나 목적에 맞게 선택적으로 수정할 수 있습니다.';
 $string['welcomep70'] = '<strong>무들</strong> 설정을 계속하기 위해서는 "다음" 버튼을 클릭하세요.';
 $string['wwwroot'] = '웹 주소';
-- 
1.7.9.5


From e235de5ef50c46dcb2a6ecb4ccaa12554b9e0879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 2 Sep 2012 11:52:58 +0200
Subject: [PATCH 553/903] MDL-34097 keep current requirements for Moodle 2.4

---
 admin/environment.xml |  118 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 1 deletion(-)

diff --git a/admin/environment.xml b/admin/environment.xml
index 004cab0..584a9b0 100644
--- a/admin/environment.xml
+++ b/admin/environment.xml
@@ -659,5 +659,121 @@
         </FEEDBACK>
       </PHP_SETTING>
     </PHP_SETTINGS>
-</MOODLE>
+  </MOODLE>
+  <MOODLE version="2.4" requires="2.2">
+    <UNICODE level="required">
+      <FEEDBACK>
+        <ON_ERROR message="unicoderequired" />
+      </FEEDBACK>
+    </UNICODE>
+    <DATABASE level="required">
+      <VENDOR name="mysql" version="5.1.33" />
+      <VENDOR name="postgres" version="8.3" />
+      <VENDOR name="mssql" version="9.0" />
+      <VENDOR name="odbc_mssql" version="9.0" />
+      <VENDOR name="mssql_n" version="9.0" />
+      <VENDOR name="oracle" version="10.2" />
+      <VENDOR name="sqlite" version="2.0" />
+    </DATABASE>
+    <PHP version="5.3.2" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="iconvrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="mbstring" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="mbstringrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="curl" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="curlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="openssl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opensslrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="tokenizer" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="tokenizerrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlrpc" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="xmlrpcrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="soap" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="soaprecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="ctype" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ctyperequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zip" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ziprequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="gd" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="gdrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="splrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="pcre" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="dom" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xml" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="intl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="intlrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="json" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="hash" level="required"/>
+    </PHP_EXTENSIONS>
+    <PHP_SETTINGS>
+      <PHP_SETTING name="memory_limit" value="40M" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="settingmemorylimit" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="safe_mode" value="0" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingsafemode" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="file_uploads" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingfileuploads" />
+        </FEEDBACK>
+      </PHP_SETTING>
+    </PHP_SETTINGS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
-- 
1.7.9.5


From 47045e82b0f4680f84f5fce0269ccdd3ade40ce2 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 2 Sep 2012 14:58:23 +0100
Subject: [PATCH 554/903] MDL-35180 theme_afterburner: fixes IE9 compatibility
 view bug

---
 theme/afterburner/style/afterburner_styles.css |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/theme/afterburner/style/afterburner_styles.css b/theme/afterburner/style/afterburner_styles.css
index eb9260e..5d78380 100644
--- a/theme/afterburner/style/afterburner_styles.css
+++ b/theme/afterburner/style/afterburner_styles.css
@@ -206,6 +206,10 @@ select, input, button {
     background-color: #34637f;
     color: #fff;
 }
+.ie7 select { /* fixes compatibility view */
+    background-color: #eee;
+    color: #036;
+}
 #loginbtn, input, button, select {
     cursor: pointer;
     margin-left: 5px;
@@ -465,4 +469,4 @@ body#page-course-view-topics.path-course div.moodle-dialogue-base div.yui3-widge
 .file-picker button,
 .file-picker textarea {
     background-color: #EEE;
-}
\ No newline at end of file
+}
-- 
1.7.9.5


From b739e2d71a90fceebefdd3d4d3b01b3a559992ce Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 3 Sep 2012 11:41:07 +1200
Subject: [PATCH 555/903] MDL-26822 user: Minor improvements post integration

---
 user/profile.php |   14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/user/profile.php b/user/profile.php
index f79b8a8..81e5e0b 100644
--- a/user/profile.php
+++ b/user/profile.php
@@ -258,11 +258,11 @@ if (isset($identityfields['address']) && $user->address) {
 }
 
 if (isset($identityfields['phone1']) && $user->phone1) {
-        print_row(get_string("phone").":", "$user->phone1");
+    print_row(get_string("phone").":", "$user->phone1");
 }
 
 if (isset($identityfields['phone2']) && $user->phone2) {
-        print_row(get_string("phone2").":", "$user->phone2");
+    print_row(get_string("phone2").":", "$user->phone2");
 }
 
 if (isset($identityfields['institution']) && $user->institution) {
@@ -273,16 +273,14 @@ if (isset($identityfields['department']) && $user->department) {
     print_row(get_string("department").":", "$user->department");
 }
 
-if (isset($identityfields['idnumber']) && $user->idnumber) {
-    print_row(get_string("idnumber").":", "$user->idnumber");
+if (isset($identityfields['idnumber']) && $user->idnumber) {
+    print_row(get_string("idnumber").":", "$user->idnumber");
 }
 
-if (($currentuser
+if (isset($identityfields['email']) and ($currentuser
   or $user->maildisplay == 1
   or has_capability('moodle/course:useremail', $context)
-  or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))
-  and isset($identityfields['email'])) {
-
+  or ($user->maildisplay == 2 and enrol_sharing_course($user, $USER)))) {
     print_row(get_string("email").":", obfuscate_mailto($user->email, ''));
 }
 
-- 
1.7.9.5


From 43b135e5989ca1b9194e3b44e43a2adf8e79f2b6 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Mon, 3 Sep 2012 12:42:26 +1200
Subject: [PATCH 556/903] MDL-35156 remove references to non-existant options

---
 grade/grading/form/guide/lib.php     |    6 ++----
 grade/grading/form/guide/preview.php |    4 +---
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/grade/grading/form/guide/lib.php b/grade/grading/form/guide/lib.php
index 1990064..9e2c832 100644
--- a/grade/grading/form/guide/lib.php
+++ b/grade/grading/form/guide/lib.php
@@ -872,10 +872,8 @@ class gradingform_guide_instance extends gradingform_instance {
             $html .= html_writer::tag('div', get_string('restoredfromdraft', 'gradingform_guide'),
                 array('class' => 'gradingform_guide-restored'));
         }
-        if (!empty($options['showdescriptionteacher'])) {
-            $html .= html_writer::tag('div', $this->get_controller()->get_formatted_description(),
-                array('class' => 'gradingform_guide-description'));
-        }
+        $html .= html_writer::tag('div', $this->get_controller()->get_formatted_description(),
+            array('class' => 'gradingform_guide-description'));
         $html .= $this->get_controller()->get_renderer($page)->display_guide($criteria, $comments, $options, $mode,
             $gradingformelement->getName(), $value, $this->validationerrors);
         return $html;
diff --git a/grade/grading/form/guide/preview.php b/grade/grading/form/guide/preview.php
index ba8aa5d..ec2c1e1 100644
--- a/grade/grading/form/guide/preview.php
+++ b/grade/grading/form/guide/preview.php
@@ -49,8 +49,6 @@ $PAGE->set_heading($title);
 
 echo $OUTPUT->header();
 echo $OUTPUT->heading($title);
-if (!empty($options['showdescriptionstudent'])) {
-    echo $OUTPUT->box($controller->get_formatted_description(), 'gradingform_guide-description');
-}
+echo $OUTPUT->box($controller->get_formatted_description(), 'gradingform_guide-description');
 echo $controller->render_preview($PAGE);
 echo $OUTPUT->footer();
-- 
1.7.9.5


From 905185dca45a953f420fd1410176992b2baa440f Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 14 Aug 2012 16:52:39 +0800
Subject: [PATCH 557/903] MDL-33812 Backup: Respect of backup_auto_keep

---
 backup/util/dbops/backup_plan_dbops.class.php |   14 +++++++++-----
 lang/en/admin.php                             |    2 +-
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/backup/util/dbops/backup_plan_dbops.class.php b/backup/util/dbops/backup_plan_dbops.class.php
index 30714ed..242116e 100644
--- a/backup/util/dbops/backup_plan_dbops.class.php
+++ b/backup/util/dbops/backup_plan_dbops.class.php
@@ -197,19 +197,19 @@ abstract class backup_plan_dbops extends backup_dbops {
     * @param int $courseid/$sectionid/$cmid
     * @param bool $users Should be true is users were included in the backup
     * @param bool $anonymised Should be true is user information was anonymized.
-    * @param bool $useidasname true to use id, false to use strings (default)
+    * @param bool $withoutname if false, include the name in the file name (default)
     * @return string The filename to use
     */
-    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidasname = false) {
+    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $withoutname = false) {
         global $DB;
 
         // Calculate backup word
         $backupword = str_replace(' ', '_', textlib::strtolower(get_string('backupfilename')));
         $backupword = trim(clean_filename($backupword), '_');
 
+        // Not $withoutname, lets fetch the name
         $shortname = '';
-        // Not $useidasname, lets calculate it, else $id will be used
-        if (!$useidasname) {
+        if (!$withoutname) {
             // Calculate proper name element (based on type)
             switch ($type) {
                 case backup::TYPE_1COURSE:
@@ -231,7 +231,11 @@ abstract class backup_plan_dbops extends backup_dbops {
             $shortname = textlib::strtolower(trim(clean_filename($shortname), '_'));
         }
 
-        $name = empty($shortname) ? $id : $shortname;
+        // The name will always contain the ID, but we append the course short name if requested.
+        $name = $id;
+        if (!$withoutname && $shortname != '') {
+            $name .= '-' . $shortname;
+        }
 
         // Calculate date
         $backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig'));
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 26fbe3b..5d26680 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -68,7 +68,7 @@ $string['availablelicenses'] = 'Available licences';
 $string['backgroundcolour'] = 'Transparent colour';
 $string['backups'] = 'Backups';
 $string['backup_shortname'] = 'Use course name in backup filename';
-$string['backup_shortnamehelp'] = 'Use the course name as part of the backup filename instead of the course id number.';
+$string['backup_shortnamehelp'] = 'Use the course name as part of the backup filename.';
 $string['badwordsconfig'] = 'Enter your list of bad words separated by commas.';
 $string['badwordsdefault'] = 'If the custom list is empty, a default list from the language pack will be used.';
 $string['badwordslist'] = 'Custom bad words list';
-- 
1.7.9.5


From 2fd679c5e13d89c8e7cd7be84a6dcef2b44a4a53 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 21 Aug 2012 13:50:55 +0800
Subject: [PATCH 558/903] MDL-33812 Backup: Revert MDL-33521

---
 backup/util/helper/backup_cron_helper.class.php |   13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index b6d81ab..8a3b19d 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -530,18 +530,7 @@ abstract class backup_cron_automated_helper {
         if (!empty($dir) && ($storage == 1 || $storage == 2)) {
             // Calculate backup filename regex, ignoring the date/time/info parts that can be
             // variable, depending of languages, formats and automated backup settings
-
-
-            // MDL-33531: use different filenames depending on backup_shortname option
-            if ( !empty($config->backup_shortname) ) {
-                $context = get_context_instance(CONTEXT_COURSE, $course->id);
-                $courseref = format_string($course->shortname, true, array('context' => $context));
-                $courseref = str_replace(' ', '_', $courseref);
-                $courseref = textlib::strtolower(trim(clean_filename($courseref), '_'));
-            } else {
-                $courseref = $course->id;
-            }
-            $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$courseref . '-';
+            $filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-' .$course->id . '-';
             $regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#';
 
             // Store all the matching files into fullpath => timemodified array
-- 
1.7.9.5


From 640f8eed6d26f89b4a9f3562fae092193cedcfe7 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 29 Aug 2012 16:00:19 +0800
Subject: [PATCH 559/903] MDL-33812 Backup: Added some upgrade information
 about the changes

---
 backup/upgrade.txt                            |   17 +++++++++++++++++
 backup/util/dbops/backup_plan_dbops.class.php |   10 +++++-----
 2 files changed, 22 insertions(+), 5 deletions(-)
 create mode 100644 backup/upgrade.txt

diff --git a/backup/upgrade.txt b/backup/upgrade.txt
new file mode 100644
index 0000000..cb02095
--- /dev/null
+++ b/backup/upgrade.txt
@@ -0,0 +1,17 @@
+This files describes API changes in /backup/*,
+information provided here is intended especially for developers.
+
+=== 2.4 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.3 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.2 ===
+
+* Since 2.2.4+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
\ No newline at end of file
diff --git a/backup/util/dbops/backup_plan_dbops.class.php b/backup/util/dbops/backup_plan_dbops.class.php
index 242116e..0752f0d 100644
--- a/backup/util/dbops/backup_plan_dbops.class.php
+++ b/backup/util/dbops/backup_plan_dbops.class.php
@@ -197,19 +197,19 @@ abstract class backup_plan_dbops extends backup_dbops {
     * @param int $courseid/$sectionid/$cmid
     * @param bool $users Should be true is users were included in the backup
     * @param bool $anonymised Should be true is user information was anonymized.
-    * @param bool $withoutname if false, include the name in the file name (default)
+    * @param bool $useidonly only use the ID in the file name
     * @return string The filename to use
     */
-    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $withoutname = false) {
+    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidonly = false) {
         global $DB;
 
         // Calculate backup word
         $backupword = str_replace(' ', '_', textlib::strtolower(get_string('backupfilename')));
         $backupword = trim(clean_filename($backupword), '_');
 
-        // Not $withoutname, lets fetch the name
+        // Not $useidonly, lets fetch the name
         $shortname = '';
-        if (!$withoutname) {
+        if (!$useidonly) {
             // Calculate proper name element (based on type)
             switch ($type) {
                 case backup::TYPE_1COURSE:
@@ -233,7 +233,7 @@ abstract class backup_plan_dbops extends backup_dbops {
 
         // The name will always contain the ID, but we append the course short name if requested.
         $name = $id;
-        if (!$withoutname && $shortname != '') {
+        if (!$useidonly && $shortname != '') {
             $name .= '-' . $shortname;
         }
 
-- 
1.7.9.5


From c128731d1938912d79b105441d9dd2431e26966a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 27 Aug 2012 14:47:01 +0800
Subject: [PATCH 560/903] MDL-35034 Repository: Google Docs does not fail when
 download is restricted

---
 lib/googleapi.php             |   24 +++++++++++-------------
 repository/googledocs/lib.php |    4 +++-
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/googleapi.php b/lib/googleapi.php
index c2d529f..3ace654 100644
--- a/lib/googleapi.php
+++ b/lib/googleapi.php
@@ -109,23 +109,21 @@ class google_docs {
                     $source = 'https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key='.$docid.'&exportFormat=xls';
                     break;
                 case 'pdf':
-                    $title  = (string)$gdoc->title;
-                    $source = (string)$gdoc->content[0]->attributes()->src;
-                    break;
                 case 'file':
-                    $title = (string)$gdoc->title;
-                    $source = (string)$gdoc->content[0]->attributes()->src;
+                    $title  = (string)$gdoc->title;
+                    // Some files don't have a content probably because the download has been restricted.
+                    if (isset($gdoc->content)) {
+                        $source = (string)$gdoc->content[0]->attributes()->src;
+                    }
                     break;
             }
 
-            if (!empty($source)) {
-                $files[] =  array( 'title' => $title,
-                    'url' => "{$gdoc->link[0]->attributes()->href}",
-                    'source' => $source,
-                    'date'   => usertime(strtotime($gdoc->updated)),
-                    'thumbnail' => (string) $OUTPUT->pix_url(file_extension_icon($title, 32))
-                );
-            }
+            $files[] =  array( 'title' => $title,
+                'url' => "{$gdoc->link[0]->attributes()->href}",
+                'source' => $source,
+                'date'   => usertime(strtotime($gdoc->updated)),
+                'thumbnail' => (string) $OUTPUT->pix_url(file_extension_icon($title, 32))
+            );
         }
 
         return $files;
diff --git a/repository/googledocs/lib.php b/repository/googledocs/lib.php
index 38299de..72ca7bb 100644
--- a/repository/googledocs/lib.php
+++ b/repository/googledocs/lib.php
@@ -92,8 +92,10 @@ class repository_googledocs extends repository {
     }
 
     public function get_file($url, $file = '') {
+        if (empty($url)) {
+           throw new repository_exception('cannotdownload', 'repository');
+        }
         $gdocs = new google_docs($this->googleoauth);
-
         $path = $this->prepare_file($file);
         return $gdocs->download_file($url, $path, self::GETFILE_TIMEOUT);
     }
-- 
1.7.9.5


From 397afd71c380b8ffe3066086f5d4f35cd453ce43 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 30 Jul 2012 14:10:46 +0800
Subject: [PATCH 561/903] MDL-28346 Backup: Added new status 'warning' for
 backup result

---
 backup/util/helper/backup_cron_helper.class.php |   55 ++++++++++++++++++-----
 lang/en/moodle.php                              |    1 +
 report/backups/index.php                        |   13 ++++--
 theme/base/style/admin.css                      |    1 +
 4 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index b6d81ab..a2a5191 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -46,6 +46,8 @@ abstract class backup_cron_automated_helper {
     const BACKUP_STATUS_UNFINISHED = 2;
     /** Course automated backup was skipped */
     const BACKUP_STATUS_SKIPPED = 3;
+    /** Course automated backup had warnings */
+    const BACKUP_STATUS_WARNING = 4;
 
     /** Run if required by the schedule set in config. Default. **/
     const RUN_ON_SCHEDULE = 0;
@@ -139,7 +141,7 @@ abstract class backup_cron_automated_helper {
                     $params = array('courseid' => $course->id, 'time' => $now-31*24*60*60, 'action' => '%view%');
                     $logexists = $DB->record_exists_select('log', $sqlwhere, $params);
                     if (!$logexists) {
-                        $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+                        $backupcourse->laststatus = self::BACKUP_STATUS_SKIPPED;
                         $backupcourse->nextstarttime = $nextstarttime;
                         $DB->update_record('backup_courses', $backupcourse);
                         mtrace('Skipping unchanged course '.$course->fullname);
@@ -160,7 +162,7 @@ abstract class backup_cron_automated_helper {
                         $starttime = time();
 
                         $backupcourse->laststarttime = time();
-                        $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED;
+                        $backupcourse->laststatus = self::BACKUP_STATUS_UNFINISHED;
                         $DB->update_record('backup_courses', $backupcourse);
 
                         $backupcourse->laststatus = backup_cron_automated_helper::launch_automated_backup($course, $backupcourse->laststarttime, $admin->id);
@@ -169,7 +171,7 @@ abstract class backup_cron_automated_helper {
 
                         $DB->update_record('backup_courses', $backupcourse);
 
-                        if ($backupcourse->laststatus) {
+                        if ($backupcourse->laststatus === self::BACKUP_STATUS_OK) {
                             // Clean up any excess course backups now that we have
                             // taken a successful backup.
                             $removedcount = backup_cron_automated_helper::remove_excess_backups($course);
@@ -188,17 +190,18 @@ abstract class backup_cron_automated_helper {
             $message = "";
 
             $count = backup_cron_automated_helper::get_backup_status_array();
-            $haserrors = ($count[backup_cron_automated_helper::BACKUP_STATUS_ERROR] != 0 || $count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED] != 0);
+            $haserrors = ($count[self::BACKUP_STATUS_ERROR] != 0 || $count[self::BACKUP_STATUS_UNFINISHED] != 0);
 
             //Build the message text
             //Summary
             $message .= get_string('summary')."\n";
             $message .= "==================================================\n";
             $message .= "  ".get_string('courses').": ".array_sum($count)."\n";
-            $message .= "  ".get_string('ok').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_OK]."\n";
-            $message .= "  ".get_string('skipped').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_SKIPPED]."\n";
-            $message .= "  ".get_string('error').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_ERROR]."\n";
-            $message .= "  ".get_string('unfinished').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED]."\n\n";
+            $message .= "  ".get_string('ok').": ".$count[self::BACKUP_STATUS_OK]."\n";
+            $message .= "  ".get_string('skipped').": ".$count[self::BACKUP_STATUS_SKIPPED]."\n";
+            $message .= "  ".get_string('error').": ".$count[self::BACKUP_STATUS_ERROR]."\n";
+            $message .= "  ".get_string('unfinished').": ".$count[self::BACKUP_STATUS_UNFINISHED]."\n";
+            $message .= "  ".get_string('warning').": ".$count[self::BACKUP_STATUS_WARNING]."\n\n";
 
             //Reference
             if ($haserrors) {
@@ -261,6 +264,7 @@ abstract class backup_cron_automated_helper {
             self::BACKUP_STATUS_OK => 0,
             self::BACKUP_STATUS_UNFINISHED => 0,
             self::BACKUP_STATUS_SKIPPED => 0,
+            self::BACKUP_STATUS_WARNING => 0
         );
 
         $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
@@ -334,7 +338,7 @@ abstract class backup_cron_automated_helper {
      */
     public static function launch_automated_backup($course, $starttime, $userid) {
 
-        $outcome = true;
+        $outcome = self::BACKUP_STATUS_OK;
         $config = get_config('backup');
         $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
 
@@ -369,6 +373,7 @@ abstract class backup_cron_automated_helper {
 
             $bc->execute_plan();
             $results = $bc->get_results();
+            $outcome = self::outcome_from_results($results);
             $file = $results['backup_destination']; // may be empty if file already moved to target location
             $dir = $config->backup_auto_destination;
             $storage = (int)$config->backup_auto_storage;
@@ -377,8 +382,10 @@ abstract class backup_cron_automated_helper {
             }
             if ($file && !empty($dir) && $storage !== 0) {
                 $filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
-                $outcome = $file->copy_content_to($dir.'/'.$filename);
-                if ($outcome && $storage === 1) {
+                if (!$file->copy_content_to($dir.'/'.$filename)) {
+                    $outcome = self::BACKUP_STATUS_ERROR;
+                }
+                if ($outcome != self::BACKUP_STATUS_ERROR && $storage === 1) {
                     $file->delete();
                 }
             }
@@ -387,7 +394,7 @@ abstract class backup_cron_automated_helper {
             $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname); // Log error header.
             $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1); // Log original exception problem.
             $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1); // Log original debug information.
-            $outcome = false;
+            $outcome = self::BACKUP_STATUS_ERROR;
         }
 
         $bc->destroy();
@@ -397,6 +404,30 @@ abstract class backup_cron_automated_helper {
     }
 
     /**
+     * Returns the backup outcome by analysing its results.
+     *
+     * @param array $results returned by a backup
+     * @return int {@link self::BACKUP_STATUS_OK} and other constants
+     */
+    public static function outcome_from_results($results) {
+        $outcome = self::BACKUP_STATUS_OK;
+        foreach ($results as $code => $value) {
+            // Each possible error and warning code has to be specified in this switch
+            // which basically analyses the results to return the correct backup status.
+            switch ($code) {
+                case 'missing_files_in_pool':
+                    $outcome = self::BACKUP_STATUS_WARNING;
+                    break;
+            }
+            // If we found the highest error level, we exit the loop.
+            if ($outcome == self::BACKUP_STATUS_ERROR) {
+                break;
+            }
+        }
+        return $outcome;
+    }
+
+    /**
      * Removes deleted courses fromn the backup_courses table so that we don't
      * waste time backing them up.
      *
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 377b840..a3d28ab 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1803,6 +1803,7 @@ $string['virusfounduser'] = 'The file you have uploaded, {$a->filename}, has bee
 $string['virusplaceholder'] = 'This file that has been uploaded was found to contain a virus and has been moved or deleted and the user notified.';
 $string['visible'] = 'Visible';
 $string['visibletostudents'] = 'Visible to {$a}';
+$string['warning'] = 'Warning';
 $string['warningdeleteresource'] = 'Warning: {$a} is referred in a resource. Would you like to update the resource?';
 $string['webpage'] = 'Web page';
 $string['week'] = 'Week';
diff --git a/report/backups/index.php b/report/backups/index.php
index 5a70587..7685117 100644
--- a/report/backups/index.php
+++ b/report/backups/index.php
@@ -27,6 +27,9 @@ require_once('../../config.php');
 require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->dirroot.'/backup/lib.php');
 
+// Required for constants in backup_cron_automated_helper
+require_once($CFG->dirroot.'/backup/util/helper/backup_cron_helper.class.php');
+
 admin_externalpage_setup('reportbackups', '', null, '', array('pagelayout'=>'report'));
 
 $table = new html_table;
@@ -45,6 +48,7 @@ $strerror = get_string("error");
 $strok = get_string("ok");
 $strunfinished = get_string("unfinished");
 $strskipped = get_string("skipped");
+$strwarning = get_string("warning");
 
 list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
 $sql = "SELECT bc.*, c.fullname $select
@@ -58,15 +62,18 @@ foreach ($rs as $backuprow) {
     context_instance_preload($backuprow);
 
     // Prepare a cell to display the status of the entry
-    if ($backuprow->laststatus == 1) {
+    if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_OK) {
         $status = $strok;
         $statusclass = 'backup-ok'; // Green
-    } else if ($backuprow->laststatus == 2) {
+    } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED) {
         $status = $strunfinished;
         $statusclass = 'backup-unfinished'; // Red
-    } else if ($backuprow->laststatus == 3) {
+    } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_SKIPPED) {
         $status = $strskipped;
         $statusclass = 'backup-skipped'; // Green
+    } else if ($backuprow->laststatus == backup_cron_automated_helper::BACKUP_STATUS_WARNING) {
+        $status = $strwarning;
+        $statusclass = 'backup-warning'; // Orange
     } else {
         $status = $strerror;
         $statusclass = 'backup-error'; // Red
diff --git a/theme/base/style/admin.css b/theme/base/style/admin.css
index 8c0ce47..df0e64f 100644
--- a/theme/base/style/admin.css
+++ b/theme/base/style/admin.css
@@ -42,6 +42,7 @@
 #page-admin-report-backups-index .backup-unfinished {color: #f00000;}
 #page-admin-report-backups-index .backup-skipped,
 #page-admin-report-backups-index .backup-ok {color: #006400;}
+#page-admin-report-backups-index .backup-warning {color: #ff9900;}
 
 #page-admin-qbehaviours .disabled {color: gray;}
 #page-admin-qbehaviours th {white-space: normal;}
-- 
1.7.9.5


From 16ee63b4b83f82db97caeb6967ecf287d1090628 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 9 Jul 2012 10:49:25 +0800
Subject: [PATCH 562/903] MDL-28346 Backup: Restore does not fail when a file
 is missing

---
 backup/util/dbops/restore_dbops.class.php         |   12 +++++++++++-
 backup/util/plan/restore_structure_step.class.php |   10 ++++++++--
 backup/util/ui/restore_ui_stage.class.php         |    3 +++
 lang/en/backup.php                                |    1 +
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php
index 2e73e8f..fb7beb3 100644
--- a/backup/util/dbops/restore_dbops.class.php
+++ b/backup/util/dbops/restore_dbops.class.php
@@ -819,10 +819,13 @@ abstract class restore_dbops {
      * @param int|null $olditemid
      * @param int|null $forcenewcontextid explicit value for the new contextid (skip mapping)
      * @param bool $skipparentitemidctxmatch
+     * @return array of result object
      */
     public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $dfltuserid, $itemname = null, $olditemid = null, $forcenewcontextid = null, $skipparentitemidctxmatch = false) {
         global $DB;
 
+        $results = array();
+
         if ($forcenewcontextid) {
             // Some components can have "forced" new contexts (example: questions can end belonging to non-standard context mappings,
             // with questions originally at system/coursecat context in source being restored to course context in target). So we need
@@ -902,8 +905,14 @@ abstract class restore_dbops {
                 // this is a regular file, it must be present in the backup pool
                 $backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
 
+                // The file is not found in the backup.
                 if (!file_exists($backuppath)) {
-                    throw new restore_dbops_exception('file_not_found_in_pool', $file);
+                    $result = new stdClass();
+                    $result->code = 'file_missing_in_backup';
+                    $result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
+                    $result->level = backup::LOG_WARNING;
+                    $results[] = $result;
+                    continue;
                 }
 
                 // create the file in the filepool if it does not exist yet
@@ -960,6 +969,7 @@ abstract class restore_dbops {
             }
         }
         $rs->close();
+        return $results;
     }
 
     /**
diff --git a/backup/util/plan/restore_structure_step.class.php b/backup/util/plan/restore_structure_step.class.php
index 4b0ff58..b6c0ead 100644
--- a/backup/util/plan/restore_structure_step.class.php
+++ b/backup/util/plan/restore_structure_step.class.php
@@ -218,8 +218,14 @@ abstract class restore_structure_step extends restore_step {
      */
     public function add_related_files($component, $filearea, $mappingitemname, $filesctxid = null, $olditemid = null) {
         $filesctxid = is_null($filesctxid) ? $this->task->get_old_contextid() : $filesctxid;
-        restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
-                                          $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+        $results = restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
+                $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+        $resultstoadd = array();
+        foreach ($results as $result) {
+            $this->log($result->message, $result->level);
+            $resultstoadd[$result->code] = true;
+        }
+        $this->task->add_result($resultstoadd);
     }
 
     /**
diff --git a/backup/util/ui/restore_ui_stage.class.php b/backup/util/ui/restore_ui_stage.class.php
index 7e92069..34bff92 100644
--- a/backup/util/ui/restore_ui_stage.class.php
+++ b/backup/util/ui/restore_ui_stage.class.php
@@ -772,6 +772,9 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
             $html .= $renderer->box_end();
         }
         $html .= $renderer->box_start();
+        if (array_key_exists('file_missing_in_backup', $this->results)) {
+            $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
+        }
         $html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
         $html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
             'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
diff --git a/lang/en/backup.php b/lang/en/backup.php
index 5fde19e..e9744d5 100644
--- a/lang/en/backup.php
+++ b/lang/en/backup.php
@@ -177,6 +177,7 @@ $string['restoreactivity'] = 'Restore activity';
 $string['restorecourse'] = 'Restore course';
 $string['restorecoursesettings'] = 'Course settings';
 $string['restoreexecutionsuccess'] = 'The course was restored successfully, clicking the continue button below will take you to view the course you restored.';
+$string['restorefileweremissing'] = 'Some files could not be restored because they were missing in the backup.';
 $string['restorenewcoursefullname'] = 'New course name';
 $string['restorenewcourseshortname'] = 'New course short name';
 $string['restorenewcoursestartdate'] = 'New start date';
-- 
1.7.9.5


From 3bae0b59167d118d3aca47c42560d9ecf6734535 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 9 Jul 2012 10:49:25 +0800
Subject: [PATCH 563/903] MDL-28346 Backup: Backup does not fail when a file
 is missing

---
 backup/moodle2/backup_custom_fields.php            |    9 ++-
 backup/util/plan/backup_structure_step.class.php   |   11 +++
 .../util/structure/backup_nested_element.class.php |   73 ++++++++++++++++++++
 backup/util/ui/backup_ui_stage.class.php           |    3 +
 lang/en/backup.php                                 |    1 +
 5 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/backup/moodle2/backup_custom_fields.php b/backup/moodle2/backup_custom_fields.php
index e0ceb33..12929de 100644
--- a/backup/moodle2/backup_custom_fields.php
+++ b/backup/moodle2/backup_custom_fields.php
@@ -96,14 +96,19 @@ class file_nested_element extends backup_nested_element {
         if (is_null($this->backupid)) {
             $this->backupid = $processor->get_var(backup::VAR_BACKUPID);
         }
-        parent::process($processor);
+        return parent::process($processor);
     }
 
     public function fill_values($values) {
         // Fill values
         parent::fill_values($values);
         // Do our own tasks (copy file from moodle to backup)
-        backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+        try {
+            backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+        } catch (file_exception $e) {
+            $this->add_result(array('missing_files_in_pool' => true));
+            $this->add_log('missing file in pool: ' . $e->debuginfo, backup::LOG_WARNING);
+        }
     }
 }
 
diff --git a/backup/util/plan/backup_structure_step.class.php b/backup/util/plan/backup_structure_step.class.php
index f62fee9..964dd3f 100644
--- a/backup/util/plan/backup_structure_step.class.php
+++ b/backup/util/plan/backup_structure_step.class.php
@@ -94,11 +94,22 @@ abstract class backup_structure_step extends backup_step {
         // Process structure definition
         $structure->process($pr);
 
+        // Get the results from the nested elements
+        $results = $structure->get_results();
+
+        // Get the log messages to append to the log
+        $logs = $structure->get_logs();
+        foreach ($logs as $log) {
+            $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
+        }
+
         // Close everything
         $xw->stop();
 
         // Destroy the structure. It helps PHP 5.2 memory a lot!
         $structure->destroy();
+
+        return $results;
     }
 
     /**
diff --git a/backup/util/structure/backup_nested_element.class.php b/backup/util/structure/backup_nested_element.class.php
index 9a47901..8557ec8 100644
--- a/backup/util/structure/backup_nested_element.class.php
+++ b/backup/util/structure/backup_nested_element.class.php
@@ -37,6 +37,8 @@ class backup_nested_element extends base_nested_element implements processable {
     protected $aliases;   // Define DB->final element aliases
     protected $fileannotations;   // array of file areas to be searched by file annotations
     protected $counter;   // Number of instances of this element that have been processed
+    protected $results;  // Logs the results we encounter during the process.
+    protected $logs;     // Some log messages that could be retrieved later.
 
     /**
      * Constructor - instantiates one backup_nested_element, specifying its basic info.
@@ -55,8 +57,16 @@ class backup_nested_element extends base_nested_element implements processable {
         $this->aliases   = array();
         $this->fileannotations = array();
         $this->counter   = 0;
+        $this->results  = array();
+        $this->logs     = array();
     }
 
+    /**
+     * Process the nested element
+     *
+     * @param object $processor the processor
+     * @return void
+     */
     public function process($processor) {
         if (!$processor instanceof base_processor) { // No correct processor, throw exception
             throw new base_element_struct_exception('incorrect_processor');
@@ -113,6 +123,69 @@ class backup_nested_element extends base_nested_element implements processable {
         $iterator->close();
     }
 
+    /**
+     * Saves a log message to an array
+     *
+     * @see backup_helper::log()
+     * @param string $message to add to the logs
+     * @param int $level level of importance {@link backup::LOG_DEBUG} and other constants
+     * @param mixed $a to be included in $message
+     * @param int $depth of the message
+     * @param display $bool supporting translation via get_string() if true
+     * @return void
+     */
+    protected function add_log($message, $level, $a = null, $depth = null, $display = false) {
+        // Adding the result to the oldest parent.
+        if ($this->get_parent()) {
+            $parent = $this->get_grandparent();
+            $parent->add_log($message, $level, $a, $depth, $display);
+        } else {
+            $log = new stdClass();
+            $log->message = $message;
+            $log->level = $level;
+            $log->a = $a;
+            $log->depth = $depth;
+            $log->display = $display;
+            $this->logs[] = $log;
+        }
+    }
+
+    /**
+     * Saves the results to an array
+     *
+     * @param array $result associative array
+     * @return void
+     */
+    protected function add_result($result) {
+        if (is_array($result)) {
+            // Adding the result to the oldest parent.
+            if ($this->get_parent()) {
+                $parent = $this->get_grandparent();
+                $parent->add_result($result);
+            } else {
+                $this->results = array_merge($this->results, $result);
+            }
+        }
+    }
+
+    /**
+     * Returns the logs
+     *
+     * @return array of log objects
+     */
+    public function get_logs() {
+        return $this->logs;
+    }
+
+    /**
+     * Returns the results
+     *
+     * @return associative array of results
+     */
+    public function get_results() {
+        return $this->results;
+    }
+
     public function set_source_array($arr) {
         // TODO: Only elements having final elements can set source
         $this->var_array = $arr;
diff --git a/backup/util/ui/backup_ui_stage.class.php b/backup/util/ui/backup_ui_stage.class.php
index 7995561..0b90e15 100644
--- a/backup/util/ui/backup_ui_stage.class.php
+++ b/backup/util/ui/backup_ui_stage.class.php
@@ -487,6 +487,9 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
         if (!empty($this->results['include_file_references_to_external_content'])) {
             $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
         }
+        if (!empty($this->results['missing_files_in_pool'])) {
+            $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
+        }
         $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
         $output .= $renderer->continue_button($restorerul);
         $output .= $renderer->box_end();
diff --git a/lang/en/backup.php b/lang/en/backup.php
index e9744d5..e053c96 100644
--- a/lang/en/backup.php
+++ b/lang/en/backup.php
@@ -163,6 +163,7 @@ $string['lockedbypermission'] = 'You don\'t have sufficient permissions to chang
 $string['lockedbyconfig'] = 'This setting has been locked by the default backup settings';
 $string['lockedbyhierarchy'] = 'Locked by dependencies';
 $string['managefiles'] = 'Manage backup files';
+$string['missingfilesinpool'] = 'Some files could not be saved during the backup, it won\'t be possible to restore them.';
 $string['moodleversion'] = 'Moodle version';
 $string['moreresults'] = 'There are too many results, enter a more specific search.';
 $string['nomatchingcourses'] = 'There are no courses to display';
-- 
1.7.9.5


From 3d5df93b804509fa4036677f934b26057c9519e0 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Gaudreau <jp.gaudreau@umontreal.ca>
Date: Wed, 22 Aug 2012 09:29:56 -0400
Subject: [PATCH 564/903] MDL-34997 - Allow shortened url youtu.be and y2u.be
 for Youtube filter

---
 filter/mediaplugin/tests/filter_test.php |    3 +++
 lib/medialib.php                         |   17 +++++++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/filter/mediaplugin/tests/filter_test.php b/filter/mediaplugin/tests/filter_test.php
index 8687610..f2029ca 100644
--- a/filter/mediaplugin/tests/filter_test.php
+++ b/filter/mediaplugin/tests/filter_test.php
@@ -57,7 +57,10 @@ class filter_mediaplugin_testcase extends advanced_testcase {
             '<a id="movie player" class="center" href="http://moodle.org/testfile/test.mpg">test mpg</a>',
             '<a href="http://moodle.org/testfile/test.ram">test</a>',
             '<a href="http://www.youtube.com/watch?v=JghQgA2HMX8" class="href=css">test file</a>',
+            '<a href="http://www.youtube-nocookie.com/watch?v=JghQgA2HMX8" class="href=css">test file</a>',
             '<a class="youtube" href="http://www.youtube.com/watch?v=JghQgA2HMX8">test file</a>',
+            '<a href="http://youtu.be/JghQgA2HMX8" class="href=css">test file</a>',
+            '<a href="http://y2u.be/JghQgA2HMX8" class="href=css">test file</a>',
             '<a class="_blanktarget" href="http://moodle.org/testfile/test.flv?d=100x100">test flv</a>',
             '<a class="hrefcss" href="http://www.youtube.com/watch?v=JghQgA2HMX8">test file</a>',
             '<a  class="content"     href="http://moodle.org/testfile/test.avi">test mp3</a>',
diff --git a/lib/medialib.php b/lib/medialib.php
index 2290060..e24f979 100644
--- a/lib/medialib.php
+++ b/lib/medialib.php
@@ -528,8 +528,8 @@ class core_media_player_youtube extends core_media_player_external {
     protected function embed_external(moodle_url $url, $name, $width, $height, $options) {
         global $CFG;
 
-        $site = $this->matches[1];
-        $videoid = $this->matches[3];
+        $site = 'www.youtube.com';
+        $videoid = end($this->matches);
 
         $info = trim($name);
         if (empty($info) or strpos($info, 'http') === 0) {
@@ -564,10 +564,15 @@ OET;
     }
 
     protected function get_regex() {
+        // Regex for standard youtube link
+         $link = '(youtube(-nocookie)?\.com/(?:watch\?v=|v/))';
+        // Regex for shortened youtube link
+        $shortlink = '((youtu|y2u)\.be/)';
+
         // Initial part of link.
-        $start = '~^https?://(www\.youtube(-nocookie)?\.com)/';
-        // Middle bit: either watch?v= or v/.
-        $middle = '(?:watch\?v=|v/)([a-z0-9\-_]+)';
+         $start = '~^https?://(www\.)?(' . $link . '|' . $shortlink . ')';
+        // Middle bit: Video key value
+        $middle = '([a-z0-9\-_]+)';
         return $start . $middle . core_media_player_external::END_LINK_REGEX_PART;
     }
 
@@ -578,7 +583,7 @@ OET;
     }
 
     public function get_embeddable_markers() {
-        return array('youtube');
+        return array('youtube.com', 'youtube-nocookie.com', 'youtu.be', 'y2u.be');
     }
 }
 
-- 
1.7.9.5


From 668ba1e92213afd2430b439d7c82c18bb7e391c4 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 28 Aug 2012 17:14:45 +0800
Subject: [PATCH 565/903] MDL-35101 Repository: Public Flickr fails when the
 picture has no license

---
 repository/flickr_public/lib.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/repository/flickr_public/lib.php b/repository/flickr_public/lib.php
index b31adaf..42d7e04 100644
--- a/repository/flickr_public/lib.php
+++ b/repository/flickr_public/lib.php
@@ -213,13 +213,14 @@ class repository_flickr_public extends repository {
 
     public function license4moodle ($license_id) {
         $license = array(
+            '0' => 'allrightsreserved',
             '1' => 'cc-nc-sa',
             '2' => 'cc-nc',
             '3' => 'cc-nc-nd',
             '4' => 'cc',
             '5' => 'cc-sa',
             '6' => 'cc-nd',
-            '7' => 'allrightsreserved'
+            '7' => 'other'
             );
         return $license[$license_id];
     }
-- 
1.7.9.5


From 82bf5b10b9e3e4078e18960c3ab762cf8a9ef8a8 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 28 Aug 2012 17:01:41 +0800
Subject: [PATCH 566/903] MDL-34633 Repository: Flickr supports small images

---
 repository/flickr/lib.php        |   42 ++++++++++++++++++------
 repository/flickr_public/lib.php |   66 ++++++++++++++++++++++++--------------
 2 files changed, 75 insertions(+), 33 deletions(-)

diff --git a/repository/flickr/lib.php b/repository/flickr/lib.php
index 478e53b..84bac4b 100644
--- a/repository/flickr/lib.php
+++ b/repository/flickr/lib.php
@@ -38,6 +38,11 @@ class repository_flickr extends repository {
     public $photos;
 
     /**
+     * Stores sizes of images to prevent multiple API call
+     */
+    static private $sizes = array();
+
+    /**
      *
      * @param int $repositoryid
      * @param object $context
@@ -228,16 +233,35 @@ class repository_flickr extends repository {
      * @return string
      */
     private function build_photo_url($photoid) {
-        $result = $this->flickr->photos_getSizes($photoid);
-        $url = '';
-        if(!empty($result[4])) {
-            $url = $result[4]['source'];
-        } elseif(!empty($result[3])) {
-            $url = $result[3]['source'];
-        } elseif(!empty($result[2])) {
-            $url = $result[2]['source'];
+        $bestsize = $this->get_best_size($photoid);
+        if (!isset($bestsize['source'])) {
+            throw new repository_exception('cannotdownload', 'repository');
+        }
+        return $bestsize['source'];
+    }
+
+    /**
+     * Returns the best size for a photo
+     *
+     * @param string $photoid the photo identifier
+     * @return array of information provided by the API
+     */
+    protected function get_best_size($photoid) {
+        if (!isset(self::$sizes[$photoid])) {
+            // Sizes are returned from smallest to greatest.
+            self::$sizes[$photoid] = $this->flickr->photos_getSizes($photoid);
+        }
+        $sizes = self::$sizes[$photoid];
+        $bestsize = array();
+        if (is_array($sizes)) {
+            while ($bestsize = array_pop($sizes)) {
+                // Make sure the source is set. Exit the loop if found.
+                if (isset($bestsize['source'])) {
+                    break;
+                }
+            }
         }
-        return $url;
+        return $bestsize;
     }
 
     public function get_link($photoid) {
diff --git a/repository/flickr_public/lib.php b/repository/flickr_public/lib.php
index 42d7e04..17cdb57 100644
--- a/repository/flickr_public/lib.php
+++ b/repository/flickr_public/lib.php
@@ -42,6 +42,11 @@ class repository_flickr_public extends repository {
     public $photos;
 
     /**
+     * Stores sizes of images to prevent multiple API call
+     */
+    static private $sizes = array();
+
+    /**
      * constructor method
      *
      * @global object $CFG
@@ -403,16 +408,35 @@ class repository_flickr_public extends repository {
      * @return string
      */
     private function build_photo_url($photoid) {
-        $result = $this->flickr->photos_getSizes($photoid);
-        $url = '';
-        if(!empty($result[4])) {
-            $url = $result[4]['source'];
-        } elseif(!empty($result[3])) {
-            $url = $result[3]['source'];
-        } elseif(!empty($result[2])) {
-            $url = $result[2]['source'];
+        $bestsize = $this->get_best_size($photoid);
+        if (!isset($bestsize['source'])) {
+            throw new repository_exception('cannotdownload', 'repository');
+        }
+        return $bestsize['source'];
+    }
+
+    /**
+     * Returns the best size for a photo
+     *
+     * @param string $photoid the photo identifier
+     * @return array of information provided by the API
+     */
+    protected function get_best_size($photoid) {
+        if (!isset(self::$sizes[$photoid])) {
+            // Sizes are returned from smallest to greatest.
+            self::$sizes[$photoid] = $this->flickr->photos_getSizes($photoid);
+        }
+        $sizes = self::$sizes[$photoid];
+        $bestsize = array();
+        if (is_array($sizes)) {
+            while ($bestsize = array_pop($sizes)) {
+                // Make sure the source is set. Exit the loop if found.
+                if (isset($bestsize['source'])) {
+                    break;
+                }
+            }
         }
-        return $url;
+        return $bestsize;
     }
 
     public function get_link($photoid) {
@@ -435,29 +459,23 @@ class repository_flickr_public extends repository {
             $author = $info['owner']['username'];
         }
         $copyright = get_string('author', 'repository') . ': ' . $author;
-        $result = $this->flickr->photos_getSizes($photoid);
-        // download link
-        $source = '';
-        // flickr photo page
-        $url = '';
-        if (!empty($result[4])) {
-            $source = $result[4]['source'];
-            $url = $result[4]['url'];
-        } elseif(!empty($result[3])) {
-            $source = $result[3]['source'];
-            $url = $result[3]['url'];
-        } elseif(!empty($result[2])) {
-            $source = $result[2]['source'];
-            $url = $result[2]['url'];
+
+        // If we can read the original secret, it means that we have access to the original picture.
+        if (isset($info['originalsecret'])) {
+            $source = $this->flickr->buildPhotoURL($info, 'original');
+        } else {
+            $source = $this->build_photo_url($photoid);
         }
+
         $result = parent::get_file($source, $file);
         $path = $result['path'];
+
         if (!empty($this->usewatermarks)) {
             $img = new moodle_image($path);
             $img->watermark($copyright, array(10,10), array('ttf'=>true, 'fontsize'=>12))->saveas($path);
         }
 
-        return array('path'=>$path, 'url'=>$url, 'author'=>$info['owner']['realname'], 'license'=>$this->license4moodle($info['license']));
+        return array('path'=>$path, 'author'=>$info['owner']['realname'], 'license'=>$this->license4moodle($info['license']));
     }
 
     /**
-- 
1.7.9.5


From 2f2242efa2fd10a04f90ccd8c5162f95e857f242 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 17 Aug 2012 11:44:00 +0800
Subject: [PATCH 567/903] MDl-30667 Course: Maxbytes list will show current
 value, if it's lower then maxbytes

---
 admin/settings/courses.php |    5 +++--
 course/edit_form.php       |    2 +-
 lib/moodlelib.php          |   12 +++++++++++-
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/admin/settings/courses.php b/admin/settings/courses.php
index f07107c..aec5102 100644
--- a/admin/settings/courses.php
+++ b/admin/settings/courses.php
@@ -35,10 +35,11 @@ if ($hassiteconfig
     $temp->add(new admin_setting_configselect('moodlecourse/showgrades', new lang_string('showgrades'), new lang_string('coursehelpshowgrades'), 1,array(0 => new lang_string('no'), 1 => new lang_string('yes'))));
     $temp->add(new admin_setting_configselect('moodlecourse/showreports', new lang_string('showreports'), '', 0,array(0 => new lang_string('no'), 1 => new lang_string('yes'))));
 
+    $currentmaxbytes = get_config('moodlecourse', 'maxbytes');
     if (isset($CFG->maxbytes)) {
-        $choices = get_max_upload_sizes($CFG->maxbytes);
+        $choices = get_max_upload_sizes($CFG->maxbytes, 0, 0, $currentmaxbytes);
     } else {
-        $choices = get_max_upload_sizes();
+        $choices = get_max_upload_sizes(0, 0, 0, $currentmaxbytes);
     }
     $temp->add(new admin_setting_configselect('moodlecourse/maxbytes', new lang_string('maximumupload'), new lang_string('coursehelpmaximumupload'), key($choices), $choices));
 
diff --git a/course/edit_form.php b/course/edit_form.php
index 75380f3..319bdac 100644
--- a/course/edit_form.php
+++ b/course/edit_form.php
@@ -156,7 +156,7 @@ class course_edit_form extends moodleform {
         $mform->addHelpButton('showreports', 'showreports');
         $mform->setDefault('showreports', $courseconfig->showreports);
 
-        $choices = get_max_upload_sizes($CFG->maxbytes);
+        $choices = get_max_upload_sizes($CFG->maxbytes, 0, 0, $course->maxbytes);
         $mform->addElement('select', 'maxbytes', get_string('maximumupload'), $choices);
         $mform->addHelpButton('maxbytes', 'maximumupload');
         $mform->setDefault('maxbytes', $courseconfig->maxbytes);
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 58a6c59..0cefa5e 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -5913,9 +5913,11 @@ function get_user_max_upload_file_size($context, $sitebytes=0, $coursebytes=0, $
  * @param int $sizebytes Set maximum size
  * @param int $coursebytes Current course $course->maxbytes (in bytes)
  * @param int $modulebytes Current module ->maxbytes (in bytes)
+ * @param int|array $custombytes custom upload size/s which will be added to list,
+ *        Only value/s smaller then maxsize will be added to list.
  * @return array
  */
-function get_max_upload_sizes($sitebytes=0, $coursebytes=0, $modulebytes=0) {
+function get_max_upload_sizes($sitebytes = 0, $coursebytes = 0, $modulebytes = 0, $custombytes = null) {
     global $CFG;
 
     if (!$maxsize = get_max_upload_file_size($sitebytes, $coursebytes, $modulebytes)) {
@@ -5927,6 +5929,14 @@ function get_max_upload_sizes($sitebytes=0, $coursebytes=0, $modulebytes=0) {
     $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152,
                       5242880, 10485760, 20971520, 52428800, 104857600);
 
+    // If custombytes is given then add it to the list.
+    if (!is_null($custombytes)) {
+        if (is_number($custombytes)) {
+            $custombytes = array((int)$custombytes);
+        }
+        $sizelist = array_unique(array_merge($sizelist, $custombytes));
+    }
+
     // Allow maxbytes to be selected if it falls outside the above boundaries
     if (isset($CFG->maxbytes) && !in_array(get_real_size($CFG->maxbytes), $sizelist)) {
         // note: get_real_size() is used in order to prevent problems with invalid values
-- 
1.7.9.5


From 70c2ec0ba26041dbebd358285b5b322cc7cd5149 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Tue, 4 Sep 2012 11:01:06 +1200
Subject: [PATCH 568/903] MDL-35208 mod_choice: respect order of options when
 running backup

---
 .../backup/moodle2/backup_choice_stepslib.php      |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mod/choice/backup/moodle2/backup_choice_stepslib.php b/mod/choice/backup/moodle2/backup_choice_stepslib.php
index bd9b0c2..77b2405 100644
--- a/mod/choice/backup/moodle2/backup_choice_stepslib.php
+++ b/mod/choice/backup/moodle2/backup_choice_stepslib.php
@@ -65,8 +65,9 @@ class backup_choice_activity_structure_step extends backup_activity_structure_st
 
         $option->set_source_sql('
             SELECT *
-              FROM {choice_options}
-             WHERE choiceid = ?',
+            FROM {choice_options}
+            WHERE choiceid = ?
+            ORDER BY id',
             array(backup::VAR_PARENTID));
 
         // All the rest of elements only happen if we are including user info
-- 
1.7.9.5


From b91833db8ae962c287030e18ab482c1fb43f8008 Mon Sep 17 00:00:00 2001
From: Simon Coggins <simoncoggins@gmail.com>
Date: Tue, 4 Sep 2012 13:10:02 +1200
Subject: [PATCH 569/903] MDL-34755 SCORM: pop-up not loading in IE7/IE8
 compat mode

---
 mod/scorm/view.js |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/scorm/view.js b/mod/scorm/view.js
index 1fd0a29..e3628ea 100644
--- a/mod/scorm/view.js
+++ b/mod/scorm/view.js
@@ -1,6 +1,6 @@
 M.mod_scormform = {};
 M.mod_scormform.init = function(Y) {
-    var scormform = Y.one('#scormviewform');
+    var scormform = document.getElementById('scormviewform');
     var cwidth = scormplayerdata.cwidth;
     var cheight = scormplayerdata.cheight;
     var poptions = scormplayerdata.popupoptions;
@@ -15,5 +15,5 @@ M.mod_scormform.init = function(Y) {
         }
         poptions = poptions+',width='+cwidth+',height='+cheight;
     }
-    scormform.setAttribute('onsubmit', "window.open('','Popup','"+poptions+"'); this.target='Popup';");
+    scormform.onsubmit = function() {window.open('', 'Popup', poptions); this.target='Popup';};
 }
-- 
1.7.9.5


From d8a640728c48e733f84161078e2f65075d8eb226 Mon Sep 17 00:00:00 2001
From: Tim Lock <tim.lock@netspot.com.au>
Date: Tue, 28 Aug 2012 13:57:35 +0930
Subject: [PATCH 570/903] MDL-35092: Add proxy support to enrol/paypal IPN

---
 enrol/paypal/ipn.php |   22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/enrol/paypal/ipn.php b/enrol/paypal/ipn.php
index b4a6bf4..e5ec7dd 100644
--- a/enrol/paypal/ipn.php
+++ b/enrol/paypal/ipn.php
@@ -34,6 +34,7 @@ require("../../config.php");
 require_once("lib.php");
 require_once($CFG->libdir.'/eventslib.php');
 require_once($CFG->libdir.'/enrollib.php');
+require_once($CFG->libdir . '/filelib.php');
 
 
 /// Keep out casual intruders
@@ -89,14 +90,17 @@ if (! $plugin_instance = $DB->get_record("enrol", array("id"=>$data->instanceid,
 $plugin = enrol_get_plugin('paypal');
 
 /// Open a connection back to PayPal to validate the data
-$header = '';
-$header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
-$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
-$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
+$c = new curl();
+$options = array(
+    'returntransfer' => true,
+    'httpheader' => array('application/x-www-form-urlencoded'),
+    'timeout' => 30,
+);
 $paypaladdr = empty($CFG->usepaypalsandbox) ? 'www.paypal.com' : 'www.sandbox.paypal.com';
-$fp = fsockopen ($paypaladdr, 80, $errno, $errstr, 30);
+$location = "https://$paypaladdr/cgi-bin/webscr";
+$result = $c->post($location, $req, $options);
 
-if (!$fp) {  /// Could not open a socket to PayPal - FAIL
+if (!$result) {  /// Could not connect to PayPal - FAIL
     echo "<p>Error: could not access paypal.com</p>";
     message_paypal_error_to_admin("Could not access paypal.com to verify payment", $data);
     die;
@@ -104,12 +108,9 @@ if (!$fp) {  /// Could not open a socket to PayPal - FAIL
 
 /// Connection is OK, so now we post the data to validate it
 
-fputs ($fp, $header.$req);
-
 /// Now read the response and check if everything is OK.
 
-while (!feof($fp)) {
-    $result = fgets($fp, 1024);
+if (strlen($result) > 0) {
     if (strcmp($result, "VERIFIED") == 0) {          // VALID PAYMENT!
 
 
@@ -296,7 +297,6 @@ while (!feof($fp)) {
     }
 }
 
-fclose($fp);
 exit;
 
 
-- 
1.7.9.5


From fb1b0bc05e7888bcaf88bb3dd1718b74c16600aa Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Thu, 16 Aug 2012 10:53:22 +0800
Subject: [PATCH 571/903] MDL-26504 blog: made it delete external blog posts
 when the external blog is deleted

---
 blog/external_blogs.php |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/blog/external_blogs.php b/blog/external_blogs.php
index 70404c2..8b1d902 100644
--- a/blog/external_blogs.php
+++ b/blog/external_blogs.php
@@ -44,7 +44,16 @@ $message = null;
 if ($delete && confirm_sesskey()) {
     $externalbloguserid = $DB->get_field('blog_external', 'userid', array('id' => $delete));
     if ($externalbloguserid == $USER->id) {
+        // Delete the external blog
         $DB->delete_records('blog_external', array('id' => $delete));
+
+        // Delete the external blog's posts
+        $deletewhere = 'module = :module
+                            AND userid = :userid
+                            AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false) . '
+                            AND ' . $DB->sql_compare_text('content') . ' = ' . $DB->sql_compare_text(':delete');
+        $DB->delete_records_select('post', $deletewhere, array('module' => 'blog_external', 'userid' => $USER->id, 'delete' => $delete));
+
         $message = get_string('externalblogdeleted', 'blog');
     }
 }
-- 
1.7.9.5


From c62ccd747c182e5d1c5f341ec7e96f877b40855d Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 28 Aug 2012 10:41:02 +0800
Subject: [PATCH 572/903] MDL-26504 blog: added upgrade code to remove orphan
 external blog posts

Conflicts:
	lib/db/upgrade.php
	version.php
---
 lib/db/upgrade.php |   10 ++++++++++
 version.php        |    2 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index dcb9f2d..c272539 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -949,5 +949,15 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.08);
     }
 
+    if ($oldversion < 2012062501.13) {
+        $subquery = 'SELECT b.id FROM {blog_external} b where ' . $DB->sql_compare_text('b.id') . ' = ' . $DB->sql_compare_text('{post}.content');
+        $sql = 'DELETE FROM {post}
+                      WHERE {post}.module = \'blog_external\'
+                            AND NOT EXISTS (' . $subquery . ')
+                            AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false);
+        $DB->execute($sql);
+        upgrade_main_savepoint(true, 2012062501.13);
+    }
+
     return true;
 }
diff --git a/version.php b/version.php
index 13f2855..268d9fc 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.12;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.13;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 2f9ac3fe1ee31c3a344ddaa6f211956c9423e9a2 Mon Sep 17 00:00:00 2001
From: Kordan <kordan@mclink.it>
Date: Tue, 4 Sep 2012 09:11:01 +0200
Subject: [PATCH 573/903] MDL-35211 theme_formal_white: updated descriptions
 involved in MDL-34916

---
 theme/formal_white/lang/en/theme_formal_white.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/theme/formal_white/lang/en/theme_formal_white.php b/theme/formal_white/lang/en/theme_formal_white.php
index cb80bc2..0b4746e 100644
--- a/theme/formal_white/lang/en/theme_formal_white.php
+++ b/theme/formal_white/lang/en/theme_formal_white.php
@@ -67,7 +67,7 @@ $string['ctmo_onfrontpageonly'] = 'in the front page only'; // ctmo == credits t
 $string['customcss'] = 'Custom CSS';
 $string['customcssdesc'] = 'Any CSS you enter here will be added to every page allowing your to easily customise this theme.';
 $string['customlogourl'] = 'Custom logo';
-$string['customlogourldesc'] = 'Change the logo for this theme by entering the URL to an image you wish to use (i.e. http://www.yoursite.local/mylogo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
+$string['customlogourldesc'] = 'Change the logo for this theme by entering the full or relatve URL to an image you wish to use (i.e. http://www.yoursite.tld/mylogo.png or ../path/to/your/logo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
 $string['displayheading'] = 'Display page heading';
 $string['displaylogo'] = 'Display logo';
 $string['fontsizereference'] = 'Font size reference';
@@ -77,7 +77,7 @@ $string['footnotedesc'] = 'The content from this textarea will be displayed in t
 $string['framemargin'] = 'Frame margin';
 $string['framemargindesc'] = 'Room between the frame and the edge of the browser window. (This setting will be ignored if "{$a}" is requested).';
 $string['frontpagelogourl'] = 'Custom front page logo';
-$string['frontpagelogourldesc'] = 'Change the logo that is displayed on the front page of your site by entering the URL to the image you wish to use (i.e. http://www.yoursite.local/myfrontpagelogo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
+$string['frontpagelogourldesc'] = 'Change the logo that is displayed on the front page of your site by entering the full or relatve URL to the image you wish to use (i.e. http://www.yoursite.tld/myfrontpagelogo.png or ../path/to/your/logo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
 $string['headerbgc'] = 'Header background colour';
 $string['headerbgcdesc'] = 'This sets the blocks header background colour for the theme.';
 $string['headercontent'] = 'Header content';
-- 
1.7.9.5


From e765d3c396e8818dd50c232e589ddccb7efae5dc Mon Sep 17 00:00:00 2001
From: Kordan <kordan@mclink.it>
Date: Tue, 4 Sep 2012 09:49:51 +0200
Subject: [PATCH 574/903] MDL-34916 theme_formal_white: added support for
 relative path of logos

---
 theme/formal_white/layout/frontpage.php |    3 +++
 theme/formal_white/layout/general.php   |    3 +++
 theme/formal_white/layout/report.php    |    3 +++
 theme/formal_white/settings.php         |    4 ++--
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/theme/formal_white/layout/frontpage.php b/theme/formal_white/layout/frontpage.php
index 29644e1..3f577e6 100644
--- a/theme/formal_white/layout/frontpage.php
+++ b/theme/formal_white/layout/frontpage.php
@@ -36,6 +36,9 @@ if (!empty($PAGE->theme->settings->frontpagelogourl)) {
 } else {
     $logourl = $OUTPUT->pix_url('logo', 'theme');
 }
+if (strtolower(substr($logourl, 0, 4)) != 'http') {
+    $logourl = $CFG->wwwroot.'/'.$logourl;
+}
 
 $hasframe = !isset($PAGE->theme->settings->noframe) || !$PAGE->theme->settings->noframe;
 
diff --git a/theme/formal_white/layout/general.php b/theme/formal_white/layout/general.php
index 3cebe1c..31e373e 100644
--- a/theme/formal_white/layout/general.php
+++ b/theme/formal_white/layout/general.php
@@ -31,6 +31,9 @@ if ($hascustommenu) {
 /************************************************************************************************/
 if (!empty($PAGE->theme->settings->customlogourl)) {
     $logourl = $PAGE->theme->settings->customlogourl;
+    if (strtolower(substr($logourl, 0, 4)) != 'http') {
+        $logourl = $CFG->wwwroot.'/'.$logourl;
+    }
 } else {
     $logourl = $OUTPUT->pix_url('logo_small', 'theme');
 }
diff --git a/theme/formal_white/layout/report.php b/theme/formal_white/layout/report.php
index 9bb7ca1..ed64bd7 100644
--- a/theme/formal_white/layout/report.php
+++ b/theme/formal_white/layout/report.php
@@ -26,6 +26,9 @@ if ($hascustommenu) {
 /************************************************************************************************/
 if (!empty($PAGE->theme->settings->customlogourl)) {
     $logourl = $PAGE->theme->settings->customlogourl;
+    if (strtolower(substr($logourl, 0, 4)) != 'http') {
+        $logourl = $CFG->wwwroot.'/'.$logourl;
+    }
 } else {
     $logourl = $OUTPUT->pix_url('logo_small', 'theme');
 }
diff --git a/theme/formal_white/settings.php b/theme/formal_white/settings.php
index 81db472..67938d0 100644
--- a/theme/formal_white/settings.php
+++ b/theme/formal_white/settings.php
@@ -47,7 +47,7 @@ if ($ADMIN->fulltree) {
     $title = get_string('customlogourl','theme_formal_white');
     $description = get_string('customlogourldesc', 'theme_formal_white');
     $default = '';
-    $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
+    $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_RAW); // we want it accepting ../ at the beginning. Security is not at its top but Moodle trusts admins.
     $settings->add($setting);
 
     // Custom front page site logo setting
@@ -55,7 +55,7 @@ if ($ADMIN->fulltree) {
     $title = get_string('frontpagelogourl','theme_formal_white');
     $description = get_string('frontpagelogourldesc', 'theme_formal_white');
     $default = '';
-    $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
+    $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_RAW); // we want it accepting ../ at the beginning. Security is not at its top but Moodle trusts admins.
     $settings->add($setting);
 
     // page header background colour setting
-- 
1.7.9.5


From 7c4fc5b50b6e632bd62b626c5403df4b7d55f5b5 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 21 Aug 2012 17:40:03 +0800
Subject: [PATCH 575/903] MDL-34945 Repository: Creating an instance requires
 the user to have the permission to view it

---
 repository/lib.php              |    6 ++++++
 repository/manage_instances.php |   16 ++++++++++------
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/repository/lib.php b/repository/lib.php
index 10f3081..b416284 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -1515,6 +1515,12 @@ abstract class repository {
             $types = repository::get_editable_types($context);
             foreach ($types as $type) {
                 if (!empty($type) && $type->get_visible()) {
+                    // If the user does not have the permission to view the repository, it won't be displayed in
+                    // the list of instances. Hiding the link to create new instances will prevent the
+                    // user from creating them without being able to find them afterwards, which looks like a bug.
+                    if (!has_capability('repository/'.$type->get_typename().':view', $context)) {
+                        continue;
+                    }
                     $instanceoptionnames = repository::static_function($type->get_typename(), 'get_instance_option_names');
                     if (!empty($instanceoptionnames)) {
                         $baseurl->param('new', $type->get_typename());
diff --git a/repository/manage_instances.php b/repository/manage_instances.php
index 5b5d1c8..e3b0dc9 100644
--- a/repository/manage_instances.php
+++ b/repository/manage_instances.php
@@ -106,12 +106,16 @@ if (!empty($new)){
     $type = repository::get_type_by_id($instance->options['typeid']);
 }
 
-if (isset($type) && !$type->get_visible()) {
-    print_error('typenotvisible', 'repository', $baseurl);
-}
-
-if (isset($type) && !$type->get_contextvisibility($context)) {
-    print_error('usercontextrepositorydisabled', 'repository', $baseurl);
+if (isset($type)) {
+    if (!$type->get_visible()) {
+        print_error('typenotvisible', 'repository', $baseurl);
+    }
+    // Prevents the user from creating/editing an instance if the repository is not visible in
+    // this context OR if the user does not have the capability to view this repository in this context.
+    $canviewrepository = has_capability('repository/'.$type->get_typename().':view', $context);
+    if (!$type->get_contextvisibility($context) || !$canviewrepository) {
+        print_error('usercontextrepositorydisabled', 'repository', $baseurl);
+    }
 }
 
 /// Create navigation links
-- 
1.7.9.5


From 4d48a651592ab18f63f78120fc73bec5ac6a0947 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Wed, 5 Sep 2012 12:44:18 +1200
Subject: [PATCH 576/903] MDL-35255 mod_assign plagiarism api shift
 update_status call to after header has been
 printed.

---
 mod/assign/locallib.php |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index a933ab5..e1e5104 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -1762,6 +1762,11 @@ class assign {
         $gradingoptionsdata->filter = $filter;
         $gradingoptionsform->set_data($gradingoptionsdata);
 
+        $actionformtext = $this->output->render($gradingactions);
+        $o .= $this->output->render(new assign_header($this->get_instance(),
+                                                      $this->get_context(), false, $this->get_course_module()->id, get_string('grading', 'assign'), $actionformtext));
+        $o .= groups_print_activity_menu($this->get_course_module(), $CFG->wwwroot . '/mod/assign/view.php?id=' . $this->get_course_module()->id.'&action=grading', true);
+
         // plagiarism update status apearring in the grading book
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
@@ -1769,12 +1774,6 @@ class assign {
             $o .= plagiarism_update_status($this->get_course(), $this->get_course_module());
         }
 
-        $actionformtext = $this->output->render($gradingactions);
-        $o .= $this->output->render(new assign_header($this->get_instance(),
-                                                      $this->get_context(), false, $this->get_course_module()->id, get_string('grading', 'assign'), $actionformtext));
-        $o .= groups_print_activity_menu($this->get_course_module(), $CFG->wwwroot . '/mod/assign/view.php?id=' . $this->get_course_module()->id.'&action=grading', true);
-
-
         // load and print the table of submissions
         if ($showquickgrading && $quickgrading) {
             $table = $this->output->render(new assign_grading_table($this, $perpage, $filter, 0, true));
-- 
1.7.9.5


From a334d8f96701f7399017ec10533bb67403750792 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Wed, 5 Sep 2012 10:16:35 +0800
Subject: [PATCH 577/903] MDL-26504 blog: fixed SQL to add explicit casting

Conflicts:

	lib/db/upgrade.php
	version.php
---
 lib/db/upgrade.php |    6 +++---
 version.php        |    2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index c272539..83c7370 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -949,14 +949,14 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.08);
     }
 
-    if ($oldversion < 2012062501.13) {
-        $subquery = 'SELECT b.id FROM {blog_external} b where ' . $DB->sql_compare_text('b.id') . ' = ' . $DB->sql_compare_text('{post}.content');
+    if ($oldversion < 2012062501.14) {
+        $subquery = 'SELECT b.id FROM {blog_external} b where b.id = ' . $DB->sql_cast_char2int('{post}.content', true);
         $sql = 'DELETE FROM {post}
                       WHERE {post}.module = \'blog_external\'
                             AND NOT EXISTS (' . $subquery . ')
                             AND ' . $DB->sql_isnotempty('post', 'uniquehash', false, false);
         $DB->execute($sql);
-        upgrade_main_savepoint(true, 2012062501.13);
+        upgrade_main_savepoint(true, 2012062501.14);
     }
 
     return true;
diff --git a/version.php b/version.php
index 268d9fc..a149a37 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.13;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.14;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From e4e29fd35e636afd602bacfebefa4e687775aee9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Wed, 5 Sep 2012 10:01:30 +0200
Subject: [PATCH 578/903] MDL-35077 do not show link to system stats report if
 stats disabled

---
 report/stats/settings.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/report/stats/settings.php b/report/stats/settings.php
index c92ec33..0644538 100644
--- a/report/stats/settings.php
+++ b/report/stats/settings.php
@@ -26,7 +26,7 @@
 defined('MOODLE_INTERNAL') || die;
 
 // just a link to course report
-$ADMIN->add('reports', new admin_externalpage('reportstats', get_string('pluginname', 'report_stats'), "$CFG->wwwroot/report/stats/index.php", 'report/stats:view'));
+$ADMIN->add('reports', new admin_externalpage('reportstats', get_string('pluginname', 'report_stats'), "$CFG->wwwroot/report/stats/index.php", 'report/stats:view', empty($CFG->enablestats)));
 
 // no report settings
 $settings = null;
-- 
1.7.9.5


From 3f4e07ef3c8bbe7ecd75db18c73348d6ac64d682 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 5 Sep 2012 18:01:24 +0200
Subject: [PATCH 579/903] MDL-29662 quiz overrides: use proper course value
 (was php notice).

---
 mod/quiz/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 4bb7494..be061bb 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1153,7 +1153,7 @@ function quiz_update_events($quiz, $override = null) {
         if (!empty($quiz->coursemodule)) {
             $cmid = $quiz->coursemodule;
         } else {
-            $cmid = get_coursemodule_from_instance('quiz', $quiz->id, $courseid)->id;
+            $cmid = get_coursemodule_from_instance('quiz', $quiz->id, $quiz->course)->id;
         }
 
         $event = new stdClass();
-- 
1.7.9.5


From a66863c357c2d7c901d669f80d58bfa782d10495 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Thu, 6 Sep 2012 11:15:56 +0800
Subject: [PATCH 580/903] MDL-35190 random failures in course externallib test

---
 course/tests/externallib_test.php |   78 ++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 32 deletions(-)

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index 08f8b4a..984b9ed 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -165,20 +165,28 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         global $DB;
 
         $this->resetAfterTest(true);
+
+        $generatedcats = array();
         $category1data['idnumber'] = 'idnumbercat1';
         $category1data['name'] = 'Category 1 for PHPunit test';
         $category1data['description'] = 'Category 1 description';
         $category1data['descriptionformat'] = FORMAT_MOODLE;
         $category1  = self::getDataGenerator()->create_category($category1data);
+        $generatedcats[$category1->id] = $category1;
         $category2  = self::getDataGenerator()->create_category(
                 array('parent' => $category1->id));
+        $generatedcats[$category2->id] = $category2;
         $category6  = self::getDataGenerator()->create_category(
                 array('parent' => $category1->id, 'visible' => 0));
+        $generatedcats[$category6->id] = $category6;
         $category3  = self::getDataGenerator()->create_category();
+        $generatedcats[$category3->id] = $category3;
         $category4  = self::getDataGenerator()->create_category(
                 array('parent' => $category3->id));
+        $generatedcats[$category4->id] = $category4;
         $category5  = self::getDataGenerator()->create_category(
                 array('parent' => $category4->id));
+        $generatedcats[$category5->id] = $category5;
 
         // Set the required capabilities by the external function.
         $context = context_system::instance();
@@ -193,11 +201,13 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         $this->assertEquals(2, count($categories));
 
         // Check the return values
-        $this->assertEquals($categories[0]['id'], $category1->id);
-        $this->assertEquals($categories[0]['idnumber'], $category1->idnumber);
-        $this->assertEquals($categories[0]['name'], $category1->name);
-        $this->assertEquals($categories[0]['description'], $category1->description);
-        $this->assertEquals($categories[0]['descriptionformat'], FORMAT_HTML);
+        foreach ($categories as $category) {
+            $generatedcat = $generatedcats[$category['id']];
+            $this->assertEquals($category['idnumber'], $generatedcat->idnumber);
+            $this->assertEquals($category['name'], $generatedcat->name);
+            $this->assertEquals($category['description'], $generatedcat->description);
+            $this->assertEquals($category['descriptionformat'], FORMAT_HTML);
+        }
 
         // Check different params.
         $categories = core_course_external::get_categories(array(
@@ -440,13 +450,17 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         $this->resetAfterTest(true);
 
+        $generatedcourses = array();
         $coursedata['idnumber'] = 'idnumbercourse1';
         $coursedata['fullname'] = 'Course 1 for PHPunit test';
         $coursedata['summary'] = 'Course 1 description';
         $coursedata['summaryformat'] = FORMAT_MOODLE;
         $course1  = self::getDataGenerator()->create_course($coursedata);
+        $generatedcourses[$course1->id] = $course1;
         $course2  = self::getDataGenerator()->create_course();
+        $generatedcourses[$course2->id] = $course2;
         $course3  = self::getDataGenerator()->create_course();
+        $generatedcourses[$course3->id] = $course3;
 
         // Set the required capabilities by the external function.
         $context = context_system::instance();
@@ -464,33 +478,33 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         // Check we retrieve the good total number of categories.
         $this->assertEquals(2, count($courses));
 
-        // Check the return values for course 1
-        $dbcourse = $DB->get_record('course', array('id' => $course1->id));
-        $this->assertEquals($courses[0]['id'], $dbcourse->id);
-        $this->assertEquals($courses[0]['idnumber'], $coursedata['idnumber']);
-        $this->assertEquals($courses[0]['fullname'], $coursedata['fullname']);
-        $this->assertEquals($courses[0]['summary'], $coursedata['summary']);
-        $this->assertEquals($courses[0]['summaryformat'], FORMAT_HTML);
-        $this->assertEquals($courses[0]['shortname'], $dbcourse->shortname);
-        $this->assertEquals($courses[0]['categoryid'], $dbcourse->category);
-        $this->assertEquals($courses[0]['format'], $dbcourse->format);
-        $this->assertEquals($courses[0]['showgrades'], $dbcourse->showgrades);
-        $this->assertEquals($courses[0]['newsitems'], $dbcourse->newsitems);
-        $this->assertEquals($courses[0]['startdate'], $dbcourse->startdate);
-        $this->assertEquals($courses[0]['numsections'], $dbcourse->numsections);
-        $this->assertEquals($courses[0]['maxbytes'], $dbcourse->maxbytes);
-        $this->assertEquals($courses[0]['showreports'], $dbcourse->showreports);
-        $this->assertEquals($courses[0]['visible'], $dbcourse->visible);
-        $this->assertEquals($courses[0]['hiddensections'], $dbcourse->hiddensections);
-        $this->assertEquals($courses[0]['groupmode'], $dbcourse->groupmode);
-        $this->assertEquals($courses[0]['groupmodeforce'], $dbcourse->groupmodeforce);
-        $this->assertEquals($courses[0]['defaultgroupingid'], $dbcourse->defaultgroupingid);
-        $this->assertEquals($courses[0]['completionnotify'], $dbcourse->completionnotify);
-        $this->assertEquals($courses[0]['lang'], $dbcourse->lang);
-        $this->assertEquals($courses[0]['forcetheme'], $dbcourse->theme);
-        $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
-        $this->assertEquals($courses[0]['enablecompletion'], $dbcourse->enablecompletion);
-        $this->assertEquals($courses[0]['completionstartonenrol'], $dbcourse->completionstartonenrol);
+        foreach ($courses as $course) {
+            $dbcourse = $generatedcourses[$course['id']];
+            $this->assertEquals($course['idnumber'], $dbcourse->idnumber);
+            $this->assertEquals($course['fullname'], $dbcourse->fullname);
+            $this->assertEquals($course['summary'], $dbcourse->summary);
+            $this->assertEquals($course['summaryformat'], FORMAT_HTML);
+            $this->assertEquals($course['shortname'], $dbcourse->shortname);
+            $this->assertEquals($course['categoryid'], $dbcourse->category);
+            $this->assertEquals($course['format'], $dbcourse->format);
+            $this->assertEquals($course['showgrades'], $dbcourse->showgrades);
+            $this->assertEquals($course['newsitems'], $dbcourse->newsitems);
+            $this->assertEquals($course['startdate'], $dbcourse->startdate);
+            $this->assertEquals($course['numsections'], $dbcourse->numsections);
+            $this->assertEquals($course['maxbytes'], $dbcourse->maxbytes);
+            $this->assertEquals($course['showreports'], $dbcourse->showreports);
+            $this->assertEquals($course['visible'], $dbcourse->visible);
+            $this->assertEquals($course['hiddensections'], $dbcourse->hiddensections);
+            $this->assertEquals($course['groupmode'], $dbcourse->groupmode);
+            $this->assertEquals($course['groupmodeforce'], $dbcourse->groupmodeforce);
+            $this->assertEquals($course['defaultgroupingid'], $dbcourse->defaultgroupingid);
+            $this->assertEquals($course['completionnotify'], $dbcourse->completionnotify);
+            $this->assertEquals($course['lang'], $dbcourse->lang);
+            $this->assertEquals($course['forcetheme'], $dbcourse->theme);
+            $this->assertEquals($course['completionstartonenrol'], $dbcourse->completionstartonenrol);
+            $this->assertEquals($course['enablecompletion'], $dbcourse->enablecompletion);
+            $this->assertEquals($course['completionstartonenrol'], $dbcourse->completionstartonenrol);
+        }
 
         // Get all courses in the DB
         $courses = core_course_external::get_courses(array());
-- 
1.7.9.5


From fa3a1652bf10cfd4d3c5b0c3f6d24df940f11239 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Thu, 6 Sep 2012 18:45:02 +1200
Subject: [PATCH 581/903] MDL-35123 SCORM: cleaner version of get_last_attempt
 and get_last_completed_attempt, fixes support for
 MS Sql driver

---
 mod/scorm/locallib.php |   47 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php
index 6021912..19e6061 100644
--- a/mod/scorm/locallib.php
+++ b/mod/scorm/locallib.php
@@ -646,33 +646,50 @@ function scorm_count_launchable($scormid, $organization='') {
     return $DB->count_records_select('scorm_scoes', "scorm = ? $sqlorganization AND ".$DB->sql_isnotempty('scorm_scoes', 'launch', false, true), $params);
 }
 
+/**
+ * Returns the last attempt used - if no attempts yet, returns 1 for first attempt
+ *
+ * @param int $scormid the id of the scorm.
+ * @param int $userid the id of the user.
+ *
+ * @return int The attempt number to use.
+ */
 function scorm_get_last_attempt($scormid, $userid) {
     global $DB;
 
     /// Find the last attempt number for the given user id and scorm id
-    if ($lastattempt = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid), 'max(attempt) as a')) {
-        if (empty($lastattempt->a)) {
-            return '1';
-        } else {
-            return $lastattempt->a;
-        }
+    $sql = "SELECT MAX(attempt)
+              FROM {scorm_scoes_track}
+             WHERE userid = ? AND scormid = ?";
+    $lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
+    if (empty($lastattempt)) {
+        return '1';
     } else {
-        return false;
+        return $lastattempt;
     }
 }
 
+/**
+ * Returns the last completed attempt used - if no completed attempts yet, returns 1 for first attempt
+ *
+ * @param int $scormid the id of the scorm.
+ * @param int $userid the id of the user.
+ *
+ * @return int The attempt number to use.
+ */
 function scorm_get_last_completed_attempt($scormid, $userid) {
     global $DB;
 
-    /// Find the last attempt number for the given user id and scorm id
-    if ($lastattempt = $DB->get_record_select('scorm_scoes_track', "userid = ? AND scormid = ? AND (value='completed' OR value='passed')", array($userid, $scormid), 'max(attempt) as a')) {
-        if (empty($lastattempt->a)) {
-            return '1';
-        } else {
-            return $lastattempt->a;
-        }
+    /// Find the last completed attempt number for the given user id and scorm id
+    $sql = "SELECT MAX(attempt)
+              FROM {scorm_scoes_track}
+             WHERE userid = ? AND scormid = ?
+               AND (value='completed' OR value='passed')";
+    $lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
+    if (empty($lastattempt)) {
+        return '1';
     } else {
-        return false;
+        return $lastattempt;
     }
 }
 
-- 
1.7.9.5


From 155fd3f64baf059a02aa9886ee3dfb85901c1bf9 Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Mon, 20 Aug 2012 13:56:56 +0800
Subject: [PATCH 582/903] MDL-6424 - blocks - Adding a warning screen when the
 user clicks the delete link.

Conflicts:
	lib/blocklib.php
---
 lang/en/block.php |    2 ++
 lib/blocklib.php  |   56 +++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/lang/en/block.php b/lang/en/block.php
index c0b8f01..a685f0e 100644
--- a/lang/en/block.php
+++ b/lang/en/block.php
@@ -37,6 +37,8 @@ $string['defaultregion'] = 'Default region';
 $string['defaultregion_help'] = 'Themes may define one or more named block regions where blocks are displayed. This setting defines which of these you want this block to appear in by default. The region may be overridden on specific pages if required.';
 $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['deleteblockcheck'] = 'Are you sure that you want to delete this block titled {$a}?';
 $string['moveblockhere'] = 'Move block here';
 $string['movingthisblockcancel'] = 'Moving this block ({$a})';
 $string['onthispage'] = 'On this page';
diff --git a/lib/blocklib.php b/lib/blocklib.php
index b41b67c..1e34a36 100644
--- a/lib/blocklib.php
+++ b/lib/blocklib.php
@@ -1114,25 +1114,65 @@ class block_manager {
      * @return boolean true if anything was done. False if not.
      */
     public function process_url_delete() {
-        $blockid = optional_param('bui_deleteid', null, PARAM_INTEGER);
+        global $CFG;
+
+        $blockid = optional_param('bui_deleteid', null, PARAM_INT);
+        $confirmdelete = optional_param('bui_confirm', null, PARAM_INT);
+
         if (!$blockid) {
             return false;
         }
 
         require_sesskey();
-
         $block = $this->page->blocks->find_instance($blockid);
-
         if (!$block->user_can_edit() || !$this->page->user_can_edit_blocks() || !$block->user_can_addto($this->page)) {
             throw new moodle_exception('nopermissions', '', $this->page->url->out(), get_string('deleteablock'));
         }
 
-        blocks_delete_instance($block->instance);
-
-        // If the page URL was a guess, it will contain the bui_... param, so we must make sure it is not there.
-        $this->page->ensure_param_not_in_url('bui_deleteid');
+        if (!$confirmdelete) {
+            $deletepage = new moodle_page();
+            $deletepage->set_pagelayout('admin');
+            $deletepage->set_course($this->page->course);
+            $deletepage->set_context($this->page->context);
+            if ($this->page->cm) {
+                $deletepage->set_cm($this->page->cm);
+            }
 
-        return true;
+            $deleteurlbase = str_replace($CFG->wwwroot . '/', '/', $this->page->url->out_omit_querystring());
+            $deleteurlparams = $this->page->url->params();
+            $deletepage->set_url($deleteurlbase, $deleteurlparams);
+            $deletepage->set_block_actions_done();
+            // At this point we are either going to redirect, or display the form, so
+            // overwrite global $PAGE ready for this. (Formslib refers to it.)
+            $PAGE = $deletepage;
+            //some functions like MoodleQuickForm::addHelpButton use $OUTPUT so we need to replace that too
+            $output = $deletepage->get_renderer('core');
+            $OUTPUT = $output;
+
+            $site = get_site();
+            $blocktitle = $block->get_title();
+            $strdeletecheck = get_string('deletecheck', 'block', $blocktitle);
+            $message = get_string('deleteblockcheck', 'block', $blocktitle);
+
+            $PAGE->navbar->add($strdeletecheck);
+            $PAGE->set_title($blocktitle . ': ' . $strdeletecheck);
+            $PAGE->set_heading($site->fullname);
+            echo $OUTPUT->header();
+            $confirmurl = new moodle_url("$deletepage->url?", array('sesskey' => sesskey(), 'bui_deleteid' => $block->instance->id, 'bui_confirm' => 1));
+            $cancelurl = new moodle_url($deletepage->url);
+            $yesbutton = new single_button($confirmurl, get_string('yes'));
+            $nobutton = new single_button($cancelurl, get_string('no'));
+            echo $OUTPUT->confirm($message, $yesbutton, $nobutton);
+            echo $OUTPUT->footer();
+            // Make sure that nothing else happens after we have displayed this form.
+            exit;
+        } else {
+            blocks_delete_instance($block->instance);
+            // bui_deleteid and bui_confirm should not be in the PAGE url.
+            $this->page->ensure_param_not_in_url('bui_deleteid');
+            $this->page->ensure_param_not_in_url('bui_confirm');
+            return true;
+        }
     }
 
     /**
-- 
1.7.9.5


From 9d2926a4e9985b42eb7da49f42196922b477b5bb Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 6 Sep 2012 19:39:49 +0200
Subject: [PATCH 583/903] MDL-6424 - blocks - Add missing global vars.

---
 lib/blocklib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/blocklib.php b/lib/blocklib.php
index 1e34a36..1986c09 100644
--- a/lib/blocklib.php
+++ b/lib/blocklib.php
@@ -1114,7 +1114,7 @@ class block_manager {
      * @return boolean true if anything was done. False if not.
      */
     public function process_url_delete() {
-        global $CFG;
+        global $CFG, $PAGE, $OUTPUT;
 
         $blockid = optional_param('bui_deleteid', null, PARAM_INT);
         $confirmdelete = optional_param('bui_confirm', null, PARAM_INT);
-- 
1.7.9.5


From ba1d10c50008c02b821f64f3c9186da07ba7ea83 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 7 Sep 2012 00:35:10 +0000
Subject: [PATCH 584/903] Automatically generated installer lang files

---
 install/lang/pl/install.php |    1 +
 install/lang/ru/install.php |    1 +
 2 files changed, 2 insertions(+)

diff --git a/install/lang/pl/install.php b/install/lang/pl/install.php
index 28adfbc..22d60fc 100644
--- a/install/lang/pl/install.php
+++ b/install/lang/pl/install.php
@@ -41,6 +41,7 @@ $string['dataroot'] = 'Katalog z danymi';
 $string['dbprefix'] = 'Prefiks tabel';
 $string['dirroot'] = 'Katalog Moodle';
 $string['environmenthead'] = 'Sprawdzam środowisko (ustawienia) ...';
+$string['environmentsub2'] = 'Każde wydanie Moodle ma pewne minimalne wymagania wersji PHP i pewną liczbę obowiązkowych rozszerzeń PHP. Pełna kontrola środowiska odbywa się przed każdą instalacją i aktualizacją. Prosimy o kontakt z administratorem serwera, jeśli nie wiesz jak zainstalować nową wersję lub włączyć rozszerzenie PHP.';
 $string['errorsinenvironment'] = 'Kontrola środowiska zakończona niepowodzeniem!';
 $string['installation'] = 'Instalacja';
 $string['langdownloaderror'] = 'Niestety język "{$a}" nie może zostać pobrany. Proces instalacji będzie kontynuowany w języku angielskim.';
diff --git a/install/lang/ru/install.php b/install/lang/ru/install.php
index bc06968..e16259e 100644
--- a/install/lang/ru/install.php
+++ b/install/lang/ru/install.php
@@ -40,6 +40,7 @@ $string['databasehost'] = 'Сервер баз данных';
 $string['databasename'] = 'Название базы данных';
 $string['databasetypehead'] = 'Выберите драйвер базы данных';
 $string['dataroot'] = 'Каталог данных';
+$string['datarootpermission'] = 'Разрешения на каталоги данных';
 $string['dbprefix'] = 'Префикс имён таблиц';
 $string['dirroot'] = 'Каталог Moodle';
 $string['environmenthead'] = 'Проверка среды...';
-- 
1.7.9.5


From 71e12dc9630c9463bc2ca13284dd9055b8c891c3 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 7 Sep 2012 02:38:46 +0200
Subject: [PATCH 585/903] weekly release 2.3.1+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index a149a37..928a90f 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.14;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.15;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120831)'; // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120907)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From f4671476ff0fcc6202d867caa051e56215014424 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Tue, 4 Sep 2012 10:29:37 +0800
Subject: [PATCH 586/903] MDL-34338: renderer for mod_folder should not use
 file_info

---
 mod/folder/renderer.php |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/mod/folder/renderer.php b/mod/folder/renderer.php
index 539affe..a321cdf 100644
--- a/mod/folder/renderer.php
+++ b/mod/folder/renderer.php
@@ -60,24 +60,26 @@ class mod_folder_renderer extends plugin_renderer_base {
         $result = '<ul>';
         foreach ($dir['subdirs'] as $subdir) {
             $image = $this->output->pix_icon(file_folder_icon(24), $subdir['dirname'], 'moodle');
-            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', s($subdir['dirname']), array('class' => 'fp-filename'));
+            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')).
+                    html_writer::tag('span', s($subdir['dirname']), array('class' => 'fp-filename'));
             $filename = html_writer::tag('div', $filename, array('class' => 'fp-filename-icon'));
             $result .= html_writer::tag('li', $filename. $this->htmllize_tree($tree, $subdir));
         }
         foreach ($dir['files'] as $file) {
-            $fileinfo = $browser->get_file_info($tree->context, $file->get_component(),
-                    $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
-            $url = $fileinfo->get_url(true);
             $filename = $file->get_filename();
-            if ($imageinfo = $fileinfo->get_imageinfo()) {
-                $fileurl = new moodle_url($fileinfo->get_url());
-                $image = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
+            $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(),
+                    $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $filename, false);
+            if (file_extension_in_typegroup($filename, 'web_image')) {
+                $image = $url->out(false, array('preview' => 'tinyicon', 'oid' => $file->get_timemodified()));
                 $image = html_writer::empty_tag('img', array('src' => $image));
             } else {
                 $image = $this->output->pix_icon(file_file_icon($file, 24), $filename, 'moodle');
             }
-            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). html_writer::tag('span', $filename, array('class' => 'fp-filename'));
-            $filename = html_writer::tag('span', html_writer::link($url, $filename), array('class' => 'fp-filename-icon'));
+            $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')).
+                    html_writer::tag('span', $filename, array('class' => 'fp-filename'));
+            $filename = html_writer::tag('span',
+                    html_writer::link($url->out(false, array('forcedownload' => 1)), $filename),
+                    array('class' => 'fp-filename-icon'));
             $result .= html_writer::tag('li', $filename);
         }
         $result .= '</ul>';
-- 
1.7.9.5


From 6d89ac64ab1f3722cca5065e828c7506adc0ecb2 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 6 Sep 2012 11:28:45 +0800
Subject: [PATCH 587/903] MDL-35223 book: use chapter names in page titles

---
 mod/book/view.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mod/book/view.php b/mod/book/view.php
index 26d5ac0..f5643d3 100644
--- a/mod/book/view.php
+++ b/mod/book/view.php
@@ -114,7 +114,8 @@ $strbook  = get_string('modulename', 'mod_book');
 $strtoc   = get_string('toc', 'mod_book');
 
 // prepare header
-$PAGE->set_title($book->name);
+$pagetitle = $book->name . ": " . $chapter->title;
+$PAGE->set_title($pagetitle);
 $PAGE->set_heading($course->fullname);
 
 book_add_fake_block($chapters, $chapter, $book, $cm, $edit);
-- 
1.7.9.5


From 41b997b1fff323ab2f91e3b0c6743d2baef36927 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 4 Sep 2012 11:56:21 +0800
Subject: [PATCH 588/903] MDL-35007 book: Adding rule to parse links to book
 chapters from 1.9 backups

Conflicts:

	mod/book/version.php
---
 .../moodle2/restore_book_activity_task.class.php   |    3 ++-
 mod/book/version.php                               |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/mod/book/backup/moodle2/restore_book_activity_task.class.php b/mod/book/backup/moodle2/restore_book_activity_task.class.php
index d9ee50e..3755f68 100644
--- a/mod/book/backup/moodle2/restore_book_activity_task.class.php
+++ b/mod/book/backup/moodle2/restore_book_activity_task.class.php
@@ -82,8 +82,9 @@ class restore_book_activity_task extends restore_activity_task {
         $rules[] = new restore_decode_rule('BOOKVIEWBYB', '/mod/book/view.php?b=$1', 'book');
         $rules[] = new restore_decode_rule('BOOKVIEWBYBCH', '/mod/book/view.php?b=$1&amp;chapterid=$2', array('book', 'book_chapter'));
 
-        // Convert old book links MDL-33362
+        // Convert old book links MDL-33362 & MDL-35007
         $rules[] = new restore_decode_rule('BOOKSTART', '/mod/book/view.php?id=$1', 'course_module');
+        $rules[] = new restore_decode_rule('BOOKCHAPTER', '/mod/book/view.php?id=$1&amp;chapterid=$2', array('course_module', 'book_chapter'));
 
         return $rules;
     }
diff --git a/mod/book/version.php b/mod/book/version.php
index 84a1638..e187cb3 100644
--- a/mod/book/version.php
+++ b/mod/book/version.php
@@ -25,6 +25,6 @@
 defined('MOODLE_INTERNAL') || die;
 
 $module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version   = 2012061701; // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061702; // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700; // Requires this Moodle version
 $module->cron      = 0;          // Period for cron to check this module (secs)
-- 
1.7.9.5


From bb7f95f830c24226fb423b17eeb9b9c7daffe5e0 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 4 Sep 2012 11:12:22 +0800
Subject: [PATCH 589/903] MDL-34944 book: Implementing reset framework for
 book

---
 mod/book/lib.php |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mod/book/lib.php b/mod/book/lib.php
index 4c3cde3..b6307f7 100644
--- a/mod/book/lib.php
+++ b/mod/book/lib.php
@@ -167,6 +167,15 @@ function book_print_recent_activity($course, $viewfullnames, $timestart) {
 }
 
 /**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function book_reset_userdata($data) {
+    return array();
+}
+
+/**
  * No cron in book.
  *
  * @return bool
-- 
1.7.9.5


From 800abd6faf700bf2fb732d09a7e8abf4decb0d51 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 3 Sep 2012 16:37:44 +0800
Subject: [PATCH 590/903] MDL-33374 profile: Use correct text for buttons when
 creating a new user

---
 lang/en/moodle.php         |    1 +
 user/editadvanced_form.php |    8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index a3d28ab..a5dd05a 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -363,6 +363,7 @@ $string['createaccount'] = 'Create my new account';
 $string['createcategory'] = 'Create category';
 $string['createfolder'] = 'Create a folder in {$a}';
 $string['createuserandpass'] = 'Choose your username and password';
+$string['createuser'] = 'Create user';
 $string['createziparchive'] = 'Create zip archive';
 $string['creatingblocks'] = 'Creating blocks';
 $string['creatingblocksroles'] = 'Creating block level role assignments and overrides';
diff --git a/user/editadvanced_form.php b/user/editadvanced_form.php
index dbe6d82..400d9d3 100644
--- a/user/editadvanced_form.php
+++ b/user/editadvanced_form.php
@@ -72,7 +72,13 @@ class user_editadvanced_form extends moodleform {
         /// Next the customisable profile fields
         profile_definition($mform, $userid);
 
-        $this->add_action_buttons(false, get_string('updatemyprofile'));
+        if ($userid == -1) {
+            $btnstring = get_string('createuser');
+        } else {
+            $btnstring = get_string('updatemyprofile');
+        }
+
+        $this->add_action_buttons(false, $btnstring);
     }
 
     function definition_after_data() {
-- 
1.7.9.5


From e81507f6b6e4af2bd86b495dfc57968a877026ea Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 6 Sep 2012 11:10:45 +0800
Subject: [PATCH 591/903] MDL-27786 calendar: Changing the eventname string
 for accessibility

---
 lang/en/calendar.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/calendar.php b/lang/en/calendar.php
index dd0b7b4..3f1cc5f 100644
--- a/lang/en/calendar.php
+++ b/lang/en/calendar.php
@@ -59,7 +59,7 @@ $string['eventduration'] = 'Duration';
 $string['eventendtime'] = 'End time';
 $string['eventinstanttime'] = 'Time';
 $string['eventkind'] = 'Type of event';
-$string['eventname'] = 'Name';
+$string['eventname'] = 'Event title';
 $string['eventnone'] = 'No events';
 $string['eventrepeat'] = 'Repeats';
 $string['eventsall'] = 'All events';
-- 
1.7.9.5


From bd916ad1ee0227d8c34a42d9e648d7bdb68730f9 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Wed, 5 Sep 2012 10:34:51 +0800
Subject: [PATCH 592/903] MDL-35257 lib: if $CFG->logguests is disabled, avoid
 some log actions

This is for performance, else there can be great contention on the guest
user record as we've seen on moodle.org.
---
 lib/datalib.php   |    5 +++++
 lib/moodlelib.php |    5 +++++
 2 files changed, 10 insertions(+)

diff --git a/lib/datalib.php b/lib/datalib.php
index 99f6b91..dde0f20 100644
--- a/lib/datalib.php
+++ b/lib/datalib.php
@@ -1764,6 +1764,11 @@ function user_accesstime_log($courseid=0) {
         return;
     }
 
+    if (isguestuser()) {
+        // Do not update guest access times/ips for performance.
+        return;
+    }
+
     if (empty($courseid)) {
         $courseid = SITEID;
     }
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 1c8f966..1d10587 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -3289,6 +3289,11 @@ function get_user_key($script, $userid, $instance=null, $iprestriction=null, $va
 function update_user_login_times() {
     global $USER, $DB;
 
+    if (isguestuser()) {
+        // Do not update guest access times/ips for performance.
+        return true;
+    }
+
     $now = time();
 
     $user = new stdClass();
-- 
1.7.9.5


From 2904faa0eb3bd762caa0a1f95e78fccd06f999c2 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 3 Sep 2012 15:20:52 +0800
Subject: [PATCH 593/903] MDL-10259 core Adding a search courses box if there
 are too many courses

---
 index.php          |    6 +++++-
 lang/en/moodle.php |    1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/index.php b/index.php
index da6545b..087a73a 100644
--- a/index.php
+++ b/index.php
@@ -204,17 +204,21 @@
             break;
 
             case FRONTPAGECOURSELIST:
+                $ncourses = $DB->count_records('course');
                 if (isloggedin() and !$hassiteconfig and !isguestuser() and empty($CFG->disablemycourses)) {
                     echo html_writer::tag('a', get_string('skipa', 'access', textlib::strtolower(get_string('mycourses'))), array('href'=>'#skipmycourses', 'class'=>'skip-block'));
                     echo $OUTPUT->heading(get_string('mycourses'), 2, 'headingblock header');
                     print_my_moodle();
                     echo html_writer::tag('span', '', array('class'=>'skip-block-to', 'id'=>'skipmycourses'));
-                } else if ((!$hassiteconfig and !isguestuser()) or ($DB->count_records('course') <= FRONTPAGECOURSELIMIT)) {
+                } else if ((!$hassiteconfig and !isguestuser()) or ($ncourses <= FRONTPAGECOURSELIMIT)) {
                     // admin should not see list of courses when there are too many of them
                     echo html_writer::tag('a', get_string('skipa', 'access', textlib::strtolower(get_string('availablecourses'))), array('href'=>'#skipavailablecourses', 'class'=>'skip-block'));
                     echo $OUTPUT->heading(get_string('availablecourses'), 2, 'headingblock header');
                     print_courses(0);
                     echo html_writer::tag('span', '', array('class'=>'skip-block-to', 'id'=>'skipavailablecourses'));
+                } else {
+                    echo html_writer::tag('div', get_string('therearecourses', '', $ncourses), array('class' => 'notifyproblem'));
+                    print_course_search('', false, 'short');
                 }
             break;
 
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index a3d28ab..c8db376 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1671,6 +1671,7 @@ $string['theme'] = 'Theme';
 $string['themes'] = 'Themes';
 $string['themesaved'] = 'New theme saved';
 $string['thereareno'] = 'There are no {$a} in this course';
+$string['therearecourses'] = 'There are {$a} courses';
 $string['thiscategorycontains'] = 'This category contains';
 $string['time'] = 'Time';
 $string['timezone'] = 'Timezone';
-- 
1.7.9.5


From a2d928b1437761044f59a905ee22ee859197dee6 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Thu, 6 Sep 2012 10:28:52 +0800
Subject: [PATCH 594/903] MDL-35264 mod_chat Changing the input frame of chat
 daemon method to a embedded page layout

---
 mod/chat/gui_sockets/chatinput.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/chat/gui_sockets/chatinput.php b/mod/chat/gui_sockets/chatinput.php
index 237f488..d0603c2 100644
--- a/mod/chat/gui_sockets/chatinput.php
+++ b/mod/chat/gui_sockets/chatinput.php
@@ -17,6 +17,7 @@ if (!$chatuser = $DB->get_record('chat_users', array('sid'=>$chat_sid))) {
 $USER = $DB->get_record('user', array('id'=>$chatuser->userid));
 
 //Setup course, lang and theme
+$PAGE->set_pagelayout('embedded');
 $PAGE->set_course($DB->get_record('course', array('id' => $chatuser->course)));
 $PAGE->requires->js('/mod/chat/gui_sockets/chat_gui_sockets.js', true);
 $PAGE->requires->js_function_call('setfocus');
-- 
1.7.9.5


From a08d03a2c03f7d3376965034f978c1dd0a31a0f5 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Thu, 6 Sep 2012 09:14:44 +0800
Subject: [PATCH 595/903] MDL-34068 mod_chat Sending text/html headers when
 sending the messages frame output for the first
 time

---
 mod/chat/chatd.php |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index f255c17..a2cd366 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -538,8 +538,18 @@ EOD;
 
         // $this->trace('QUIRKS value for this connection is '.$customdata['quirks']);
 
+        $header  = "HTTP/1.1 200 OK\n";
+        $header .= "Connection: close\n";
+        $header .= "Date: ".date('r')."\n";
+        $header .= "Server: Moodle\n";
+        $header .= "Content-Type: text/html; charset=utf-8\n";
+        $header .= "Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT\n";
+        $header .= "Cache-Control: no-cache, must-revalidate\n";
+        $header .= "Expires: Wed, 4 Oct 1978 09:32:45 GMT\n";
+        $header .= "\n";
+
         $this->dismiss_half($sessionid, false);
-        $this->write_data($this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL], $CHAT_HTMLHEAD_JS);
+        $this->write_data($this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL], $header . $CHAT_HTMLHEAD_JS);
         $this->trace('Connection accepted: '.$this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL].', SID: '.$sessionid.' UID: '.$chatuser->userid.' GID: '.$chatuser->groupid, E_USER_WARNING);
 
         // Finally, broadcast the "entered the chat" message
-- 
1.7.9.5


From d37de5e0df27de1f21213db145b543c7d9bddd67 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 16 Aug 2012 15:28:03 +0800
Subject: [PATCH 596/903] MDL-34765 Course: Re-sorting courses uses natural
 order

---
 course/category.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/course/category.php b/course/category.php
index 5989cf8..b0b5684 100644
--- a/course/category.php
+++ b/course/category.php
@@ -27,6 +27,7 @@
 
 require_once("../config.php");
 require_once($CFG->dirroot.'/course/lib.php');
+require_once($CFG->libdir.'/textlib.class.php');
 
 $id = required_param('id', PARAM_INT); // Category id
 $page = optional_param('page', 0, PARAM_INT); // which page to show
@@ -75,7 +76,8 @@ $sesskeyprovided = !empty($sesskey) && confirm_sesskey($sesskey);
 // Process any category actions.
 if ($canmanage && $resort && $sesskeyprovided) {
     // Resort the category if requested
-    if ($courses = get_courses($category->id, "fullname ASC", 'c.id,c.fullname,c.sortorder')) {
+    if ($courses = get_courses($category->id, 'c.id,c.fullname,c.sortorder')) {
+        collatorlib::asort_objects_by_property($courses, 'fullname', collatorlib::SORT_NATURAL);
         $i = 1;
         foreach ($courses as $course) {
             $DB->set_field('course', 'sortorder', $category->sortorder+$i, array('id'=>$course->id));
-- 
1.7.9.5


From 689a3bcd17472dc52f3c44883635e7c6056d95a1 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 4 Sep 2012 18:12:26 +0800
Subject: [PATCH 597/903] MDL-34984 admin setting: fixed labeling and
 shortname display for admin setting

---
 lib/adminlib.php |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/adminlib.php b/lib/adminlib.php
index 5062c99..2e8121b 100644
--- a/lib/adminlib.php
+++ b/lib/adminlib.php
@@ -6217,9 +6217,8 @@ function format_admin_setting($setting, $title='', $form='', $description='', $l
     $str = '
 <div class="form-item clearfix" id="admin-'.$setting->name.'">
   <div class="form-label">
-    <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
-      '.$override.$warning.'
-    </label>
+    <label '.$labelfor.'>'.highlightfast($query, $title).$override.$warning.'</label>
+    <span class="form-shortname">'.highlightfast($query, $name).'</span>
   </div>
   <div class="form-setting">'.$form.$defaultinfo.'</div>
   <div class="form-description">'.highlight($query, markdown_to_html($description)).'</div>
-- 
1.7.9.5


From 5c0c094f3c912e957940bd198acfd92e5783ce4f Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 27 Jul 2012 18:50:06 +0800
Subject: [PATCH 598/903] MDL-34573 accessibility compliance for tag: Add
 forform input text and select tag

---
 tag/coursetags_edit.php |   11 +++++++----
 tag/manage.php          |    7 +++++--
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/tag/coursetags_edit.php b/tag/coursetags_edit.php
index 8dbc285..8f0e4d6 100644
--- a/tag/coursetags_edit.php
+++ b/tag/coursetags_edit.php
@@ -159,11 +159,12 @@ echo $OUTPUT->header();
                 <div class="coursetag_edit_centered">
                     <div class="coursetag_edit_row">
                         <div class="coursetag_edit_left">
-                            $edittagthisunit
+                            <label for="coursetag_new_tag">$edittagthisunit</label>
                         </div>
                         <div class="coursetag_edit_right">
                             <div class="coursetag_form_input1">
-                                <input type="text" name="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
+                                <label clas="accesshide" for="coursetag_sug_keyword">$edittagthisunit</label>
+                                <input type="text" name="coursetag_sug_keyword" id="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
                             </div>
                             <div class="coursetag_form_input2">
                                 <input type="text" name="coursetag_new_tag" id="coursetag_new_tag" class="coursetag_form_input2a"
@@ -182,10 +183,12 @@ EOT;
             $outstr .= <<<EOT1
                     <div class="coursetag_edit_row">
                         <div class="coursetag_edit_left">
-                            $editdeletemytag
+                            <label for="del_tag">
+                                $editdeletemytag
+                            </label>
                         </div>
                         <div class="coursetag_edit_right">
-                            <select name="del_tag">
+                            <select id="del_tag" name="del_tag">
                                 $selectoptions
                             </select>
                         </div>
diff --git a/tag/manage.php b/tag/manage.php
index e0edeb9..d63b09d 100644
--- a/tag/manage.php
+++ b/tag/manage.php
@@ -260,8 +260,10 @@ if ($tagrecords = $DB->get_records_sql($query, $params, $table->get_page_start()
         $flag           =   $tag->flag;
         $timemodified   =   format_time(time() - $tag->timemodified);
         $checkbox       =   '<input type="checkbox" name="tagschecked[]" value="'.$tag->id.'" />';
-        $text           =   '<input type="text" name="newname['.$tag->id.']" />';
-        $tagtype        =   html_writer::select($existing_tagtypes, 'tagtypes['.$tag->id.']', $tag->tagtype, false);
+        $text           =   html_writer::label(get_string('newname', 'tag'), 'newname_' . $tag->id, false, array('class' => 'accesshide'));
+        $text          .=   '<input type="text" id="newname_' . $tag->id. '" name="newname['.$tag->id.']" />';
+        $tagtype        =   html_writer::label(get_string('tagtype', 'tag'), 'menutagtypes'. $tag->id, false, array('class' => 'accesshide'));
+        $tagtype       .=   html_writer::select($existing_tagtypes, 'tagtypes['.$tag->id.']', $tag->tagtype, false, array('id' => 'menutagtypes'. $tag->id));
 
         //if the tag if flagged, highlight it
         if ($tag->flag > 0) {
@@ -283,6 +285,7 @@ if ($tagrecords = $DB->get_records_sql($query, $params, $table->get_page_start()
     echo '<input type="button" onclick="checknone()" value="'.get_string('deselectall').'" /> ';
     echo '<input type="hidden" name="sesskey" value="'.sesskey().'" /> ';
     echo '<br/><br/>';
+    echo html_writer::label(get_string('withselectedtags', 'tag'), 'menuformaction', false, array('class' => 'accesshide'));
     echo '<select id="menuformaction" name="action">
                 <option value="" selected="selected">'. get_string('withselectedtags', 'tag') .'</option>
                 <option value="reset">'. get_string('resetflag', 'tag') .'</option>
-- 
1.7.9.5


From 2afda054e876d616f32f17d48500d5d6aa90761d Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 13 Aug 2012 17:15:58 +0800
Subject: [PATCH 599/903] MDL-34573 Tag: update label for suggested tag

---
 blocks/tags/lang/en/block_tags.php |    1 +
 tag/coursetags_edit.php            |   11 +++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/blocks/tags/lang/en/block_tags.php b/blocks/tags/lang/en/block_tags.php
index 0643b91..265cd5a 100644
--- a/blocks/tags/lang/en/block_tags.php
+++ b/blocks/tags/lang/en/block_tags.php
@@ -82,6 +82,7 @@ $string['pluginname'] = 'Tags';
 $string['select'] = 'Select...';
 $string['showcoursetags'] = 'Show course tags';
 $string['showcoursetagsdef'] = 'Display the course tagging features in the tags block, allowing students to tag courses.';
+$string['suggestedtagthisunit'] = 'Suggested tag to this course:';
 $string['tags'] = 'tags';
 $string['tagthisunit'] = 'Tag this course:';
 $string['tagunits'] = 'to tag your favourite courses';
diff --git a/tag/coursetags_edit.php b/tag/coursetags_edit.php
index 8f0e4d6..85ae603 100644
--- a/tag/coursetags_edit.php
+++ b/tag/coursetags_edit.php
@@ -147,6 +147,7 @@ echo $OUTPUT->header();
         // Print the add and delete form
         coursetag_get_jscript();
         $edittagthisunit = get_string('edittagthisunit', $tagslang);
+        $suggestedtagthisunit = get_string('suggestedtagthisunit', $tagslang);
         $arrowtitle = get_string('arrowtitle', $tagslang);
         $sesskey = sesskey();
         $leftarrow = $OUTPUT->pix_url('t/arrow_left');
@@ -159,13 +160,19 @@ echo $OUTPUT->header();
                 <div class="coursetag_edit_centered">
                     <div class="coursetag_edit_row">
                         <div class="coursetag_edit_left">
-                            <label for="coursetag_new_tag">$edittagthisunit</label>
+                            <label for="coursetag_sug_tag">$suggestedtagthisunit</label>
                         </div>
                         <div class="coursetag_edit_right">
                             <div class="coursetag_form_input1">
-                                <label clas="accesshide" for="coursetag_sug_keyword">$edittagthisunit</label>
                                 <input type="text" name="coursetag_sug_keyword" id="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
                             </div>
+                        </div>
+                    </div>
+                    <div class="coursetag_edit_row">
+                        <div class="coursetag_edit_left">
+                            <label for="coursetag_new_tag">$edittagthisunit</label>
+                        </div>
+                        <div class="coursetag_edit_right">
                             <div class="coursetag_form_input2">
                                 <input type="text" name="coursetag_new_tag" id="coursetag_new_tag" class="coursetag_form_input2a"
                                     onfocus="ctags_getKeywords()" onkeyup="ctags_getKeywords()" maxlength="50" />
-- 
1.7.9.5


From 14d15f125eac8ba69b989dba62f1422981f3af94 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 17 Aug 2012 12:01:34 +0800
Subject: [PATCH 600/903] MDL-34573 - add label for search tag input text

---
 tag/locallib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/tag/locallib.php b/tag/locallib.php
index 589b6dc..a5ff704 100644
--- a/tag/locallib.php
+++ b/tag/locallib.php
@@ -233,6 +233,7 @@ function tag_print_search_box($return=false) {
     $output = $OUTPUT->box_start('','tag-search-box');
     $output .= '<form action="'.$CFG->wwwroot.'/tag/search.php" style="display:inline">';
     $output .= '<div>';
+    $output .= '<label class="accesshide" for="searchform_search">'.get_string('searchtags', 'tag').'</label>';
     $output .= '<input id="searchform_search" name="query" type="text" size="40" />';
     $output .= '<button id="searchform_button" type="submit">'. get_string('search', 'tag') .'</button><br />';
     $output .= '</div>';
-- 
1.7.9.5


From cd029574b699c74e55fa287f0b4db45d2dcf9fde Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 31 Aug 2012 15:23:59 +0800
Subject: [PATCH 601/903] MDL-29872 Dropbox repository: add message handler to
 filepicker header and add message to logout from
 dropbox. When user clicked on logout button from
 dropbox repository, it will also logging them out
 from dropbox site through a popup window

---
 files/renderer.php                                |    1 +
 repository/dropbox/lang/en/repository_dropbox.php |    1 +
 repository/dropbox/lib.php                        |    2 ++
 repository/filepicker.js                          |   13 ++++++++++++-
 4 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/files/renderer.php b/files/renderer.php
index cfa14e0..b0eed2a 100644
--- a/files/renderer.php
+++ b/files/renderer.php
@@ -526,6 +526,7 @@ class core_files_renderer extends plugin_renderer_base {
                     <div class="{!}fp-tb-logout"><img src="'.$this->pix_url('a/logout').'" /><a href="#"></a></div>
                     <div class="{!}fp-tb-manage"><a href="#"><img src="'.$this->pix_url('a/setting').'" /> '.get_string('manageurl', 'repository').'</a></div>
                     <div class="{!}fp-tb-help"><a href="#"><img src="'.$this->pix_url('a/help').'" /> '.get_string('help').'</a></div>
+                    <div class="{!}fp-tb-message"></div>
                 </div>
                 <div class="{!}fp-viewbar">
                     <a class="{!}fp-vb-icons" href="#"></a>
diff --git a/repository/dropbox/lang/en/repository_dropbox.php b/repository/dropbox/lang/en/repository_dropbox.php
index abf16c1..6f0728d 100644
--- a/repository/dropbox/lang/en/repository_dropbox.php
+++ b/repository/dropbox/lang/en/repository_dropbox.php
@@ -33,3 +33,4 @@ $string['instruction'] = 'You can get your API Key and secret from <a href="http
 $string['cachelimit'] = 'Cache limit';
 $string['cachelimit_info'] = 'Enter the maximum size of files (in bytes) to be cached on server for Dropbox aliases/shortcuts. Cached files will be served when the source is no longer available. Empty value or zero mean caching of all files regardless of size.';
 $string['dropbox:view'] = 'View a Dropbox folder';
+$string['logoutdesc'] = '(Logout when you finish using Dropbox)';
diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index a0af82f..768580e 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -179,6 +179,8 @@ class repository_dropbox extends repository {
         $list['manage'] = 'https://www.dropbox.com/home';
         $list['dynload'] = true;
         $list['nosearch'] = true;
+        $list['logouturl'] = 'https://www.dropbox.com/logout';
+        $list['message'] = get_string('logoutdesc', 'repository_dropbox');
         // process breadcrumb trail
         $list['path'] = array(
             array('name'=>get_string('dropbox', 'repository_dropbox'), 'path'=>'/')
diff --git a/repository/filepicker.js b/repository/filepicker.js
index d277574..9654045 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -1386,6 +1386,8 @@ M.core_filepicker.init = function(Y, options) {
             this.active_repo.norefresh = (data.login || data.norefresh); // this is either login form or 'norefresh' attribute set
             this.active_repo.nologin = (data.login || data.nologin); // this is either login form or 'nologin' attribute is set
             this.active_repo.logouttext = data.logouttext?data.logouttext:null;
+            this.active_repo.logouturl = (data.logouturl || '');
+            this.active_repo.message = (data.message || '');
             this.active_repo.help = data.help?data.help:null;
             this.active_repo.manage = data.manage?data.manage:null;
             this.print_header();
@@ -1698,6 +1700,9 @@ M.core_filepicker.init = function(Y, options) {
                         callback: this.display_response
                     }, true);
                 }
+                if (this.active_repo.logouturl) {
+                    window.open(this.active_repo.logouturl, 'repo_auth', 'location=0,status=0,width=500,height=300,scrollbars=yes');
+                }
             }, this);
             toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
                 e.preventDefault();
@@ -1720,7 +1725,7 @@ M.core_filepicker.init = function(Y, options) {
                             callback: this.display_response
                         }, true);
                     }
-                }, this);
+            }, this);
 
             // it does not matter what kind of element is .fp-tb-manage, we create a dummy <a>
             // element and use it to open url on click event
@@ -1817,6 +1822,12 @@ M.core_filepicker.init = function(Y, options) {
             // help url
             enable_tb_control(toolbar.one('.fp-tb-help'), r.help);
             Y.one('#fp-tb-help-'+client_id+'-link').set('href', r.help);
+
+            // message
+            if (toolbar.one('.fp-tb-message')) {
+                enable_tb_control(toolbar.one('.fp-tb-message'), r.message);
+                toolbar.one('.fp-tb-message').setContent(r.message);
+            }
         },
         print_path: function() {
             if (!this.pathbar) {
-- 
1.7.9.5


From 9cd1f8ffe6be474f95e6f5247c7dc14f0379e288 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 7 Sep 2012 10:30:24 +0200
Subject: [PATCH 602/903] MDL-35289 add missing charmap usage info string

---
 lib/editor/tinymce/lang/en/editor_tinymce.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/editor/tinymce/lang/en/editor_tinymce.php b/lib/editor/tinymce/lang/en/editor_tinymce.php
index 587ed66..2209291 100644
--- a/lib/editor/tinymce/lang/en/editor_tinymce.php
+++ b/lib/editor/tinymce/lang/en/editor_tinymce.php
@@ -122,6 +122,7 @@ $string['advanced_dlg:about_version'] = 'Version';
 $string['advanced_dlg:anchor_name'] = 'Anchor name';
 $string['advanced_dlg:anchor_title'] = 'Insert/edit anchor';
 $string['advanced_dlg:charmap_title'] = 'Select custom character';
+$string['advanced_dlg:charmap_usage'] = 'Use left and right arrows to navigate.';
 $string['advanced_dlg:code_title'] = 'HTML Source Editor';
 $string['advanced_dlg:code_wordwrap'] = 'Word wrap';
 $string['advanced_dlg:colorpicker_color'] = 'Color:';
-- 
1.7.9.5


From bafffec18191e5f20716f2845b1b221cdf2e6556 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 8 Sep 2012 10:49:00 +0200
Subject: [PATCH 603/903] MDL-35270 fix ambiguously defined column

Credit goes to Sara Arjona, thanks.
---
 enrol/cohort/locallib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/enrol/cohort/locallib.php b/enrol/cohort/locallib.php
index 5ca237a..fb41a62 100644
--- a/enrol/cohort/locallib.php
+++ b/enrol/cohort/locallib.php
@@ -51,8 +51,8 @@ class enrol_cohort_handler {
         $sql = "SELECT e.*, r.id as roleexists
                   FROM {enrol} e
              LEFT JOIN {role} r ON (r.id = e.roleid)
-                 WHERE customint1 = :cohortid AND enrol = 'cohort'
-              ORDER BY id ASC";
+                 WHERE e.customint1 = :cohortid AND e.enrol = 'cohort'
+              ORDER BY e.id ASC";
         if (!$instances = $DB->get_records_sql($sql, array('cohortid'=>$ca->cohortid))) {
             return true;
         }
-- 
1.7.9.5


From 7413ce9896042b028a85cb5bf59bc75554ca2084 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Sun, 9 Sep 2012 16:23:09 +0200
Subject: [PATCH 604/903] Moodle 2.3.2 release

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 928a90f..38c2756 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.15;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120907)'; // Human-friendly version name
+$release  = '2.3.2 (Build: 20120910)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 87224397516360e18b62cec355fd8de12791fe12 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Mon, 27 Aug 2012 03:24:10 +0200
Subject: [PATCH 605/903] MDL-30018 restore: better answer matching. Credit
 goes to Tyler Bannister, thanks!

On backup, contents are cleaned to be safe utf8. That was leading to
some matching problems on restore against not cleaned DB contents (for
already existing questions). This commit adds one fallback method to
perform the match against cleaned DB contents.
---
 backup/moodle2/restore_qtype_plugin.class.php |   16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/backup/moodle2/restore_qtype_plugin.class.php b/backup/moodle2/restore_qtype_plugin.class.php
index 40b06ac..99365ba 100644
--- a/backup/moodle2/restore_qtype_plugin.class.php
+++ b/backup/moodle2/restore_qtype_plugin.class.php
@@ -154,6 +154,22 @@ abstract class restore_qtype_plugin extends restore_plugin {
                        AND ' . $DB->sql_compare_text('answer', 255) . ' = ' . $DB->sql_compare_text('?', 255);
             $params = array($newquestionid, $data->answertext);
             $newitemid = $DB->get_field_sql($sql, $params);
+
+            // Not able to find the answer, let's try cleaning the answertext
+            // of all the question answers in DB as slower fallback. MDL-30018.
+            if (!$newitemid) {
+                $params = array('question' => $newquestionid);
+                $answers = $DB->get_records('question_answers', $params, '', 'id, answer');
+                foreach ($answers as $answer) {
+                    // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+                    $clean = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $answer->answer); // Clean CTRL chars.
+                    $clean = preg_replace("/\r\n|\r/", "\n", $clean); // Normalize line ending.
+                    if ($clean === $data->answertext) {
+                        $newitemid = $data->id;
+                    }
+                }
+            }
+
             // If we haven't found the newitemid, something has gone really wrong, question in DB
             // is missing answers, exception
             if (!$newitemid) {
-- 
1.7.9.5


From 879c31c1ba87f7cf4801262523565e521c46ddd4 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Thu, 23 Aug 2012 10:24:10 +0800
Subject: [PATCH 606/903] MDL-27398 mod_chat Adding CLI_SCRIPT to chat daemon

Credit to Jorge Villalon
---
 mod/chat/chatd.php |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index f255c17..caedaa5 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -1,6 +1,8 @@
 #!/usr/bin/php -q
 <?php
 
+define('CLI_SCRIPT', true);
+
 // Browser quirks
 define('QUIRK_CHUNK_UPDATE', 0x0001);
 
-- 
1.7.9.5


From c8cac02c99d35c1ecb08e018b8d9297ebdec235a Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Tue, 4 Sep 2012 10:22:47 +0800
Subject: [PATCH 607/903] MDL-27398 mod_chat Removing deprecated calls and
 moving dependencies

Credit to Jorge Villalon
---
 mod/chat/chatd.php |   18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index caedaa5..6d6d361 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -3,6 +3,9 @@
 
 define('CLI_SCRIPT', true);
 
+require(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->dirroot . '/mod/chat/lib.php');
+
 // Browser quirks
 define('QUIRK_CHUNK_UPDATE', 0x0001);
 
@@ -29,30 +32,15 @@ $_SERVER['PHP_SELF']        = 'dummy';
 $_SERVER['SERVER_NAME']     = 'dummy';
 $_SERVER['HTTP_USER_AGENT'] = 'dummy';
 
-define('NO_MOODLE_COOKIES', true); // session not used here
-
-include('../../config.php');
-include('lib.php');
-
 $_SERVER['SERVER_NAME'] = $CFG->chat_serverhost;
 $_SERVER['PHP_SELF']    = "http://$CFG->chat_serverhost:$CFG->chat_serverport/mod/chat/chatd.php";
 
 $safemode = ini_get('safe_mode');
-
-if($phpversion < '4.3') {
-    die("Error: The Moodle chat daemon requires at least PHP version 4.3 to run.\n       Since your version is $phpversion, you have to upgrade.\n\n");
-}
 if(!empty($safemode)) {
     die("Error: Cannot run with PHP safe_mode = On. Turn off safe_mode in php.ini.\n");
 }
 
-$passref = ini_get('allow_call_time_pass_reference');
-if(empty($passref)) {
-    die("Error: Cannot run with PHP allow_call_time_pass_reference = Off. Turn on allow_call_time_pass_reference in php.ini.\n");
-}
-
 @set_time_limit (0);
-set_magic_quotes_runtime(0);
 error_reporting(E_ALL);
 
 function chat_empty_connection() {
-- 
1.7.9.5


From f4dfb810c871cf0754eacae9ddc258a9de1e082d Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Tue, 4 Sep 2012 10:23:56 +0800
Subject: [PATCH 608/903] MDL-27398 mod_chat Adding file basic doc

---
 mod/chat/chatd.php |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index 6d6d361..07aa00a 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -1,6 +1,29 @@
 #!/usr/bin/php -q
 <?php
 
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chat daemon
+ *
+ * @package    mod_chat
+ * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 define('CLI_SCRIPT', true);
 
 require(dirname(dirname(dirname(__FILE__))).'/config.php');
-- 
1.7.9.5


From 799de151452875081551f26e4fb617f2a327eed9 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Tue, 4 Sep 2012 10:24:45 +0800
Subject: [PATCH 609/903] MDL-27398 mod_chat Removing PAGE references

---
 mod/chat/chatd.php |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index 07aa00a..75ea3ae 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -238,12 +238,11 @@ class ChatDaemon {
     }
 
     function get_user_window($sessionid) {
-        global $CFG, $PAGE, $OUTPUT;
+        global $CFG, $OUTPUT;
 
         static $str;
 
         $info = &$this->sets_info[$sessionid];
-        $PAGE->set_course($info['course']);
 
         $timenow = time();
 
@@ -720,7 +719,6 @@ EOD;
     }
 
     function message_broadcast($message, $sender) {
-        global $PAGE;
 
         if(empty($this->conn_sets)) {
             return true;
@@ -738,7 +736,6 @@ EOD;
             {
 
                 // Simply give them the message
-                $PAGE->set_course($info['course']);
                 $output = chat_format_message_manually($message, $info['courseid'], $sender, $info['user']);
                 $this->trace('Delivering message "'.$output->text.'" to '.$this->conn_sets[$sessionid][CHAT_CONNECTION_CHANNEL]);
 
-- 
1.7.9.5


From 360769aa0fdf085c19a85d4d1365e11716474339 Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Mon, 10 Sep 2012 14:51:32 +0800
Subject: [PATCH 610/903] MDL-30857 block_community Removing comments
 hardcoded height

---
 blocks/community/yui/comments/comments.js |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/blocks/community/yui/comments/comments.js b/blocks/community/yui/comments/comments.js
index 155a823..7355b80 100644
--- a/blocks/community/yui/comments/comments.js
+++ b/blocks/community/yui/comments/comments.js
@@ -23,8 +23,7 @@ YUI.add('moodle-block_community-comments', function(Y) {
                     bodyContent:Y.one('#commentoverlay-'+commentid).get('innerHTML'),
                     visible: false, //by default it is not displayed
                     lightbox : false,
-                    zIndex:100,
-                    height: '350px'
+                    zIndex:100
                 });
 
                 this.overlays[commentid].get('contentBox').one('.commenttitle').remove();
@@ -86,4 +85,4 @@ YUI.add('moodle-block_community-comments', function(Y) {
 
 }, '@VERSION@', {
     requires:['base','overlay', 'moodle-enrol-notification']
-});
\ No newline at end of file
+});
-- 
1.7.9.5


From 5371fa19283ff23f049aed7f749bbef5f55d6e44 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 6 Sep 2012 14:25:26 +0800
Subject: [PATCH 611/903] MDL-30829 Accessibility: Docking a block disables
 the accessible anchors

---
 blocks/dock.js |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/blocks/dock.js b/blocks/dock.js
index 5560a32..5e4a56f 100644
--- a/blocks/dock.js
+++ b/blocks/dock.js
@@ -863,6 +863,12 @@ M.core_dock.genericblock.prototype = {
             return;
         }
 
+        // Disable the skip anchor when docking
+        var skipanchor = node.previous();
+        if (skipanchor.hasClass('skip-block')) {
+            skipanchor.hide();
+        }
+
         var blockclass = (function(classes){
             var r = /(^|\s)(block_[a-zA-Z0-9_]+)(\s|$)/;
             var m = r.exec(classes);
@@ -937,6 +943,12 @@ M.core_dock.genericblock.prototype = {
     return_to_block : function(dockitem) {
         var placeholder = this.Y.one('#content_placeholder_'+this.id);
 
+        // Enable the skip anchor when going back to block mode
+        var skipanchor = placeholder.previous();
+        if (skipanchor.hasClass('skip-block')) {
+            skipanchor.show();
+        }
+
         if (this.cachedcontentnode.one('.header')) {
             this.cachedcontentnode.one('.header').insert(dockitem.contents, 'after');
         } else {
-- 
1.7.9.5


From 817fcbb5497ada8bb51c48992880aaaaaa7acee3 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Mon, 10 Sep 2012 13:06:47 +0100
Subject: [PATCH 612/903] MDL-35343 JavaScript visible in multichoice choice
 feedback.

Also, Match correct answer, and calculated multi and multianswer
feedback.
---
 question/type/calculatedmulti/styles.css |    3 +++
 question/type/match/styles.css           |    3 +++
 question/type/multianswer/styles.css     |    3 +++
 question/type/multichoice/styles.css     |    3 +++
 4 files changed, 12 insertions(+)

diff --git a/question/type/calculatedmulti/styles.css b/question/type/calculatedmulti/styles.css
index 75ce4f9..f751527 100644
--- a/question/type/calculatedmulti/styles.css
+++ b/question/type/calculatedmulti/styles.css
@@ -7,6 +7,9 @@
     display: inline;
     background: #FFF3BF;
 }
+.que.calculatedmulti .answer .specificfeedback script {
+    display: none;
+}
 .que.calculatedmulti .answer div.r0,
 .que.calculatedmulti .answer div.r1 {
     padding: 0.3em;
diff --git a/question/type/match/styles.css b/question/type/match/styles.css
index 0f79d8c..5320cdf 100644
--- a/question/type/match/styles.css
+++ b/question/type/match/styles.css
@@ -1,3 +1,6 @@
 .que.match .feedback .rightanswer * {
     display: inline;
 }
+.que.match .feedback .rightanswer script {
+    display: none;
+}
diff --git a/question/type/multianswer/styles.css b/question/type/multianswer/styles.css
index fbeb0fe..aeeaccf 100644
--- a/question/type/multianswer/styles.css
+++ b/question/type/multianswer/styles.css
@@ -14,6 +14,9 @@
     display: inline;
     background: #FFF3BF;
 }
+.que.multianswer .answer .specificfeedback script {
+    display: none;
+}
 .que.multianswer .answer div.r0,
 .que.multianswer .answer div.r1 {
     padding: 0.3em;
diff --git a/question/type/multichoice/styles.css b/question/type/multichoice/styles.css
index 4aa77fd..c179bb8 100644
--- a/question/type/multichoice/styles.css
+++ b/question/type/multichoice/styles.css
@@ -6,6 +6,9 @@
     display: inline;
     background: #FFF3BF;
 }
+.que.multichoice .answer .specificfeedback script {
+    display: none;
+}
 .que.multichoice .answer div.r0,
 .que.multichoice .answer div.r1 {
     padding: 0.3em;
-- 
1.7.9.5


From cc17d246e4c959cd335feb15b1e06387321b7210 Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Mon, 10 Sep 2012 12:31:39 -0700
Subject: [PATCH 613/903] MDL-32230 block_rss_client: remove extra cleaning
 step

---
 blocks/rss_client/block_rss_client.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/rss_client/block_rss_client.php b/blocks/rss_client/block_rss_client.php
index 086983d..38f8856 100644
--- a/blocks/rss_client/block_rss_client.php
+++ b/blocks/rss_client/block_rss_client.php
@@ -239,7 +239,7 @@
 
         $r = html_writer::start_tag('li');
             $r.= html_writer::start_tag('div',array('class'=>'link'));
-                $r.= html_writer::link(clean_param($link,PARAM_URL), s($title), array('onclick'=>'this.target="_blank"'));
+                $r.= html_writer::link($link, s($title), array('onclick'=>'this.target="_blank"'));
             $r.= html_writer::end_tag('div');
 
             if($this->config->display_description && !empty($description)){
-- 
1.7.9.5


From 919105e5d138f967a4fa4f5fecb2d7f2dbfa342a Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Thu, 30 Aug 2012 15:42:54 +0800
Subject: [PATCH 614/903] MDL-32785 - lib - Ignorning hard frozen fields when
 submitting data.

---
 lib/formslib.php |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/formslib.php b/lib/formslib.php
index 31a5419..ea1fdcb 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -1669,10 +1669,14 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         $unfiltered = array();
         if (null === $elementList) {
             // iterate over all elements, calling their exportValue() methods
-            $emptyarray = array();
             foreach (array_keys($this->_elements) as $key) {
-                if ($this->_elements[$key]->isFrozen() && !$this->_elements[$key]->_persistantFreeze){
-                    $value = $this->_elements[$key]->exportValue($emptyarray, true);
+                if ($this->_elements[$key]->isFrozen() && !$this->_elements[$key]->_persistantFreeze) {
+                    $varname = $this->_elements[$key]->_attributes['name'];
+                    $value = '';
+                    // If we have a default value then export it.
+                    if (isset($this->_defaultValues[$varname])) {
+                        $value = array($varname => $this->_defaultValues[$varname]);
+                    }
                 } else {
                     $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
                 }
@@ -1699,7 +1703,6 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         if (is_array($this->_constantValues)) {
             $unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $this->_constantValues);
         }
-
         return $unfiltered;
     }
 
-- 
1.7.9.5


From babf5f522eddad014cfd04eb9389bda902a29fec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Wed, 5 Sep 2012 14:05:36 +0200
Subject: [PATCH 615/903] MDL-35272 Fix typo in qformat_blackboard_six.php

Credit goes to German Valero for spotting and reporting this.
---
 .../lang/en/qformat_blackboard_six.php             |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/question/format/blackboard_six/lang/en/qformat_blackboard_six.php b/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
index 020c7a2..c7c4746 100644
--- a/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
+++ b/question/format/blackboard_six/lang/en/qformat_blackboard_six.php
@@ -25,10 +25,10 @@
 $string['defaultname'] = 'Imported question {$a}';
 $string['errormanifest'] = 'Error while parsing the IMS manifest document';
 $string['importnotext'] = 'Missing question text in XML file';
-$string['filenothandled'] = 'This archive contains reference to a file material {$a} wich is not currently handled by import';
+$string['filenothandled'] = 'This archive contains reference to a file material {$a} which is not currently handled by import';
 $string['imagenotfound'] = 'Image file with path {$a} was not found in the import.';
 $string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
 $string['pluginname'] = 'Blackboard V6+';
 $string['pluginname_help'] = 'Blackboard V6+ format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
-$string['unhandledpresblock'] = 'Unhandled presentation bloc';
+$string['unhandledpresblock'] = 'Unhandled presentation block';
 $string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
-- 
1.7.9.5


From cfe32be82264276eb51eb94db1ba4f3b0268652c Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Fri, 24 Aug 2012 14:32:04 +0800
Subject: [PATCH 616/903] MDL-34660: Fix SQL error in assignments module with
 Oracle Database I by replacing 'offline' with
 'nosubmissions'

---
 mod/assign/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index 2da6610..070dc50 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -258,7 +258,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 offline, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
+    $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));
 
@@ -298,7 +298,7 @@ function assign_print_overview($courses, &$htmlarray) {
             $str .= '<div class="details">';
             $str .= get_string('mysubmission', 'assign');
             $submission = $mysubmissions[$assignment->id];
-            if ($submission->offline) {
+            if ($submission->nosubmissions) {
                  $str .= get_string('offline', 'assign');
             } else if(!$submission->status || $submission->status == 'draft'){
                  $str .= $strnotsubmittedyet;
-- 
1.7.9.5


From 7189c6102f1a82f95e1b27b9f81c993e0d950c93 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 11 Sep 2012 02:18:38 +0200
Subject: [PATCH 617/903] MDL-34338 mod_folder: delete unused $browser var.

---
 mod/folder/renderer.php |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mod/folder/renderer.php b/mod/folder/renderer.php
index a321cdf..3cc317d 100644
--- a/mod/folder/renderer.php
+++ b/mod/folder/renderer.php
@@ -56,7 +56,6 @@ class mod_folder_renderer extends plugin_renderer_base {
         if (empty($dir['subdirs']) and empty($dir['files'])) {
             return '';
         }
-        $browser = get_file_browser();
         $result = '<ul>';
         foreach ($dir['subdirs'] as $subdir) {
             $image = $this->output->pix_icon(file_folder_icon(24), $subdir['dirname'], 'moodle');
@@ -104,4 +103,4 @@ class folder_tree implements renderable {
         $fs = get_file_storage();
         $this->dir = $fs->get_area_tree($this->context->id, 'mod_folder', 'content', 0);
     }
-}
\ No newline at end of file
+}
-- 
1.7.9.5


From c84b70456ad6b04c2d33e01a02c7e67d363599ab Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 3 Sep 2012 16:44:49 +0800
Subject: [PATCH 618/903] MDL-33857 Increase performance of queries for Server
 files repository

- file_info class now has new methods get_non_empty_children and count_non_empty_children; added default implementation;
- all core classes extending file_info have their implementation of those methods;
- class repository_local_file used for caching get_children() results is removed;
- class repository_local rewritten to use new methods from file_info;
- added caching of retrieved modules in file_browser::get_file_info_context_module() - this query is slow and executed multiple times on big servers
---
 lib/filebrowser/file_browser.php                |    7 +-
 lib/filebrowser/file_info.php                   |  105 +++++++
 lib/filebrowser/file_info_context_course.php    |  192 ++++++++++--
 lib/filebrowser/file_info_context_coursecat.php |   44 +++
 lib/filebrowser/file_info_context_module.php    |   92 +++++-
 lib/filebrowser/file_info_stored.php            |   64 ++++
 mod/book/locallib.php                           |   75 ++++-
 mod/data/locallib.php                           |   70 ++++-
 mod/forum/locallib.php                          |   70 ++++-
 mod/glossary/locallib.php                       |   77 ++++-
 mod/imscp/locallib.php                          |   68 +++-
 mod/workshop/fileinfolib.php                    |   73 ++++-
 repository/local/lib.php                        |  382 ++++++++---------------
 13 files changed, 987 insertions(+), 332 deletions(-)

diff --git a/lib/filebrowser/file_browser.php b/lib/filebrowser/file_browser.php
index f2105cb..d5ac755 100644
--- a/lib/filebrowser/file_browser.php
+++ b/lib/filebrowser/file_browser.php
@@ -201,8 +201,13 @@ class file_browser {
     private function get_file_info_context_module($context, $component, $filearea, $itemid, $filepath, $filename) {
         global $COURSE, $DB, $CFG;
 
+        static $cachedmodules = array();
 
-        if (!$cm = get_coursemodule_from_id('', $context->instanceid)) {
+        if (!array_key_exists($context->instanceid, $cachedmodules)) {
+            $cachedmodules[$context->instanceid] = get_coursemodule_from_id('', $context->instanceid);
+        }
+
+        if (!($cm = $cachedmodules[$context->instanceid])) {
             return null;
         }
 
diff --git a/lib/filebrowser/file_info.php b/lib/filebrowser/file_info.php
index d5bcade..9ad0364 100644
--- a/lib/filebrowser/file_info.php
+++ b/lib/filebrowser/file_info.php
@@ -89,6 +89,111 @@ abstract class file_info {
     public abstract function get_children();
 
     /**
+     * Builds SQL sub query (WHERE clause) for selecting files with the specified extensions
+     *
+     * If $extensions == '*' (any file), the result is array('', array())
+     * otherwise the result is something like array('AND filename ...', array(...))
+     *
+     * @param string|array $extensions - either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param string $prefix prefix for DB table files in the query (empty by default)
+     * @return array of two elements: $sql - sql where clause and $params - array of parameters
+     */
+    protected function build_search_files_sql($extensions, $prefix = null) {
+        global $DB;
+        if (strlen($prefix)) {
+            $prefix = $prefix.'.';
+        } else {
+            $prefix = '';
+        }
+        $sql = '';
+        $params = array();
+        if (is_array($extensions) && !in_array('*', $extensions)) {
+            $likes = array();
+            $cnt = 0;
+            foreach ($extensions as $ext) {
+                $cnt++;
+                $likes[] = $DB->sql_like($prefix.'filename', ':filename'.$cnt, false);
+                $params['filename'.$cnt] = '%'.$ext;
+            }
+            $sql .= ' AND ('.join(' OR ', $likes).')';
+        }
+        return array($sql, $params);
+     }
+
+    /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * It is recommended to overwrite this function so it uses a proper SQL
+     * query and does not create unnecessary file_info objects (might require a lot of time
+     * and memory usage on big sites).
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        $list = $this->get_children();
+        $nonemptylist = array();
+        foreach ($list as $fileinfo) {
+            if ($fileinfo->is_directory()) {
+                if ($fileinfo->count_non_empty_children($extensions)) {
+                    $nonemptylist[] = $fileinfo;
+                }
+            } else if ($extensions === '*') {
+                $nonemptylist[] = $fileinfo;
+            } else {
+                $filename = $fileinfo->get_visible_name();
+                $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+                if (!empty($extension) && in_array('.'.$extension, $extensions)) {
+                    $nonemptylist[] = $fileinfo;
+                }
+            }
+        }
+        return $nonemptylist;
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * This function is used by repository_local to evaluate if the folder is empty. But
+     * it also can be used to check if folder has only one subfolder because in some cases
+     * this subfolder can be skipped.
+     *
+     * It is strongly recommended to overwrite this function so it uses a proper SQL
+     * query and does not create file_info objects (later might require a lot of time
+     * and memory usage on big sites).
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        $list = $this->get_children();
+        $cnt = 0;
+        foreach ($list as $fileinfo) {
+            if ($cnt > 1) {
+                // it only matters if it is 0, 1 or 2+
+                return $cnt;
+            }
+            if ($fileinfo->is_directory()) {
+                if ($fileinfo->count_non_empty_children($extensions)) {
+                    $cnt++;
+                }
+            } else if ($extensions === '*') {
+                $cnt++;
+            } else {
+                $filename = $fileinfo->get_visible_name();
+                $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+                if (!empty($extension) && in_array('.'.$extension, $extensions)) {
+                    $cnt++;
+                }
+            }
+        }
+        return $cnt;
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info or null for root
diff --git a/lib/filebrowser/file_info_context_course.php b/lib/filebrowser/file_info_context_course.php
index 50876b3..0ee7402 100644
--- a/lib/filebrowser/file_info_context_course.php
+++ b/lib/filebrowser/file_info_context_course.php
@@ -350,49 +350,92 @@ class file_info_context_course extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
-        $children = array();
+        return $this->get_filtered_children('*', false, true);
+    }
 
-        if ($child = $this->get_area_course_summary(0, '/', '.')) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_course_section(null, null, null)) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_backup_section(null, null, null)) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_backup_course(0, '/', '.')) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_backup_automated(0, '/', '.')) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_course_legacy(0, '/', '.')) {
-            $children[] = $child;
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+        $areas = array(
+            array('course', 'summary'),
+            array('course', 'section'),
+            array('backup', 'section'),
+            array('backup', 'course'),
+            array('backup', 'automated'),
+            array('course', 'legacy')
+        );
+        $children = array();
+        foreach ($areas as $area) {
+            if ($child = $this->get_file_info($area[0], $area[1], 0, '/', '.')) {
+                if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+                    $children[] = $child;
+                    if ($countonly && count($children)>1) {
+                        return 2;
+                    }
+                }
+            }
         }
 
         if (!has_capability('moodle/course:managefiles', $this->context)) {
             // 'managefiles' capability is checked in every activity module callback.
             // Don't even waste time on retrieving the modules if we can't browse the files anyway
-            return $children;
-        }
-
-        // now list all modules
-        $modinfo = get_fast_modinfo($this->course);
-        foreach ($modinfo->cms as $cminfo) {
-            if (empty($cminfo->uservisible)) {
-                continue;
-            }
-            $modcontext = get_context_instance(CONTEXT_MODULE, $cminfo->id);
-            if ($child = $this->browser->get_file_info($modcontext)) {
-                $children[] = $child;
+        } else {
+            // now list all modules
+            $modinfo = get_fast_modinfo($this->course);
+            foreach ($modinfo->cms as $cminfo) {
+                if (empty($cminfo->uservisible)) {
+                    continue;
+                }
+                $modcontext = context_module::instance($cminfo->id, IGNORE_MISSING);
+                if ($child = $this->browser->get_file_info($modcontext)) {
+                    if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+                        $children[] = $child;
+                        if ($countonly && count($children)>1) {
+                            return 2;
+                        }
+                    }
+                }
             }
         }
 
+        if ($countonly) {
+            return count($children);
+        }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @todo error checking if get_parent_contextid() returns false
@@ -473,6 +516,37 @@ class file_info_area_course_legacy extends file_info_stored {
 
         return $result;
     }
+
+    /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        if (!$this->lf->is_directory()) {
+            return array();
+        }
+
+        $result = array();
+        $fs = get_file_storage();
+
+        $storedfiles = $fs->get_directory_files($this->context->id, 'course', 'legacy', 0,
+                                                $this->lf->get_filepath(), false, true, "filepath, filename");
+        foreach ($storedfiles as $file) {
+            $extension = strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+            if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
+                $fileinfo = new file_info_area_course_legacy($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
+                                                 $this->itemidused, $this->readaccess, $this->writeaccess, false);
+                if (!$file->is_directory() || $fileinfo->count_non_empty_children($extensions)) {
+                    $result[] = $fileinfo;
+                }
+            }
+        }
+
+        return $result;
+    }
 }
 
 /**
@@ -579,6 +653,35 @@ class file_info_area_course_section extends file_info {
     }
 
     /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        global $DB;
+        $params1 = array(
+            'courseid' => $this->course->id,
+            'contextid' => $this->context->id,
+            'component' => 'course',
+            'filearea' => 'section',
+            'emptyfilename' => '.');
+        $sql1 = "SELECT 1 from {files} f, {course_sections} cs
+            WHERE cs.course = :courseid
+            AND f.contextid = :contextid
+            AND f.component = :component
+            AND f.filearea = :filearea
+            AND f.itemid = cs.id
+            AND f.filename <> :emptyfilename";
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        return $DB->record_exists_sql($sql1.' '.$sql2, array_merge($params1, $params2)) ? 2 : 0;
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info|null file_info or null for root
@@ -690,6 +793,35 @@ class file_info_area_backup_section extends file_info {
     }
 
     /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        global $DB;
+        $params1 = array(
+            'courseid' => $this->course->id,
+            'contextid' => $this->context->id,
+            'component' => 'backup',
+            'filearea' => 'section',
+            'emptyfilename' => '.');
+        $sql1 = "SELECT 1 from {files} f, {course_sections} cs
+            WHERE cs.course = :courseid
+            AND f.contextid = :contextid
+            AND f.component = :component
+            AND f.filearea = :filearea
+            AND f.itemid = cs.id
+            AND f.filename <> :emptyfilename";
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        return $DB->record_exists_sql($sql1.' '.$sql2, array_merge($params1, $params2)) ? 2 : 0;
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info or null for root
diff --git a/lib/filebrowser/file_info_context_coursecat.php b/lib/filebrowser/file_info_context_coursecat.php
index 99b6d1f..97e3d91 100644
--- a/lib/filebrowser/file_info_context_coursecat.php
+++ b/lib/filebrowser/file_info_context_coursecat.php
@@ -189,6 +189,50 @@ class file_info_context_coursecat extends file_info {
     }
 
     /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        global $DB;
+        if (($child = $this->get_area_coursecat_description(0, '/', '.'))
+                && $child->count_non_empty_children($extensions)) {
+            return 2;
+        }
+
+        $course_cats = $DB->get_records('course_categories', array('parent'=>$this->category->id), 'sortorder', 'id,visible');
+        foreach ($course_cats as $category) {
+            $context = context_coursecat::instance($category->id);
+            if (!$category->visible and !has_capability('moodle/category:viewhiddencategories', $context)) {
+                continue;
+            }
+            if (($child = $this->browser->get_file_info($context))
+                    && $child->count_non_empty_children($extensions)) {
+                return 2;
+            }
+        }
+
+        $courses = $DB->get_records('course', array('category'=>$this->category->id), 'sortorder', 'id,visible');
+        foreach ($courses as $course) {
+            $context = context_course::instance($course->id);
+            if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
+                continue;
+            }
+            if (($child = $this->browser->get_file_info($context))
+                    && $child->count_non_empty_children($extensions)) {
+                return 2;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info|null fileinfo instance or null for root directory
diff --git a/lib/filebrowser/file_info_context_module.php b/lib/filebrowser/file_info_context_module.php
index 0357ee3..a873737 100644
--- a/lib/filebrowser/file_info_context_module.php
+++ b/lib/filebrowser/file_info_context_module.php
@@ -41,6 +41,8 @@ class file_info_context_module extends file_info {
     protected $modname;
     /** @var array Available file areas */
     protected $areas;
+    /** @var array caches the result of last call to get_non_empty_children() */
+    protected $nonemptychildren;
 
     /**
      * Constructor
@@ -58,6 +60,7 @@ class file_info_context_module extends file_info {
         $this->course  = $course;
         $this->cm      = $cm;
         $this->modname = $modname;
+        $this->nonemptychildren = null;
 
         include_once("$CFG->dirroot/mod/$modname/lib.php");
 
@@ -258,25 +261,94 @@ class file_info_context_module extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
-        $children = array();
+        return $this->get_filtered_children('*', false, true);
+    }
 
-        if ($child = $this->get_area_backup(0, '/', '.')) {
-            $children[] = $child;
-        }
-        if ($child = $this->get_area_intro(0, '/', '.')) {
-            $children[] = $child;
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+        global $DB;
+        // prepare list of areas including intro and backup
+        $areas = array(
+            array('mod_'.$this->modname, 'intro'),
+            array('backup', 'activity')
+        );
+        foreach ($this->areas as $area=>$desctiption) {
+            $areas[] = array('mod_'.$this->modname, $area);
         }
 
-        foreach ($this->areas as $area=>$desctiption) {
-            if ($child = $this->get_file_info('mod_'.$this->modname, $area, null, null, null)) {
-                $children[] = $child;
+        $params1 = array('contextid' => $this->context->id, 'emptyfilename' => '.');
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        $children = array();
+        foreach ($areas as $area) {
+            if (!$returnemptyfolders) {
+                // fast pre-check if there are any files in the filearea
+                $params1['component'] = $area[0];
+                $params1['filearea'] = $area[1];
+                if (!$DB->record_exists_sql('SELECT 1 from {files}
+                        WHERE contextid = :contextid
+                        AND filename <> :emptyfilename
+                        AND component = :component
+                        AND filearea = :filearea '.$sql2,
+                        array_merge($params1, $params2))) {
+                    continue;
+                }
+            }
+            if ($child = $this->get_file_info($area[0], $area[1], null, null, null)) {
+                if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+                    $children[] = $child;
+                    if ($countonly && count($children)>1) {
+                        break;
+                    }
+                }
             }
         }
-
+        if ($countonly) {
+            return count($children);
+        }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        global $DB;
+        if ($this->nonemptychildren !== null) {
+            return $this->nonemptychildren;
+        }
+        $this->nonemptychildren = $this->get_filtered_children($extensions);
+        return $this->nonemptychildren;
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        global $DB;
+        if ($this->nonemptychildren !== null) {
+            return count($this->nonemptychildren);
+        }
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info|null file_info or null for root
diff --git a/lib/filebrowser/file_info_stored.php b/lib/filebrowser/file_info_stored.php
index 44fa566..1c4d2d2 100644
--- a/lib/filebrowser/file_info_stored.php
+++ b/lib/filebrowser/file_info_stored.php
@@ -351,6 +351,70 @@ class file_info_stored extends file_info {
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        $result = array();
+        if (!$this->lf->is_directory()) {
+            return $result;
+        }
+
+        $fs = get_file_storage();
+
+        $storedfiles = $fs->get_directory_files($this->context->id, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(),
+                                                $this->lf->get_filepath(), false, true, "filepath, filename");
+        foreach ($storedfiles as $file) {
+            $extension = strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+            if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
+                $fileinfo = new file_info_stored($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
+                                                 $this->itemidused, $this->readaccess, $this->writeaccess, false);
+                if (!$file->is_directory() || $fileinfo->count_non_empty_children($extensions)) {
+                    $result[] = $fileinfo;
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        global $DB;
+        if (!$this->lf->is_directory()) {
+            return 0;
+        }
+
+        $filepath = $this->lf->get_filepath();
+        $length = textlib::strlen($filepath);
+        $sql = "SELECT 1
+                  FROM {files} f
+                 WHERE f.contextid = :contextid AND f.component = :component AND f.filearea = :filearea AND f.itemid = :itemid
+                       AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
+                       AND filename <> '.' ";
+        $params = array('contextid' => $this->context->id,
+            'component' => $this->lf->get_component(),
+            'filearea' => $this->lf->get_filearea(),
+            'itemid' => $this->lf->get_itemid(),
+            'filepath' => $filepath);
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        // we don't need to check access to individual files here, since the user can access parent
+        return $DB->record_exists_sql($sql.' '.$sql2, array_merge($params, $params2)) ? 2 : 0;
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info|null file_info instance or null for root
diff --git a/mod/book/locallib.php b/mod/book/locallib.php
index 26d0e40..eba2e52 100644
--- a/mod/book/locallib.php
+++ b/mod/book/locallib.php
@@ -448,19 +448,86 @@ class book_file_info extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
+        return $this->get_filtered_children('*', false, true);
+    }
+
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
         global $DB;
+        $params = array('contextid' => $this->context->id,
+            'component' => 'mod_book',
+            'filearea' => $this->filearea,
+            'bookid' => $this->cm->instance);
+        $sql = 'SELECT DISTINCT bc.id, bc.pagenum
+                    FROM {files} f, {book_chapters} bc
+                    WHERE f.contextid = :contextid
+                    AND f.component = :component
+                    AND f.filearea = :filearea
+                    AND bc.bookid = :bookid
+                    AND bc.id = f.itemid';
+        if (!$returnemptyfolders) {
+            $sql .= ' AND filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY bc.pagenum';
+        }
 
+        $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        $chapters = $DB->get_records('book_chapters', array('bookid'=>$this->cm->instance), 'pagenum', 'id, pagenum');
-        foreach ($chapters as $itemid => $unused) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $itemid)) {
-                $children[] = $child;
+        foreach ($rs as $record) {
+            if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $record->id)) {
+                if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+                    $children[] = $child;
+                }
+            }
+            if ($countonly && count($children)>1) {
+                break;
             }
         }
+        $rs->close();
+        if ($countonly) {
+            return count($children);
+        }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      * @return file_info or null for root
      */
diff --git a/mod/data/locallib.php b/mod/data/locallib.php
index e06430a..16c25c7 100644
--- a/mod/data/locallib.php
+++ b/mod/data/locallib.php
@@ -493,21 +493,81 @@ class data_file_info_container extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
+        return $this->get_filtered_children('*', false, true);
+    }
+
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
         global $DB;
+        $params = array('contextid' => $this->context->id,
+            'component' => $this->component,
+            'filearea' => $this->filearea);
+        $sql = 'SELECT DISTINCT itemid
+                    FROM {files}
+                    WHERE contextid = :contextid
+                    AND component = :component
+                    AND filearea = :filearea';
+        if (!$returnemptyfolders) {
+            $sql .= ' AND filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY itemid DESC';
+        }
 
+        $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'component' => $this->component,
-            'filearea' => $this->filearea), 'itemid DESC', "DISTINCT itemid");
-        foreach ($itemids as $itemid => $unused) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $itemid)) {
+        foreach ($rs as $record) {
+            if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $record->itemid)) {
                 $children[] = $child;
             }
+            if ($countonly && count($children)>1) {
+                break;
+            }
+        }
+        $rs->close();
+        if ($countonly) {
+            return count($children);
         }
-
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info or null for root
diff --git a/mod/forum/locallib.php b/mod/forum/locallib.php
index dd1b3af..f8840b6 100644
--- a/mod/forum/locallib.php
+++ b/mod/forum/locallib.php
@@ -484,21 +484,81 @@ class forum_file_info_container extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
+        return $this->get_filtered_children('*', false, true);
+    }
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
         global $DB;
+        $params = array('contextid' => $this->context->id,
+            'component' => $this->component,
+            'filearea' => $this->filearea);
+        $sql = 'SELECT DISTINCT itemid
+                    FROM {files}
+                    WHERE contextid = :contextid
+                    AND component = :component
+                    AND filearea = :filearea';
+        if (!$returnemptyfolders) {
+            $sql .= ' AND filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY itemid DESC';
+        }
 
+        $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'component' => $this->component,
-            'filearea' => $this->filearea), 'itemid DESC', "DISTINCT itemid");
-        foreach ($itemids as $itemid => $unused) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_forum', $this->filearea, $itemid)) {
+        foreach ($rs as $record) {
+            if (($child = $this->browser->get_file_info($this->context, 'mod_forum', $this->filearea, $record->itemid))
+                    && ($returnemptyfolders || $child->count_non_empty_children($extensions))) {
                 $children[] = $child;
             }
+            if ($countonly && count($children)>1) {
+                break;
+            }
+        }
+        $rs->close();
+        if ($countonly) {
+            return count($children);
         }
-
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info or null for root
diff --git a/mod/glossary/locallib.php b/mod/glossary/locallib.php
index 2f0b448..e848138 100644
--- a/mod/glossary/locallib.php
+++ b/mod/glossary/locallib.php
@@ -540,31 +540,88 @@ class glossary_file_info_container extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
-        global $DB;
+        return $this->get_filtered_children('*', false, true);
+    }
 
-        $sql = "SELECT DISTINCT f.itemid, ge.concept
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+        global $DB;
+        $sql = 'SELECT DISTINCT f.itemid, ge.concept
                   FROM {files} f
-                  JOIN {modules} m ON (m.name = 'glossary' AND m.visible = 1)
-                  JOIN {course_modules} cm ON (cm.module = m.id AND cm.id = ?)
+                  JOIN {modules} m ON (m.name = :modulename AND m.visible = 1)
+                  JOIN {course_modules} cm ON (cm.module = m.id AND cm.id = :instanceid)
                   JOIN {glossary} g ON g.id = cm.instance
                   JOIN {glossary_entries} ge ON (ge.glossaryid = g.id AND ge.id = f.itemid)
-                 WHERE f.contextid = ? AND f.component = ? AND f.filearea = ?
-              ORDER BY ge.concept, f.itemid";
-        $params = array($this->context->instanceid, $this->context->id, $this->component, $this->filearea);
+                 WHERE f.contextid = :contextid
+                  AND f.component = :component
+                  AND f.filearea = :filearea';
+        $params = array(
+            'modulename' => 'glossary',
+            'instanceid' => $this->context->instanceid,
+            'contextid' => $this->context->id,
+            'component' => $this->component,
+            'filearea' => $this->filearea);
+        if (!$returnemptyfolders) {
+            $sql .= ' AND f.filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY ge.concept, f.itemid';
+        }
 
         $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        foreach ($rs as $file) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $file->itemid)) {
+        foreach ($rs as $record) {
+            if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $record->itemid)) {
                 $children[] = $child;
             }
+            if ($countonly && count($children)>1) {
+                break;
+            }
         }
         $rs->close();
-
+        if ($countonly) {
+            return count($children);
+        }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      *
      * @return file_info or null for root
diff --git a/mod/imscp/locallib.php b/mod/imscp/locallib.php
index 6eb6ebb..bff1b0e 100644
--- a/mod/imscp/locallib.php
+++ b/mod/imscp/locallib.php
@@ -273,19 +273,81 @@ class imscp_file_info extends file_info {
      * @return array of file_info instances
      */
     public function get_children() {
+        return $this->get_filtered_children('*', false, true);
+    }
+
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
         global $DB;
+        $params = array('contextid' => $this->context->id,
+            'component' => 'mod_imscp',
+            'filearea' => $this->filearea);
+        $sql = 'SELECT DISTINCT itemid
+                    FROM {files}
+                    WHERE contextid = :contextid
+                    AND component = :component
+                    AND filearea = :filearea';
+        if (!$returnemptyfolders) {
+            $sql .= ' AND filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY itemid';
+        }
 
+        $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        $itemids = $DB->get_records('files', array('contextid'=>$this->context->id, 'component'=>'mod_imscp', 'filearea'=>$this->filearea), 'itemid', "DISTINCT itemid");
-        foreach ($itemids as $itemid=>$unused) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_imscp', $this->filearea, $itemid)) {
+        foreach ($rs as $record) {
+            if ($child = $this->browser->get_file_info($this->context, 'mod_imscp', $this->filearea, $record->itemid)) {
                 $children[] = $child;
             }
+            if ($countonly && count($children)>1) {
+                break;
+            }
+        }
+        $rs->close();
+        if ($countonly) {
+            return count($children);
         }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      * @return file_info or null for root
      */
diff --git a/mod/workshop/fileinfolib.php b/mod/workshop/fileinfolib.php
index 5a8b4a2..eb1a3bf 100644
--- a/mod/workshop/fileinfolib.php
+++ b/mod/workshop/fileinfolib.php
@@ -87,25 +87,88 @@ class workshop_file_info_submissions_container extends file_info {
         return true;
     }
 
+
     /**
-     * Returns list of children.
+     * Returns list of children nodes
+     *
      * @return array of file_info instances
      */
     public function get_children() {
+        return $this->get_filtered_children('*', false, true);
+    }
+    /**
+     * Help function to return files matching extensions or their count
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+     * @return array|int array of file_info instances or the count
+     */
+    private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
         global $DB;
+        $params = array('contextid' => $this->context->id,
+            'component' => 'mod_workshop',
+            'filearea' => $this->filearea);
+        $sql = 'SELECT DISTINCT itemid
+                    FROM {files}
+                    WHERE contextid = :contextid
+                    AND component = :component
+                    AND filearea = :filearea';
+        if (!$returnemptyfolders) {
+            $sql .= ' AND filename <> :emptyfilename';
+            $params['emptyfilename'] = '.';
+        }
+        list($sql2, $params2) = $this->build_search_files_sql($extensions);
+        $sql .= ' '.$sql2;
+        $params = array_merge($params, $params2);
+        if (!$countonly) {
+            $sql .= ' ORDER BY itemid DESC';
+        }
 
+        $rs = $DB->get_recordset_sql($sql, $params);
         $children = array();
-        $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'component' => 'mod_workshop', 'filearea' => $this->filearea),
-            'itemid', "DISTINCT itemid");
-        foreach ($itemids as $itemid => $unused) {
-            if ($child = $this->browser->get_file_info($this->context, 'mod_workshop', $this->filearea, $itemid)) {
+        foreach ($rs as $record) {
+            if (($child = $this->browser->get_file_info($this->context, 'mod_workshop', $this->filearea, $record->itemid))
+                    && ($returnemptyfolders || $child->count_non_empty_children($extensions))) {
                 $children[] = $child;
             }
+            if ($countonly && count($children)>1) {
+                break;
+            }
+        }
+        $rs->close();
+        if ($countonly) {
+            return count($children);
         }
         return $children;
     }
 
     /**
+     * Returns list of children which are either files matching the specified extensions
+     * or folders that contain at least one such file.
+     *
+     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @return array of file_info instances
+     */
+    public function get_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, false);
+    }
+
+    /**
+     * Returns the number of children which are either files matching the specified extensions
+     * or folders containing at least one such file.
+     *
+     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * In this function 1 is never returned to avoid skipping the single subfolder
+     *
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return int
+     */
+    public function count_non_empty_children($extensions = '*') {
+        return $this->get_filtered_children($extensions, true);
+    }
+
+    /**
      * Returns parent file_info instance
      * @return file_info or null for root
      */
diff --git a/repository/local/lib.php b/repository/local/lib.php
index d8898bf..a0b77a5 100644
--- a/repository/local/lib.php
+++ b/repository/local/lib.php
@@ -29,22 +29,16 @@ require_once($CFG->dirroot . '/repository/lib.php');
  *
  * @since 2.0
  * @package    repository_local
+ * @copyright  2012 Marina Glancy
  * @copyright  2009 Dongsheng Cai {@link http://dongsheng.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class repository_local extends repository {
     /**
-     * local plugin doesn't require login, so list all files
-     * @return mixed
-     */
-    public function print_login() {
-        return $this->get_listing();
-    }
-
-    /**
      * Get file listing
      *
      * @param string $encodedpath
+     * @param string $page no paging is used in repository_local
      * @return mixed
      */
     public function get_listing($encodedpath = '', $page = '') {
@@ -53,11 +47,17 @@ class repository_local extends repository {
         $ret['dynload'] = true;
         $ret['nosearch'] = true;
         $ret['nologin'] = true;
-        $list = array();
+        $ret['list'] = array();
+
+        $itemid   = null;
+        $filename = null;
+        $filearea = null;
+        $filepath = null;
+        $component = null;
 
         if (!empty($encodedpath)) {
             $params = unserialize(base64_decode($encodedpath));
-            if (is_array($params)) {
+            if (is_array($params) && isset($params['contextid'])) {
                 $component = is_null($params['component']) ? NULL : clean_param($params['component'], PARAM_COMPONENT);
                 $filearea  = is_null($params['filearea']) ? NULL : clean_param($params['filearea'], PARAM_AREA);
                 $itemid    = is_null($params['itemid']) ? NULL : clean_param($params['itemid'], PARAM_INT);
@@ -65,52 +65,54 @@ class repository_local extends repository {
                 $filename  = is_null($params['filename']) ? NULL : clean_param($params['filename'], PARAM_FILE);
                 $context = get_context_instance_by_id(clean_param($params['contextid'], PARAM_INT));
             }
+        }
+        if (empty($context) && !empty($this->context)) {
+            list($repositorycontext, $course, $cm) = get_context_info_array($this->context->id);
+            if (isset($course->id)) {
+                $context = context_course::instance($course->id);
+            }
+        }
+        if (empty($context)) {
+            $context = context_system::instance();
+        }
+
+        // prepare list of allowed extensions: $extensions is either string '*'
+        // or array of lowercase extensions, i.e. array('.gif','.jpg')
+        $extensions = optional_param_array('accepted_types', '', PARAM_RAW);
+        if (empty($extensions) || $extensions === '*' || (is_array($extensions) && in_array('*', $extensions))) {
+            $extensions = '*';
         } else {
-            $itemid   = null;
-            $filename = null;
-            $filearea = null;
-            $filepath = null;
-            $component = null;
-            if (!empty($this->context)) {
-                list($context, $course, $cm) = get_context_info_array($this->context->id);
-                if (is_object($course)) {
-                    $context = get_context_instance(CONTEXT_COURSE, $course->id);
-                } else {
-                    $context = get_system_context();
-                }
-            } else {
-                $context = get_system_context();
+            if (!is_array($extensions)) {
+                $extensions = array($extensions);
             }
+            $extensions = array_map('strtolower', $extensions);
         }
 
+        // build file tree
         $browser = get_file_browser();
-
-        $list = array();
-        if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
-            // build file tree
-            $element = repository_local_file::retrieve_file_info($fileinfo, $this);
-            $nonemptychildren = $element->get_non_empty_children();
-            foreach ($nonemptychildren as $child) {
-                $list[] = (array)$child->get_node();
-            }
-        } else {
+        if (!($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename))) {
             // if file doesn't exist, build path nodes root of current context
             $fileinfo = $browser->get_file_info($context, null, null, null, null, null);
         }
+        $ret['list'] = $this->get_non_empty_children($fileinfo, $extensions);
+
         // build path navigation
+        $path = array();
+        for ($level = $fileinfo; $level; $level = $level->get_parent()) {
+            array_unshift($path, $level);
+        }
+        array_unshift($path, null);
         $ret['path'] = array();
-        $element = repository_local_file::retrieve_file_info($fileinfo, $this);
-        for ($level = $element; $level; $level = $level->get_parent()) {
-            if ($level == $element || !$level->can_skip()) {
-                array_unshift($ret['path'], $level->get_node_path());
+        for ($i=1; $i<count($path); $i++) {
+            if ($path[$i] == $fileinfo || !$this->can_skip($path[$i], $extensions, $path[$i-1])) {
+                $ret['path'][] = $this->get_node_path($path[$i]);
             }
         }
-        $ret['list'] = array_filter($list, array($this, 'filter'));
         return $ret;
     }
 
     /**
-     * Local file don't support to link to external links
+     * Tells how the file can be picked from this repository
      *
      * @return int
      */
@@ -137,111 +139,112 @@ class repository_local extends repository {
         // this should be realtime
         return 0;
     }
-}
-
-/**
- * Class to cache some information about file
- *
- * This class is a wrapper to instances of file_info. It caches such information as
- * parent and list of children. It also stores an array of already retrieved elements.
- *
- * It also implements more comprehensive algorithm for checking if folder is empty
- * (taking into account the filtering of the files). To decrease number of levels
- * we check if some subfolders can be skipped from the tree.
- *
- * As a result we display in Server files repository only non-empty folders and skip
- * filearea folders if this is the only filearea in the module.
- * For non-admin the course categories are not shown as well (courses are shown as a list)
- *
- * @package    repository_local
- * @copyright  2012 Marina Glancy
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class repository_local_file {
-    /** @var array stores already retrieved files */
-    private static $cachedfiles = array();
-    /** @var file_info Stores the original file */
-    public $fileinfo;
-    /** @var bool whether this file is directory */
-    private $isdir;
-    /** @var array caches retrieved children */
-    private $children = null;
-    /** @var array caches retrieved information whether this file is an empty directory */
-    protected $isempty = null;
-    /** @var repository link to the container repository (for filtering the results) */
-    private $repository;
-    /** @var repository_local_file link to parent directory */
-    protected $parent;
-    /** @var bool caches calculated information on whether this directory must be skipped in the tree */
-    private $skip = null;
 
     /**
-     * Creates (or retrieves from cache) the repository_local_file object for $file_info
+     * Returns all children elements that have one of the specified extensions
+     *
+     * This function may skip subfolers and recursively add their children
+     * {@link repository_local::can_skip()}
      *
      * @param file_info $fileinfo
-     * @param repository $repository
-     * @param repository_local_file $parent
-     * @return repository_local_file
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @return array array of file_info elements
      */
-    public static function retrieve_file_info(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
-        $encodedpath = base64_encode(serialize($fileinfo->get_params()));
-        if (!isset(self::$cachedfiles[$encodedpath])) {
-            self::$cachedfiles[$encodedpath] = new repository_local_file($fileinfo, $repository, $parent);
+    private function get_non_empty_children(file_info $fileinfo, $extensions) {
+        $nonemptychildren = $fileinfo->get_non_empty_children($extensions);
+        $list = array();
+        foreach ($nonemptychildren as $child) {
+            if ($this->can_skip($child, $extensions, $fileinfo)) {
+                $list = array_merge($list, $this->get_non_empty_children($child, $extensions));
+            } else {
+                $list[] = $this->get_node($child);
+            }
         }
-        return self::$cachedfiles[$encodedpath];
+        return $list;
     }
 
     /**
-     * Creates an object
+     * Wether this folder may be skipped in folder hierarchy
+     *
+     * 1. Skip the name of a single filearea in a module
+     * 2. Skip course categories for non-admins who do not have navshowmycoursecategories setting
      *
      * @param file_info $fileinfo
-     * @param repository $repository
-     * @param repository_local_file $parent
+     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param file_info|int $parent specify parent here if we know it to avoid creating extra objects
+     * @return bool
      */
-    private function __construct(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
-        $this->repository = $repository;
-        $this->fileinfo = $fileinfo;
-        $this->isdir = $fileinfo->is_directory();
-        if (!$this->isdir) {
-            $node = array('title' => $this->fileinfo->get_visible_name());
-            $this->isempty = !$repository->filter($node);
-            $this->skip = false;
+    private function can_skip(file_info $fileinfo, $extensions, $parent = -1) {
+        global $CFG;
+        static $skipcategories = null;
+        if (!$fileinfo->is_directory()) {
+            // do not skip files
+            return false;
         }
+        if ($fileinfo instanceof file_info_context_coursecat) {
+            // This is a course category. For non-admins we do not display categories
+            return empty($CFG->navshowmycoursecategories) &&
+                            !has_capability('moodle/course:update', context_system::instance());
+        } else if ($fileinfo instanceof file_info_context_course ||
+                $fileinfo instanceof file_info_context_user ||
+                $fileinfo instanceof file_info_area_course_legacy ||
+                $fileinfo instanceof file_info_context_module ||
+                $fileinfo instanceof file_info_context_system) {
+            // these instances can never be filearea inside an activity, they will never be skipped
+            return false;
+        } else {
+            $params = $fileinfo->get_params();
+            if (strlen($params['filearea']) &&
+                    ($params['filepath'] === '/' || empty($params['filepath'])) &&
+                    ($params['filename'] === '.' || empty($params['filename']))) {
+                if ($parent === -1) {
+                    $parent = $fileinfo->get_parent();
+                }
+                // This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
+                if ($parent && ($parent instanceof file_info_context_module)) {
+                    if ($parent->count_non_empty_children($extensions) <= 1) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /**
-     * Returns node for $ret['list']
+     * Converts file_info object to element of repository return list
      *
+     * @param file_info $fileinfo
      * @return array
      */
-    public function get_node() {
+    private function get_node(file_info $fileinfo) {
         global $OUTPUT;
-        $encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
+        $encodedpath = base64_encode(serialize($fileinfo->get_params()));
         $node = array(
-            'title' => $this->fileinfo->get_visible_name(),
-            'datemodified' => $this->fileinfo->get_timemodified(),
-            'datecreated' => $this->fileinfo->get_timecreated()
+            'title' => $fileinfo->get_visible_name(),
+            'datemodified' => $fileinfo->get_timemodified(),
+            'datecreated' => $fileinfo->get_timecreated()
         );
-        if ($this->isdir) {
+        if ($fileinfo->is_directory()) {
             $node['path'] = $encodedpath;
             $node['thumbnail'] = $OUTPUT->pix_url(file_folder_icon(90))->out(false);
             $node['children'] = array();
         } else {
-            $node['size'] = $this->fileinfo->get_filesize();
-            $node['author'] = $this->fileinfo->get_author();
-            $node['license'] = $this->fileinfo->get_license();
-            $node['isref'] = $this->fileinfo->is_external_file();
-            if ($this->fileinfo->get_status() == 666) {
+            $node['size'] = $fileinfo->get_filesize();
+            $node['author'] = $fileinfo->get_author();
+            $node['license'] = $fileinfo->get_license();
+            $node['isref'] = $fileinfo->is_external_file();
+            if ($fileinfo->get_status() == 666) {
                 $node['originalmissing'] = true;
             }
             $node['source'] = $encodedpath;
-            $node['thumbnail'] = $OUTPUT->pix_url(file_file_icon($this->fileinfo, 90))->out(false);
-            $node['icon'] = $OUTPUT->pix_url(file_file_icon($this->fileinfo, 24))->out(false);
-            if ($imageinfo = $this->fileinfo->get_imageinfo()) {
+            $node['thumbnail'] = $OUTPUT->pix_url(file_file_icon($fileinfo, 90))->out(false);
+            $node['icon'] = $OUTPUT->pix_url(file_file_icon($fileinfo, 24))->out(false);
+            if ($imageinfo = $fileinfo->get_imageinfo()) {
                 // what a beautiful picture, isn't it
-                $fileurl = new moodle_url($this->fileinfo->get_url());
-                $node['realthumbnail'] = $fileurl->out(false, array('preview' => 'thumb', 'oid' => $this->fileinfo->get_timemodified()));
-                $node['realicon'] = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $this->fileinfo->get_timemodified()));
+                $fileurl = new moodle_url($fileinfo->get_url());
+                $node['realthumbnail'] = $fileurl->out(false, array('preview' => 'thumb', 'oid' => $fileinfo->get_timemodified()));
+                $node['realicon'] = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
                 $node['image_width'] = $imageinfo['width'];
                 $node['image_height'] = $imageinfo['height'];
             }
@@ -250,155 +253,16 @@ class repository_local_file {
     }
 
     /**
-     * Returns node for $ret['path']
+     * Converts file_info object to element of repository return path
      *
+     * @param file_info $fileinfo
      * @return array
      */
-    public function get_node_path() {
-        $encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
+    private function get_node_path(file_info $fileinfo) {
+        $encodedpath = base64_encode(serialize($fileinfo->get_params()));
         return array(
             'path' => $encodedpath,
-            'name' => $this->fileinfo->get_visible_name()
+            'name' => $fileinfo->get_visible_name()
         );
     }
-
-    /**
-     * Checks if this is a directory
-     *
-     * @return bool
-     */
-    public function is_dir() {
-        return $this->isdir;
-    }
-
-    /**
-     * Returns children of this element
-     *
-     * @return array
-     */
-    public function get_children() {
-        if (!$this->isdir) {
-            return array();
-        }
-        if ($this->children === null) {
-            $this->children = array();
-            $children = $this->fileinfo->get_children();
-            for ($i=0; $i<count($children); $i++) {
-                $this->children[] = self::retrieve_file_info($children[$i], $this->repository, $this);
-            }
-        }
-        return $this->children;
-    }
-
-    /**
-     * Checks if this folder is empty (contains no non-empty children)
-     *
-     * @return bool
-     */
-    public function is_empty() {
-        if ($this->isempty === null) {
-            $this->isempty = true;
-            if (!$this->fileinfo->is_empty_area()) {
-                // even if is_empty_area() returns false, element still may be empty
-                $children = $this->get_children();
-                if (!empty($children)) {
-                    // 1. Let's look at already retrieved children
-                    foreach ($children as $childnode) {
-                        if ($childnode->isempty === false) {
-                            // we already calculated isempty for a child, and it is not empty
-                            $this->isempty = false;
-                            break;
-                        }
-                    }
-                    if ($this->isempty) {
-                        // 2. now we know that this directory contains children that are either empty or we don't know
-                        foreach ($children as $childnode) {
-                            if (!$childnode->is_empty()) {
-                                $this->isempty = false;
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return $this->isempty;
-    }
-
-    /**
-     * Returns the parent element
-     *
-     * @return repository_local_file
-     */
-    public function get_parent() {
-        if ($this->parent === null) {
-            if ($parent = $this->fileinfo->get_parent()) {
-                $this->parent = self::retrieve_file_info($parent, $this->repository);
-            } else {
-                $this->parent = false;
-            }
-        }
-        return $this->parent;
-    }
-
-    /**
-     * Wether this folder may be skipped in tree view
-     *
-     * @return bool
-     */
-    public function can_skip() {
-        global $CFG;
-        if ($this->skip === null) {
-            $this->skip = false;
-            if ($this->fileinfo instanceof file_info_stored) {
-                $params = $this->fileinfo->get_params();
-                if (strlen($params['filearea']) && $params['filepath'] == '/' && $params['filename'] == '.') {
-                    // This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
-                    if ($parent = $this->get_parent()) {
-                        $siblings = $parent->get_children();
-                        $countnonempty = 0;
-                        foreach ($siblings as $sibling) {
-                            if (!$sibling->is_empty()) {
-                                $countnonempty++;
-                                if ($countnonempty > 1) {
-                                    break;
-                                }
-                            }
-                        }
-                        if ($countnonempty <= 1) {
-                            $this->skip = true;
-                        }
-                    }
-                }
-            } else if ($this->fileinfo instanceof file_info_context_coursecat) {
-                // This is a course category. For non-admins we do not display categories
-                $this->skip = empty($CFG->navshowmycoursecategories) &&
-                        !has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM));
-            }
-        }
-        return $this->skip;
-    }
-
-    /**
-     * Returns array of children who have any elmenets
-     *
-     * If a subfolder can be skipped - list children of subfolder instead
-     * (recursive function)
-     *
-     * @return array
-     */
-    public function get_non_empty_children() {
-        $children = $this->get_children();
-        $nonemptychildren = array();
-        foreach ($children as $child) {
-            if (!$child->is_empty()) {
-                if ($child->can_skip()) {
-                    $nonemptychildren = array_merge($nonemptychildren, $child->get_non_empty_children());
-                } else {
-                    $nonemptychildren[] = $child;
-                }
-            }
-        }
-        return $nonemptychildren;
-    }
 }
-- 
1.7.9.5


From 1ab628b72e3a4182583824c58cfec5409e3fd25b Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Mon, 9 Jul 2012 10:49:11 +0800
Subject: [PATCH 619/903] MDL-34223 increased performance in
 forum_get_file_info() for admins

---
 mod/forum/lib.php |   33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 7c4ed9d..4556123 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -4106,15 +4106,34 @@ function forum_get_file_info($browser, $areas, $course, $cm, $context, $filearea
         return new forum_file_info_container($browser, $course, $cm, $context, $areas, $filearea);
     }
 
-    if (!$post = $DB->get_record('forum_posts', array('id' => $itemid))) {
+    static $cached = array();
+    // $cached will store last retrieved post, discussion and forum. To make sure that the cache
+    // is cleared between unit tests we check if this is the same session
+    if (!isset($cached['sesskey']) || $cached['sesskey'] != sesskey()) {
+        $cached = array('sesskey' => sesskey());
+    }
+
+    if (isset($cached['post']) && $cached['post']->id == $itemid) {
+        $post = $cached['post'];
+    } else if ($post = $DB->get_record('forum_posts', array('id' => $itemid))) {
+        $cached['post'] = $post;
+    } else {
         return null;
     }
 
-    if (!$discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
+    if (isset($cached['discussion']) && $cached['discussion']->id == $post->discussion) {
+        $discussion = $cached['discussion'];
+    } else if ($discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
+        $cached['discussion'] = $discussion;
+    } else {
         return null;
     }
 
-    if (!$forum = $DB->get_record('forum', array('id' => $cm->instance))) {
+    if (isset($cached['forum']) && $cached['forum']->id == $cm->instance) {
+        $forum = $cached['forum'];
+    } else if ($forum = $DB->get_record('forum', array('id' => $cm->instance))) {
+        $cached['forum'] = $forum;
+    } else {
         return null;
     }
 
@@ -4131,12 +4150,10 @@ function forum_get_file_info($browser, $areas, $course, $cm, $context, $filearea
         return null;
     }
     // Make sure groups allow this user to see this file
-    if ($discussion->groupid > 0) {
+    if ($discussion->groupid > 0 && !has_capability('moodle/site:accessallgroups', $context)) {
         $groupmode = groups_get_activity_groupmode($cm, $course);
-        if ($groupmode == SEPARATEGROUPS) {
-            if (!groups_is_member($discussion->groupid) and !has_capability('moodle/site:accessallgroups', $context)) {
-                return null;
-            }
+        if ($groupmode == SEPARATEGROUPS && !groups_is_member($discussion->groupid)) {
+            return null;
         }
     }
 
-- 
1.7.9.5


From ceed31ad6b59ab3e22fd65e67ab0e1c08a123082 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 11 Sep 2012 11:53:26 +0800
Subject: [PATCH 620/903] MDL-34765 Course: Fixed missing argument in course
 reordering

---
 course/category.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/category.php b/course/category.php
index b0b5684..a04e499 100644
--- a/course/category.php
+++ b/course/category.php
@@ -76,7 +76,7 @@ $sesskeyprovided = !empty($sesskey) && confirm_sesskey($sesskey);
 // Process any category actions.
 if ($canmanage && $resort && $sesskeyprovided) {
     // Resort the category if requested
-    if ($courses = get_courses($category->id, 'c.id,c.fullname,c.sortorder')) {
+    if ($courses = get_courses($category->id, '', 'c.id,c.fullname,c.sortorder')) {
         collatorlib::asort_objects_by_property($courses, 'fullname', collatorlib::SORT_NATURAL);
         $i = 1;
         foreach ($courses as $course) {
-- 
1.7.9.5


From e0c567c3bedb18fd68d5a049d254f689ad0187a3 Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Tue, 21 Aug 2012 15:13:00 +0800
Subject: [PATCH 621/903] MDL-29463 - Chat - Change socket_setopt to
 socket_set_options

---
 mod/chat/chatd.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mod/chat/chatd.php b/mod/chat/chatd.php
index f43bdee..51951d9 100644
--- a/mod/chat/chatd.php
+++ b/mod/chat/chatd.php
@@ -835,7 +835,7 @@ EOD;
 
         // [pj]: I really must have a good read on sockets. What exactly does this do?
         // http://www.unixguide.net/network/socketfaq/4.5.shtml is still not enlightening enough for me.
-        socket_setopt($this->listen_socket, SOL_SOCKET, SO_REUSEADDR, 1);
+        socket_set_option($this->listen_socket, SOL_SOCKET, SO_REUSEADDR, 1);
         socket_set_nonblock($this->listen_socket);
     }
 
@@ -935,8 +935,8 @@ if(!$DAEMON->query_start()) {
     die();
 }
 
-if (!function_exists('socket_setopt')) {
-    echo "Error: Function socket_setopt() does not exist.\n";
+if (!function_exists('socket_set_option')) {
+    echo "Error: Function socket_set_option() does not exist.\n";
     echo "Possibly PHP has not been compiled with --enable-sockets.\n\n";
     die();
 }
-- 
1.7.9.5


From 6b43759eff5de266f21f681f1d1a1dae6fb13da2 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Tue, 11 Sep 2012 12:27:17 -0700
Subject: [PATCH 622/903] MDL-35374 - Cannot delete blocks off frontpage

---
 lib/blocklib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/blocklib.php b/lib/blocklib.php
index 1986c09..47885c9 100644
--- a/lib/blocklib.php
+++ b/lib/blocklib.php
@@ -1158,7 +1158,7 @@ class block_manager {
             $PAGE->set_title($blocktitle . ': ' . $strdeletecheck);
             $PAGE->set_heading($site->fullname);
             echo $OUTPUT->header();
-            $confirmurl = new moodle_url("$deletepage->url?", array('sesskey' => sesskey(), 'bui_deleteid' => $block->instance->id, 'bui_confirm' => 1));
+            $confirmurl = new moodle_url($deletepage->url, array('sesskey' => sesskey(), 'bui_deleteid' => $block->instance->id, 'bui_confirm' => 1));
             $cancelurl = new moodle_url($deletepage->url);
             $yesbutton = new single_button($confirmurl, get_string('yes'));
             $nobutton = new single_button($cancelurl, get_string('no'));
-- 
1.7.9.5


From 102d0bd05b6e054e6943f17cd3ef1db5d8e4cfa3 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Tue, 11 Sep 2012 14:23:12 -0700
Subject: [PATCH 623/903] MDL-35376 - Shortcut/alias not working for Private
 file repo

---
 lib/filelib.php                  |    2 +-
 lib/filestorage/file_storage.php |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/filelib.php b/lib/filelib.php
index df23d91..7c2087e 100644
--- a/lib/filelib.php
+++ b/lib/filelib.php
@@ -832,7 +832,7 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
             if ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) {
                 $oldfile->replace_content_with($newfile);
                 // push changes to all local files that are referencing this file
-                $fs->update_references_to_storedfile($this);
+                $fs->update_references_to_storedfile($oldfile);
             }
 
             // unchanged file or directory - we keep it as is
diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index ae8df9c..917705b 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -1821,7 +1821,7 @@ class file_storage {
      * @param stored_file $storedfile
      */
     public function update_references_to_storedfile(stored_file $storedfile) {
-        global $CFG;
+        global $CFG, $DB;
         $params = array();
         $params['contextid'] = $storedfile->get_contextid();
         $params['component'] = $storedfile->get_component();
-- 
1.7.9.5


From 7737d24b92a9da6fccfd6120072f477d05baa88d Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Wed, 12 Sep 2012 13:52:50 +0800
Subject: [PATCH 624/903] MDL-35264 mod_chat Bigger frame for text input

---
 mod/chat/gui_sockets/index.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/chat/gui_sockets/index.php b/mod/chat/gui_sockets/index.php
index 4a5de8b..ab3d83b 100644
--- a/mod/chat/gui_sockets/index.php
+++ b/mod/chat/gui_sockets/index.php
@@ -64,7 +64,7 @@ $courseshortname = format_string($course->shortname, true, array('context' => ge
   </title>
  </head>
  <frameset cols="*,200" border="5" framespacing="no" frameborder="yes" marginwidth="2" marginheight="1">
-  <frameset rows="0,*,50" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
+  <frameset rows="0,*,70" border="0" framespacing="no" frameborder="no" marginwidth="2" marginheight="1">
    <frame src="../empty.php" name="empty" scrolling="auto" noresize marginwidth="2" marginheight="0">
    <frame src="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport?win=chat&amp;$params"; ?>" scrolling="auto" name="msg" noresize marginwidth="2" marginheight="0">
    <frame src="chatinput.php?<?php echo $params ?>" name="input" scrolling="no" marginwidth="2" marginheight="1">
-- 
1.7.9.5


From b06143c5c2d14c19fdb146857b72ed858522bcc1 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 12 Sep 2012 11:12:46 +0100
Subject: [PATCH 625/903] MDL-34082 course restrict modules: typo in MDL-19125
 upgrade code.

---
 lib/db/upgrade.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 83c7370..97f3fb2 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -248,7 +248,7 @@ function xmldb_main_upgrade($oldversion) {
         if ($CFG->restrictmodulesfor === 'all') {
             $courses = $DB->get_records_menu('course', array(), 'id', 'id, 1');
         } else if ($CFG->restrictmodulesfor === 'requested') {
-            $courses = $DB->get_records_menu('course', array('retrictmodules' => 1), 'id', 'id, 1');
+            $courses = $DB->get_records_menu('course', array('restrictmodules' => 1), 'id', 'id, 1');
         } else {
             $courses = array();
         }
@@ -314,7 +314,7 @@ function xmldb_main_upgrade($oldversion) {
 
     if ($oldversion < 2012031500.02) {
 
-        // Define field retrictmodules to be dropped from course
+        // Define field restrictmodules to be dropped from course
         $table = new xmldb_table('course');
         $field = new xmldb_field('restrictmodules');
 
-- 
1.7.9.5


From 5df0a6b47e246ce0a5de46bfe3fdf4d6974a2242 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 11 Sep 2012 15:04:00 +0100
Subject: [PATCH 626/903] MDL-34841 error importing questions with long names.

The problem was with the non-UTF-8-safe way that a question name
was being constructed from the question text.

I have done a proper fix with methods in the base class to
carefully construct a question name that is reasonable, and
which will fit in the database column. Then I have changed all
importers to use the new methods.

I also remembered not to break the lesson in the process.
---
 mod/lesson/format.php                              |   31 +++++++++
 question/format.php                                |   31 +++++++++
 question/format/aiken/format.php                   |    2 +-
 question/format/blackboard/format.php              |   10 +--
 question/format/blackboard_six/formatpool.php      |   10 +--
 question/format/blackboard_six/formatqti.php       |    7 +-
 question/format/examview/format.php                |    4 +-
 question/format/gift/format.php                    |    8 +--
 question/format/learnwise/format.php               |    5 +-
 question/format/missingword/format.php             |    2 +-
 question/format/multianswer/format.php             |   13 +---
 .../multianswer/tests/multianswerformat_test.php   |    4 +-
 question/format/webct/format.php                   |   13 +---
 question/format/xml/format.php                     |    6 +-
 question/tests/importexport_test.php               |   67 ++++++++++++++++++++
 15 files changed, 154 insertions(+), 59 deletions(-)

diff --git a/mod/lesson/format.php b/mod/lesson/format.php
index 95bb645..134c14b 100644
--- a/mod/lesson/format.php
+++ b/mod/lesson/format.php
@@ -541,6 +541,37 @@ class qformat_default {
         return NULL;
     }
 
+    /**
+     * Construct a reasonable default question name, based on the start of the question text.
+     * @param string $questiontext the question text.
+     * @param string $default default question name to use if the constructed one comes out blank.
+     * @return string a reasonable question name.
+     */
+    public function create_default_question_name($questiontext, $default) {
+        $name = $this->clean_question_name(shorten_text($questiontext, 80));
+        if ($name) {
+            return $name;
+        } else {
+            return $default;
+        }
+    }
+
+    /**
+     * Ensure that a question name does not contain anything nasty, and will fit in the DB field.
+     * @param string $name the raw question name.
+     * @return string a safe question name.
+     */
+    public function clean_question_name($name) {
+        $name = clean_param($name, PARAM_TEXT); // Matches what the question editing form does.
+        $name = trim($name);
+        $trimlength = 251;
+        while (textlib::strlen($name) > 255 && $trimlength > 0) {
+            $name = shorten_text($name, $trimlength);
+            $trimlength -= 10;
+        }
+        return $name;
+    }
+
     function defaultquestion() {
     // returns an "empty" question
     // Somewhere to specify question parameters that are not handled
diff --git a/question/format.php b/question/format.php
index dd02cfc..13c1232 100644
--- a/question/format.php
+++ b/question/format.php
@@ -661,6 +661,37 @@ class qformat_default {
     }
 
     /**
+     * Construct a reasonable default question name, based on the start of the question text.
+     * @param string $questiontext the question text.
+     * @param string $default default question name to use if the constructed one comes out blank.
+     * @return string a reasonable question name.
+     */
+    public function create_default_question_name($questiontext, $default) {
+        $name = $this->clean_question_name(shorten_text($questiontext, 80));
+        if ($name) {
+            return $name;
+        } else {
+            return $default;
+        }
+    }
+
+    /**
+     * Ensure that a question name does not contain anything nasty, and will fit in the DB field.
+     * @param string $name the raw question name.
+     * @return string a safe question name.
+     */
+    public function clean_question_name($name) {
+        $name = clean_param($name, PARAM_TEXT); // Matches what the question editing form does.
+        $name = trim($name);
+        $trimlength = 251;
+        while (textlib::strlen($name) > 255 && $trimlength > 0) {
+            $name = shorten_text($name, $trimlength);
+            $trimlength -= 10;
+        }
+        return $name;
+    }
+
+    /**
      * Add a blank combined feedback to a question object.
      * @param object question
      * @return object question
diff --git a/question/format/aiken/format.php b/question/format/aiken/format.php
index 4e64c2f..968a211 100644
--- a/question/format/aiken/format.php
+++ b/question/format/aiken/format.php
@@ -95,7 +95,7 @@ class qformat_aiken extends qformat_default {
                 } else {
                     // Must be the first line of a new question, since no recognised prefix.
                     $question->qtype = MULTICHOICE;
-                    $question->name = shorten_text(s($nowline), 50);
+                    $question->name = $this->create_default_question_name($nowline, get_string('questionname', 'question'));
                     $question->questiontext = htmlspecialchars(trim($nowline), ENT_NOQUOTES);
                     $question->questiontextformat = FORMAT_HTML;
                     $question->generalfeedback = '';
diff --git a/question/format/blackboard/format.php b/question/format/blackboard/format.php
index 1e7fa0d..9d30323 100644
--- a/question/format/blackboard/format.php
+++ b/question/format/blackboard/format.php
@@ -123,13 +123,9 @@ class qformat_blackboard extends qformat_based_on_xml {
             $question->questiontext = $text;
         }
         // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
-        $question->name = shorten_text(strip_tags($question->questiontext), 200);
-        $question->name = substr($question->name, 0, 250);
-        if (!$question->name) {
-            $id = $this->getpath($questiondata,
-                    array('@', 'id'), '',  true);
-            $question->name = get_string('defaultname', 'qformat_blackboard' , $id);
-        }
+        $id = $this->getpath($questiondata, array('@', 'id'), '',  true);
+        $question->name = $this->create_default_question_name($question->questiontext,
+                get_string('defaultname', 'qformat_blackboard', $id));
 
         $question->generalfeedback = '';
         $question->generalfeedbackformat = FORMAT_HTML;
diff --git a/question/format/blackboard_six/formatpool.php b/question/format/blackboard_six/formatpool.php
index 80867f3..a6c942c 100644
--- a/question/format/blackboard_six/formatpool.php
+++ b/question/format/blackboard_six/formatpool.php
@@ -92,13 +92,9 @@ class qformat_blackboard_six_pool extends qformat_blackboard_six_base {
         $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
 
         // Put name in question object. We must ensure it is not empty and it is less than 250 chars.
-        $question->name = shorten_text(strip_tags($question->questiontext['text']), 200);
-        $question->name = substr($question->name, 0, 250);
-        if (!$question->name) {
-            $id = $this->getpath($questiondata,
-                    array('@', 'id'), '',  true);
-            $question->name = get_string('defaultname', 'qformat_blackboard_six' , $id);
-        }
+        $id = $this->getpath($questiondata, array('@', 'id'), '',  true);
+        $question->name = $this->create_default_question_name($question->questiontext['text'],
+                get_string('defaultname', 'qformat_blackboard_six' , $id));
 
         $question->generalfeedback = '';
         $question->generalfeedbackformat = FORMAT_HTML;
diff --git a/question/format/blackboard_six/formatqti.php b/question/format/blackboard_six/formatqti.php
index 223d9f6..37545fd 100644
--- a/question/format/blackboard_six/formatqti.php
+++ b/question/format/blackboard_six/formatqti.php
@@ -510,11 +510,8 @@ class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
         $question->questiontext = $this->cleaned_text_field($text);
         $question->questiontextformat = FORMAT_HTML; // Needed because add_blank_combined_feedback uses it.
 
-        $question->name = shorten_text(strip_tags($question->questiontext['text']), 200);
-        $question->name = substr($question->name, 0, 250);
-        if (!$question->name) {
-            $question->name = get_string('defaultname', 'qformat_blackboard_six' , $quest->id);
-        }
+        $question->name = $this->create_default_question_name($question->questiontext['text'],
+                get_string('defaultname', 'qformat_blackboard_six' , $quest->id));
         $question->generalfeedback = '';
         $question->generalfeedbackformat = FORMAT_HTML;
         $question->generalfeedbackfiles = array();
diff --git a/question/format/examview/format.php b/question/format/examview/format.php
index 9cb9bb5..2f3eccd 100644
--- a/question/format/examview/format.php
+++ b/question/format/examview/format.php
@@ -131,7 +131,7 @@ class qformat_examview extends qformat_based_on_xml {
             $question->questiontext = $htmltext;
             $question->questiontextformat = FORMAT_HTML;
             $question->questiontextfiles = array();
-            $question->name = shorten_text( $question->questiontext, 250 );
+            $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
             $question->qtype = MATCH;
             $question = $this->add_blank_combined_feedback($question);
             $question->subquestions = array();
@@ -200,7 +200,7 @@ class qformat_examview extends qformat_based_on_xml {
         $question->questiontext = $this->cleaninput($htmltext);
         $question->questiontextformat = FORMAT_HTML;
         $question->questiontextfiles = array();
-        $question->name = shorten_text( $question->questiontext, 250 );
+        $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
 
         switch ($question->qtype) {
             case MULTICHOICE:
diff --git a/question/format/gift/format.php b/question/format/gift/format.php
index 1cb0e25..ecca6e2 100644
--- a/question/format/gift/format.php
+++ b/question/format/gift/format.php
@@ -206,7 +206,7 @@ class qformat_gift extends qformat_default {
                 // name will be assigned after processing question text below
             } else {
                 $questionname = substr($text, 0, $namefinish);
-                $question->name = trim($this->escapedchar_post($questionname));
+                $question->name = $this->clean_question_name($this->escapedchar_post($questionname));
                 $text = trim(substr($text, $namefinish+2)); // Remove name from text
             }
         } else {
@@ -251,13 +251,9 @@ class qformat_gift extends qformat_default {
 
         // set question name if not already set
         if ($question->name === false) {
-            $question->name = $question->questiontext;
+            $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
         }
 
-        // ensure name is not longer than 250 characters
-        $question->name = shorten_text($question->name, 200);
-        $question->name = strip_tags(substr($question->name, 0, 250));
-
         // determine QUESTION TYPE
         $question->qtype = NULL;
 
diff --git a/question/format/learnwise/format.php b/question/format/learnwise/format.php
index fa80475..ae80f13 100644
--- a/question/format/learnwise/format.php
+++ b/question/format/learnwise/format.php
@@ -126,10 +126,7 @@ class qformat_learnwise extends qformat_default {
 
         $question = $this->defaultquestion();
         $question->qtype = MULTICHOICE;
-        $question->name = substr($questiontext, 0, 30);
-        if (strlen($questiontext) > 30) {
-            $question->name .= '...';
-        }
+        $question->name = $this->create_default_question_name($questiontext, get_string('questionname', 'question'));
 
         $question->questiontext = $questiontext;
         $question->single = ($type == 'multichoice') ? 1 : 0;
diff --git a/question/format/missingword/format.php b/question/format/missingword/format.php
index 15e1d71..d4347bc 100644
--- a/question/format/missingword/format.php
+++ b/question/format/missingword/format.php
@@ -89,7 +89,7 @@ class qformat_missingword extends qformat_default {
 
         /// Save the new question text
         $question->questiontext = substr_replace($text, "_____", $answerstart, $answerlength+1);
-        $question->name = $question->questiontext;
+        $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
 
 
         /// Parse the answers
diff --git a/question/format/multianswer/format.php b/question/format/multianswer/format.php
index d7a7ac7..b7c412e 100644
--- a/question/format/multianswer/format.php
+++ b/question/format/multianswer/format.php
@@ -62,18 +62,7 @@ class qformat_multianswer extends qformat_default {
         $question->penalty = 0.3333333;
 
         if (!empty($question)) {
-            $name = html_to_text(implode(' ', $lines));
-            $name = preg_replace('/{[^}]*}/', '', $name);
-            $name = trim($name);
-
-            if ($name) {
-                $question->name = shorten_text($name, 45);
-            } else {
-                // We need some name, so use the current time, since that will be
-                // reasonably unique.
-                $question->name = userdate(time());
-            }
-
+            $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
             $questions[] = $question;
         }
 
diff --git a/question/format/multianswer/tests/multianswerformat_test.php b/question/format/multianswer/tests/multianswerformat_test.php
index 29c3224..8e1d301 100644
--- a/question/format/multianswer/tests/multianswerformat_test.php
+++ b/question/format/multianswer/tests/multianswerformat_test.php
@@ -47,7 +47,9 @@ class qformat_multianswer_test extends question_testcase {
         $qs = $importer->readquestions($lines);
 
         $expectedq = (object) array(
-            'name' => 'Match the following cities with the ...',
+            'name' => 'Match the following cities with the correct state:
+* San Francisco: {#1}
+* ...',
             'questiontext' => 'Match the following cities with the correct state:
 * San Francisco: {#1}
 * Tucson: {#2}
diff --git a/question/format/webct/format.php b/question/format/webct/format.php
index c599ca8..28841e8 100644
--- a/question/format/webct/format.php
+++ b/question/format/webct/format.php
@@ -259,11 +259,8 @@ class qformat_webct extends qformat_default {
 
                     // Setup default value of missing fields
                     if (!isset($question->name)) {
-                        $question->name = $question->questiontext;
-                    }
-                    if (strlen($question->name) > 255) {
-                        $question->name = substr($question->name,0,250)."...";
-                        $warnings[] = get_string("questionnametoolong", "qformat_webct", $nQuestionStartLine);
+                        $question->name = $this->create_default_question_name(
+                                $question->questiontext, get_string('questionname', 'question'));
                     }
                     if (!isset($question->defaultmark)) {
                         $question->defaultmark = 1;
@@ -466,11 +463,7 @@ class qformat_webct extends qformat_default {
 
             if (preg_match("~^:TITLE:(.*)~i",$line,$webct_options)) {
                 $name = trim($webct_options[1]);
-                if (strlen($name) > 255) {
-                    $name = substr($name,0,250)."...";
-                    $warnings[] = get_string("questionnametoolong", "qformat_webct", $nLineCounter);
-                }
-                $question->name = $name;
+                $question->name = $this->clean_question_name($name);
                 continue;
             }
 
diff --git a/question/format/xml/format.php b/question/format/xml/format.php
index 740279f..1a0e992 100644
--- a/question/format/xml/format.php
+++ b/question/format/xml/format.php
@@ -166,9 +166,9 @@ class qformat_xml extends qformat_default {
         $qo = $this->defaultquestion();
 
         // Question name
-        $qo->name = $this->getpath($question,
+        $qo->name = $this->clean_question_name($this->getpath($question,
                 array('#', 'name', 0, '#', 'text', 0, '#'), '', true,
-                get_string('xmlimportnoname', 'qformat_xml'));
+                get_string('xmlimportnoname', 'qformat_xml')));
         $qo->questiontext = $this->getpath($question,
                 array('#', 'questiontext', 0, '#', 'text', 0, '#'), '', true);
         $qo->questiontextformat = $this->trans_format($this->getpath(
@@ -437,7 +437,7 @@ class qformat_xml extends qformat_default {
         $qo->course = $this->course;
         $qo->generalfeedback = '';
 
-        $qo->name = $this->import_text($question['#']['name'][0]['#']['text']);
+        $qo->name = $this->clean_question_name($this->import_text($question['#']['name'][0]['#']['text']));
         $qo->questiontextformat = $questiontext['format'];
         $qo->questiontext = $qo->questiontext['text'];
         $qo->questiontextfiles = array();
diff --git a/question/tests/importexport_test.php b/question/tests/importexport_test.php
index 0ffe435..96d0704 100644
--- a/question/tests/importexport_test.php
+++ b/question/tests/importexport_test.php
@@ -87,4 +87,71 @@ class qformat_default_test extends advanced_testcase {
         $path = '<evil>Nasty <virus //> thing<//evil>';
         $this->assertEquals(array('Nasty  thing'), $format->split_category_path($path));
     }
+
+    public function test_clean_question_name() {
+        $format = new testable_qformat();
+
+        $name = 'Nice simple name';
+        $this->assertEquals($name, $format->clean_question_name($name));
+
+        $name = 'Question in <span lang="en" class="multilang">English</span><span lang="fr" class="multilang">French</span>';
+        $this->assertEquals($name, $format->clean_question_name($name));
+
+        $name = 'Evil <script type="text/javascrip">alert("You have been hacked!");</script>';
+        $this->assertEquals('Evil alert("You have been hacked!");', $format->clean_question_name($name));
+
+        $name = 'This is a very long question name. It goes on and on and on. ' .
+                'I wonder if it will ever stop. The quetsion name field in the database is only ' .
+                'two hundred and fifty five characters wide, so if the import file contains a ' .
+                'name longer than that, the code had better truncate it!';
+        $this->assertEquals(shorten_text($name, 251), $format->clean_question_name($name));
+
+        // The worst case scenario is a whole lot of single charaters in separate multilang tags.
+        $name = '<span lang="en" class="multilang">A</span>' .
+                '<span lang="fr" class="multilang">B</span>' .
+                '<span lang="fr_ca" class="multilang">C</span>' .
+                '<span lang="en_us" class="multilang">D</span>' .
+                '<span lang="de" class="multilang">E</span>' .
+                '<span lang="cz" class="multilang">F</span>' .
+                '<span lang="it" class="multilang">G</span>' .
+                '<span lang="es" class="multilang">H</span>' .
+                '<span lang="pt" class="multilang">I</span>' .
+                '<span lang="ch" class="multilang">J</span>';
+        $this->assertEquals(shorten_text($name, 1), $format->clean_question_name($name));
+    }
+
+    public function test_create_default_question_name() {
+        $format = new testable_qformat();
+
+        $text = 'Nice simple name';
+        $this->assertEquals($text, $format->create_default_question_name($text, 'Default'));
+
+        $this->assertEquals('Default', $format->create_default_question_name('', 'Default'));
+
+        $text = 'Question in <span lang="en" class="multilang">English</span><span lang="fr" class="multilang">French</span>';
+        $this->assertEquals($text, $format->create_default_question_name($text, 'Default'));
+
+        $text = 'Evil <script type="text/javascrip">alert("You have been hacked!");</script>';
+        $this->assertEquals('Evil alert("You have been hacked!");',
+                $format->create_default_question_name($text, 'Default'));
+
+        $text = 'This is a very long question text. It goes on and on and on. ' .
+                'I wonder if it will ever stop. The question name field in the database is only ' .
+                'two hundred and fifty five characters wide, so if the import file contains a ' .
+                'name longer than that, the code had better truncate it!';
+        $this->assertEquals(shorten_text($text, 80), $format->create_default_question_name($text, 'Default'));
+
+        // The worst case scenario is a whole lot of single charaters in separate multilang tags.
+        $text = '<span lang="en" class="multilang">A</span>' .
+                '<span lang="fr" class="multilang">B</span>' .
+                '<span lang="fr_ca" class="multilang">C</span>' .
+                '<span lang="en_us" class="multilang">D</span>' .
+                '<span lang="de" class="multilang">E</span>' .
+                '<span lang="cz" class="multilang">F</span>' .
+                '<span lang="it" class="multilang">G</span>' .
+                '<span lang="es" class="multilang">H</span>' .
+                '<span lang="pt" class="multilang">I</span>' .
+                '<span lang="ch" class="multilang">J</span>';
+        $this->assertEquals(shorten_text($text, 1), $format->create_default_question_name($text, 'Default'));
+    }
 }
-- 
1.7.9.5


From b4271570c60f54f411d389de368079bca47b6de3 Mon Sep 17 00:00:00 2001
From: Kanika Goyal <kanikagoyal999@gmail.com>
Date: Mon, 2 Apr 2012 09:52:53 +0530
Subject: [PATCH 627/903] MDL-32125 mod_forum: updating subscription mode not
 reflected

---
 mod/forum/lib.php |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 4556123..5b4617e 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -216,6 +216,13 @@ function forum_update_instance($forum, $mform) {
 
     $DB->update_record('forum', $forum);
 
+    $modcontext = get_context_instance(CONTEXT_MODULE, $forum->coursemodule);
+    if (($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) && ($oldforum->forcesubscribe <> $forum->forcesubscribe)) {
+        $users = forum_get_potential_subscribers($modcontext, 0, 'u.id, u.email', '');
+        foreach ($users as $user) {
+            forum_subscribe($user->id, $forum->id);
+        }
+    }
     forum_grade_item_update($forum);
 
     return true;
-- 
1.7.9.5


From fa501712c740dfcd937cdb29fc170530324fbff1 Mon Sep 17 00:00:00 2001
From: Kanika Goyal <kanikagoyal999@gmail.com>
Date: Mon, 2 Apr 2012 09:55:12 +0530
Subject: [PATCH 628/903] MDL-32125 mod_forum: updating subscription mode not
 reflected

---
 mod/forum/lib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 5b4617e..f0147e6 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -223,6 +223,7 @@ function forum_update_instance($forum, $mform) {
             forum_subscribe($user->id, $forum->id);
         }
     }
+
     forum_grade_item_update($forum);
 
     return true;
-- 
1.7.9.5


From b3557ac52db2a47c9d6b2fbfc2743881345bfe0b Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 13 Sep 2012 00:34:33 +0000
Subject: [PATCH 629/903] Automatically generated installer lang files

---
 install/lang/eu/admin.php |    2 +-
 install/lang/ga/error.php |   48 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 install/lang/ga/error.php

diff --git a/install/lang/eu/admin.php b/install/lang/eu/admin.php
index 51e908c..e751fee 100644
--- a/install/lang/eu/admin.php
+++ b/install/lang/eu/admin.php
@@ -39,5 +39,5 @@ $string['clitypevaluedefault'] = 'sartu balorea, sakatu Enter-i berezko balorea
 $string['cliunknowoption'] = 'Aukera ezezagunak:{$a}
 Mesedez, erabili --laguntza aukera.';
 $string['cliyesnoprompt'] = 'idatzi b (bai esateko) edo e (ez esateko)';
-$string['environmentrequireinstall'] = 'derrigorrezkoa da instalatuta etagaituta izatea';
+$string['environmentrequireinstall'] = 'derrigorrezkoa da instalatuta eta gaituta izatea';
 $string['environmentrequireversion'] = '{$a->needed} bertsioa beharrezkoa da eta zu {$a->current} ari zara egikaritzen';
diff --git a/install/lang/ga/error.php b/install/lang/ga/error.php
new file mode 100644
index 0000000..3655f09
--- /dev/null
+++ b/install/lang/ga/error.php
@@ -0,0 +1,48 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['cannotcreatelangdir'] = 'Ní féidir eolaire teanga a chruthú';
+$string['cannotcreatetempdir'] = 'Ní féidir eolaire sealadach a chruthú';
+$string['cannotdownloadcomponents'] = 'Ní féidir na comhphairteanna a íoslódáil';
+$string['cannotdownloadzipfile'] = 'Ní féidir comhad ZIP a íoslódáil';
+$string['cannotfindcomponent'] = 'Ní féidir teacht ar chomhpháirt';
+$string['cannotsavemd5file'] = 'Ni féidir an comhad md5 a shábháil';
+$string['cannotsavezipfile'] = 'Ni féidir an comhad ZIP a shábháil';
+$string['cannotunzipfile'] = 'Ní féidir an comhad a dhízipeáil';
+$string['componentisuptodate'] = 'Tá an chomhpháirt suas chun dáta';
+$string['downloadedfilecheckfailed'] = 'Theip ar an seiceáil comhaid íoslódailte';
+$string['invalidmd5'] = 'Bhí "an athróg seiceála mícheart – triail arís é';
+$string['missingrequiredfield'] = 'Réimse riachtanach ar iarraidh';
+$string['remotedownloaderror'] = 'Theip ar íoslódail comhpháirte chuig do fhreastalaí, dearbhaigh seachshocruithe moltar iarmhíreanna , PHP cURL go hard.<br /"><br />Y Caithfidh tú an comhad <a href="""{$a->url}"">{$a->url}</a> a íoslódáil de láimh';
+$string['wrongdestpath'] = 'Cosán sprice mícheart';
+$string['wrongsourcebase'] = 'Foinse mícheart do bhunachar URL';
+$string['wrongzipfilename'] = 'Ainm mícherat comhaid ZIP';
-- 
1.7.9.5


From a6984540892ef2072200ac7cbd3774c4f11f5041 Mon Sep 17 00:00:00 2001
From: Simon Coggins <simon.coggins@totaralms.com>
Date: Wed, 1 Aug 2012 11:08:50 +1200
Subject: [PATCH 630/903] MDL-34644 SCORM fix completion when only completion
 on view is selected.

---
 mod/scorm/lib.php |   58 ++++++++++++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php
index 822d3e2..c587b68 100644
--- a/mod/scorm/lib.php
+++ b/mod/scorm/lib.php
@@ -1183,33 +1183,37 @@ function scorm_get_completion_state($course, $cm, $userid, $type) {
     if (!$scorm = $DB->get_record('scorm', array('id' => $cm->instance))) {
         print_error('cannotfindscorm');
     }
-
-    // Get user's tracks data
-    $tracks = $DB->get_records_sql(
-        "
-        SELECT
-            id,
-            element,
-            value
-        FROM
-            {scorm_scoes_track}
-        WHERE
-            scormid = ?
-        AND userid = ?
-        AND element IN
-        (
-            'cmi.core.lesson_status',
-            'cmi.completion_status',
-            'cmi.success_status',
-            'cmi.core.score.raw',
-            'cmi.score.raw'
-        )
-        ",
-        array($scorm->id, $userid)
-    );
-
-    if (!$tracks) {
-        return completion_info::aggregate_completion_states($type, $result, false);
+    // Only check for existence of tracks and return false if completionstatusrequired or completionscorerequired
+    // this means that if only view is required we don't end up with a false state.
+    if ($scorm->completionstatusrequired !== null ||
+        $scorm->completionscorerequired !== null) {
+        // Get user's tracks data.
+        $tracks = $DB->get_records_sql(
+            "
+            SELECT
+                id,
+                element,
+                value
+            FROM
+                {scorm_scoes_track}
+            WHERE
+                scormid = ?
+            AND userid = ?
+            AND element IN
+            (
+                'cmi.core.lesson_status',
+                'cmi.completion_status',
+                'cmi.success_status',
+                'cmi.core.score.raw',
+                'cmi.score.raw'
+            )
+            ",
+            array($scorm->id, $userid)
+        );
+
+        if (!$tracks) {
+            return completion_info::aggregate_completion_states($type, $result, false);
+        }
     }
 
     // Check for status
-- 
1.7.9.5


From c21f901559d566b940e70b36be7cd462275f6699 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 13 Sep 2012 16:33:15 +0100
Subject: [PATCH 631/903] MDL-35419 question manual grading: valdiation must
 handle 0,5

Yet another , as decimal separator issue!

To fix this nicely, I refactored some code into question_utils.
---
 question/behaviour/behaviourbase.php         |    6 +++---
 question/engine/lib.php                      |   27 ++++++++++++++++++++++++++
 question/engine/questionattempt.php          |    9 ++-------
 question/engine/tests/questionutils_test.php |   12 +++++++++++-
 4 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/question/behaviour/behaviourbase.php b/question/behaviour/behaviourbase.php
index cd527ef..1f6beb2 100644
--- a/question/behaviour/behaviourbase.php
+++ b/question/behaviour/behaviourbase.php
@@ -477,9 +477,9 @@ abstract class question_behaviour {
      */
     public static function is_manual_grade_in_range($qubaid, $slot) {
         $prefix = 'q' . $qubaid . ':' . $slot . '_';
-        $mark = optional_param($prefix . '-mark', null, PARAM_NUMBER);
-        $maxmark = optional_param($prefix . '-maxmark', null, PARAM_NUMBER);
-        $minfraction = optional_param($prefix . ':minfraction', null, PARAM_NUMBER);
+        $mark = question_utils::optional_param_mark($prefix . '-mark');
+        $maxmark = optional_param($prefix . '-maxmark', null, PARAM_FLOAT);
+        $minfraction = optional_param($prefix . ':minfraction', null, PARAM_FLOAT);
         return is_null($mark) || ($mark >= $minfraction * $maxmark && $mark <= $maxmark);
     }
 
diff --git a/question/engine/lib.php b/question/engine/lib.php
index d9c7d0f..9fdfc03 100644
--- a/question/engine/lib.php
+++ b/question/engine/lib.php
@@ -789,6 +789,33 @@ abstract class question_utils {
         return self::$thousands[$number / 1000 % 10] . self::$hundreds[$number / 100 % 10] .
                 self::$tens[$number / 10 % 10] . self::$units[$number % 10];
     }
+
+    /**
+     * Typically, $mark will have come from optional_param($name, null, PARAM_RAW_TRIMMED).
+     * This method copes with:
+     *  - keeping null or '' input unchanged.
+     *  - nubmers that were typed as either 1.00 or 1,00 form.
+     *
+     * @param string|null $mark raw use input of a mark.
+     * @return float|string|null cleaned mark as a float if possible. Otherwise '' or null.
+     */
+    public static function clean_param_mark($mark) {
+        if ($mark === '' || is_null($mark)) {
+            return $mark;
+        }
+
+        return clean_param(str_replace(',', '.', $mark), PARAM_FLOAT);
+    }
+
+    /**
+     * Get a sumitted variable (from the GET or POST data) that is a mark.
+     * @param string $parname the submitted variable name.
+     * @return float|string|null cleaned mark as a float if possible. Otherwise '' or null.
+     */
+    public static function optional_param_mark($parname) {
+        return self::clean_param_mark(
+                optional_param($parname, null, PARAM_RAW_TRIMMED));
+    }
 }
 
 
diff --git a/question/engine/questionattempt.php b/question/engine/questionattempt.php
index 1be7df2..d89f0f7 100644
--- a/question/engine/questionattempt.php
+++ b/question/engine/questionattempt.php
@@ -882,13 +882,8 @@ class question_attempt {
     public function get_submitted_var($name, $type, $postdata = null) {
         switch ($type) {
             case self::PARAM_MARK:
-                // Special case to work around PARAM_NUMBER converting '' to 0.
-                $mark = $this->get_submitted_var($name, PARAM_RAW_TRIMMED, $postdata);
-                if ($mark === '' || is_null($mark)) {
-                    return $mark;
-                } else {
-                    return clean_param(str_replace(',', '.', $mark), PARAM_NUMBER);
-                }
+                // Special case to work around PARAM_FLOAT converting '' to 0.
+                return question_utils::clean_param_mark($this->get_submitted_var($name, PARAM_RAW_TRIMMED, $postdata));
 
             case self::PARAM_FILES:
                 return $this->process_response_files($name, $name, $postdata);
diff --git a/question/engine/tests/questionutils_test.php b/question/engine/tests/questionutils_test.php
index e51d4db..e5935f4 100644
--- a/question/engine/tests/questionutils_test.php
+++ b/question/engine/tests/questionutils_test.php
@@ -191,4 +191,14 @@ class question_utils_test extends advanced_testcase {
         $this->setExpectedException('moodle_exception');
         question_utils::int_to_roman(1.5);
     }
-}
\ No newline at end of file
+
+    public function test_clean_param_mark() {
+        $this->assertNull(question_utils::clean_param_mark(null));
+        $this->assertSame('', question_utils::clean_param_mark(''));
+        $this->assertSame(0.0, question_utils::clean_param_mark('0'));
+        $this->assertSame(1.5, question_utils::clean_param_mark('1.5'));
+        $this->assertSame(1.5, question_utils::clean_param_mark('1,5'));
+        $this->assertSame(-1.5, question_utils::clean_param_mark('-1.5'));
+        $this->assertSame(-1.5, question_utils::clean_param_mark('-1,5'));
+    }
+}
-- 
1.7.9.5


From 9844498b0aa0aa80a9a89c1248a2672c427f53de Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 14 Sep 2012 00:34:18 +0000
Subject: [PATCH 632/903] Automatically generated installer lang files

---
 install/lang/es/install.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/es/install.php b/install/lang/es/install.php
index e239a5f..3d0cfd0 100644
--- a/install/lang/es/install.php
+++ b/install/lang/es/install.php
@@ -41,6 +41,7 @@ $string['databasehost'] = 'Servidor de la base de datos';
 $string['databasename'] = 'Nombre de la base de datos';
 $string['databasetypehead'] = 'Seleccione el controlador de la base de datos';
 $string['dataroot'] = 'Directorio de Datos';
+$string['datarootpermission'] = 'Permisos directorios de datos';
 $string['dbprefix'] = 'Prefijo de tablas';
 $string['dirroot'] = 'Directorio Moodle';
 $string['environmenthead'] = 'Comprobando su entorno';
-- 
1.7.9.5


From 77393dec21f63d04910036706d200e461f8b9888 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 14 Sep 2012 10:38:12 +0200
Subject: [PATCH 633/903] Revert "MDL-32125 mod_forum: updating subscription
 mode not reflected"

This reverts commit fa501712c740dfcd937cdb29fc170530324fbff1.
---
 mod/forum/lib.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index f0147e6..5b4617e 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -223,7 +223,6 @@ function forum_update_instance($forum, $mform) {
             forum_subscribe($user->id, $forum->id);
         }
     }
-
     forum_grade_item_update($forum);
 
     return true;
-- 
1.7.9.5


From b92083421c7ef4f0ee7e0afc51edf978b1122b32 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 14 Sep 2012 10:38:17 +0200
Subject: [PATCH 634/903] Revert "MDL-32125 mod_forum: updating subscription
 mode not reflected"

This reverts commit b4271570c60f54f411d389de368079bca47b6de3.
---
 mod/forum/lib.php |    7 -------
 1 file changed, 7 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 5b4617e..4556123 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -216,13 +216,6 @@ function forum_update_instance($forum, $mform) {
 
     $DB->update_record('forum', $forum);
 
-    $modcontext = get_context_instance(CONTEXT_MODULE, $forum->coursemodule);
-    if (($forum->forcesubscribe == FORUM_INITIALSUBSCRIBE) && ($oldforum->forcesubscribe <> $forum->forcesubscribe)) {
-        $users = forum_get_potential_subscribers($modcontext, 0, 'u.id, u.email', '');
-        foreach ($users as $user) {
-            forum_subscribe($user->id, $forum->id);
-        }
-    }
     forum_grade_item_update($forum);
 
     return true;
-- 
1.7.9.5


From 6b3177344d8425e9407e97e19765e2a3f1e739ce Mon Sep 17 00:00:00 2001
From: Michael Aherne <Michael Aherne>
Date: Fri, 14 Sep 2012 10:17:17 +0100
Subject: [PATCH 635/903] MDL-35163 quiz Make quiz report options available to
 attempts form

---
 mod/quiz/report/attemptsreport_table.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/report/attemptsreport_table.php b/mod/quiz/report/attemptsreport_table.php
index f119da0..4b57900 100644
--- a/mod/quiz/report/attemptsreport_table.php
+++ b/mod/quiz/report/attemptsreport_table.php
@@ -518,7 +518,7 @@ abstract class quiz_attempts_report_table extends table_sql {
             return;
         }
 
-        $url = new moodle_url($this->reporturl, $this->displayoptions);
+        $url = $this->options->get_url();
         $url->param('sesskey', sesskey());
 
         echo '<div id="tablecontainer">';
-- 
1.7.9.5


From 32efb09e62b4a68299c6c9eaafe001cce517e5d0 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 14 Sep 2012 19:10:43 +0200
Subject: [PATCH 636/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 38c2756..d032d57 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2 (Build: 20120910)';  // Human-friendly version name
+$release  = '2.3.2+ (Build: 20120914)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From e7f72fb5d64b387038ef7ca51df71b3bdeef2ab5 Mon Sep 17 00:00:00 2001
From: Itamar Tzadok <itamar@substantialmethods.com>
Date: Mon, 3 Sep 2012 22:58:48 -0400
Subject: [PATCH 637/903] MDL-32688 My Moodle - Fixed fatal error in guest
 access to My Moodle

---
 my/index.php |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/my/index.php b/my/index.php
index 1324c79..2b0105f 100644
--- a/my/index.php
+++ b/my/index.php
@@ -81,11 +81,13 @@ $PAGE->set_subpage($currentpage->id);
 $PAGE->set_title($header);
 $PAGE->set_heading($header);
 
-if (get_home_page() != HOMEPAGE_MY) {
-    if (optional_param('setdefaulthome', false, PARAM_BOOL)) {
-        set_user_preference('user_home_page_preference', HOMEPAGE_MY);
-    } else if (!empty($CFG->defaulthomepage) && $CFG->defaulthomepage == HOMEPAGE_USER) {
-        $PAGE->settingsnav->get('usercurrentsettings')->add(get_string('makethismyhome'), new moodle_url('/my/', array('setdefaulthome'=>true)), navigation_node::TYPE_SETTING);
+if (!isguestuser()) {   // Skip default home page for guests
+    if (get_home_page() != HOMEPAGE_MY) {
+        if (optional_param('setdefaulthome', false, PARAM_BOOL)) {
+            set_user_preference('user_home_page_preference', HOMEPAGE_MY);
+        } else if (!empty($CFG->defaulthomepage) && $CFG->defaulthomepage == HOMEPAGE_USER) {
+            $PAGE->settingsnav->get('usercurrentsettings')->add(get_string('makethismyhome'), new moodle_url('/my/', array('setdefaulthome'=>true)), navigation_node::TYPE_SETTING);
+        }
     }
 }
 
-- 
1.7.9.5


From 250b340003cc3557100171a1f70047d748e5caa0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Fri, 14 Sep 2012 23:54:16 +0200
Subject: [PATCH 638/903] MDL-35129 add missing recordset closing in db
 transfer

---
 lib/dtl/database_exporter.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/dtl/database_exporter.php b/lib/dtl/database_exporter.php
index 7051c82..5d3c121 100644
--- a/lib/dtl/database_exporter.php
+++ b/lib/dtl/database_exporter.php
@@ -153,6 +153,7 @@ abstract class database_exporter {
                 $this->export_table_data($table, $row);
             }
             $this->finish_table_export($table);
+            $rs->close();
         }
         $this->finish_database_export();
     }
-- 
1.7.9.5


From fe5a985c0e502a9af0c01403f9e459b542bd1501 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 15 Sep 2012 10:49:48 +0200
Subject: [PATCH 639/903] MDL-35129 implement new export_table_recordset()

This is necessary because MySQL get_recordset_sql() stores the data in memory, unfortunately the alternative resultset iteration blocks concurrent access - that is why we need new method for export.
---
 lib/dml/moodle_database.php               |   14 ++++++++++++++
 lib/dml/mysqli_native_moodle_database.php |   21 ++++++++++++++++++++
 lib/dml/tests/dml_test.php                |   30 +++++++++++++++++++++++++++++
 lib/dtl/database_exporter.php             |    2 +-
 4 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/lib/dml/moodle_database.php b/lib/dml/moodle_database.php
index 9531782..7a81253 100644
--- a/lib/dml/moodle_database.php
+++ b/lib/dml/moodle_database.php
@@ -1102,6 +1102,20 @@ abstract class moodle_database {
     public abstract function get_recordset_sql($sql, array $params=null, $limitfrom=0, $limitnum=0);
 
     /**
+     * Get all records from a table.
+     *
+     * This method works around potential memory problems and may improve performance,
+     * this method may block access to table until the recordset is closed.
+     *
+     * @param string $table Name of database table.
+     * @return moodle_recordset A moodle_recordset instance {@link function get_recordset}.
+     * @throws dml_exception A DML specific exception is thrown for any errors.
+     */
+    public function export_table_recordset($table) {
+        return $this->get_recordset($table, array());
+    }
+
+    /**
      * Get a number of records as an array of objects where all the given conditions met.
      *
      * If the query succeeds and returns at least one record, the
diff --git a/lib/dml/mysqli_native_moodle_database.php b/lib/dml/mysqli_native_moodle_database.php
index 1a238ba..21404d7 100644
--- a/lib/dml/mysqli_native_moodle_database.php
+++ b/lib/dml/mysqli_native_moodle_database.php
@@ -905,6 +905,27 @@ class mysqli_native_moodle_database extends moodle_database {
         return $this->create_recordset($result);
     }
 
+    /**
+     * Get all records from a table.
+     *
+     * This method works around potential memory problems and may improve performance,
+     * this method may block access to table until the recordset is closed.
+     *
+     * @param string $table Name of database table.
+     * @return moodle_recordset A moodle_recordset instance {@link function get_recordset}.
+     * @throws dml_exception A DML specific exception is thrown for any errors.
+     */
+    public function export_table_recordset($table) {
+        $sql = $this->fix_table_names("SELECT * FROM {{$table}}");
+
+        $this->query_start($sql, array(), SQL_QUERY_SELECT);
+        // MYSQLI_STORE_RESULT may eat all memory for large tables, unfortunately MYSQLI_USE_RESULT blocks other queries.
+        $result = $this->mysqli->query($sql, MYSQLI_USE_RESULT);
+        $this->query_end($result);
+
+        return $this->create_recordset($result);
+    }
+
     protected function create_recordset($result) {
         return new mysqli_native_moodle_recordset($result);
     }
diff --git a/lib/dml/tests/dml_test.php b/lib/dml/tests/dml_test.php
index 2bb7270..e056b53 100644
--- a/lib/dml/tests/dml_test.php
+++ b/lib/dml/tests/dml_test.php
@@ -1300,6 +1300,36 @@ class dml_testcase extends database_driver_testcase {
         // note: fetching nulls, empties, LOBs already tested by test_insert_record() no needed here
     }
 
+    public function test_export_table_recordset() {
+        $DB = $this->tdb;
+        $dbman = $DB->get_manager();
+
+        $table = $this->get_test_table();
+        $tablename = $table->getName();
+
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('course', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $dbman->create_table($table);
+
+        $ids = array();
+        $ids[] = $DB->insert_record($tablename, array('course' => 3));
+        $ids[] = $DB->insert_record($tablename, array('course' => 5));
+        $ids[] = $DB->insert_record($tablename, array('course' => 4));
+        $ids[] = $DB->insert_record($tablename, array('course' => 3));
+        $ids[] = $DB->insert_record($tablename, array('course' => 2));
+        $ids[] = $DB->insert_record($tablename, array('course' => 1));
+        $ids[] = $DB->insert_record($tablename, array('course' => 0));
+
+        $rs = $DB->export_table_recordset($tablename);
+        $rids = array();
+        foreach ($rs as $record) {
+            $rids[] = $record->id;
+        }
+        $rs->close();
+        $this->assertEquals($ids, $rids, '', 0, 0, true);
+    }
+
     public function test_get_records() {
         $DB = $this->tdb;
         $dbman = $DB->get_manager();
diff --git a/lib/dtl/database_exporter.php b/lib/dtl/database_exporter.php
index 5d3c121..4d9b7bb 100644
--- a/lib/dtl/database_exporter.php
+++ b/lib/dtl/database_exporter.php
@@ -144,7 +144,7 @@ abstract class database_exporter {
         $tables = $this->schema->getTables();
         $this->begin_database_export($CFG->version, $CFG->release, date('c'), $description);
         foreach ($tables as $table) {
-            $rs = $this->mdb->get_recordset_sql('SELECT * FROM {'.$table->getName().'}');
+            $rs = $this->mdb->export_table_recordset($table->getName());
             if (!$rs) {
                 throw new ddl_table_missing_exception($table->getName());
             }
-- 
1.7.9.5


From 1077bf7086290a5477a9b3fb5911cb216396edf3 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Thu, 13 Sep 2012 13:26:36 -0400
Subject: [PATCH 640/903] MDL-35411 assign Include plugin
 (submission/feedback) info, even when there is no
 user data.

assign_plugin_config data was only included in backups/imports if user data was included in
the backup. This patch moves it out with the standard structure of the assign backup.
---
 .../backup/moodle2/backup_assign_stepslib.php      |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/mod/assign/backup/moodle2/backup_assign_stepslib.php b/mod/assign/backup/moodle2/backup_assign_stepslib.php
index fa97208..7d9f0a8 100644
--- a/mod/assign/backup/moodle2/backup_assign_stepslib.php
+++ b/mod/assign/backup/moodle2/backup_assign_stepslib.php
@@ -94,8 +94,9 @@ class backup_assign_activity_structure_step extends backup_activity_structure_st
         $pluginconfigs->add_child($pluginconfig);
 
 
-        // Define sources
+        // Define sources.
         $assign->set_source_table('assign', array('id' => backup::VAR_ACTIVITYID));
+        $pluginconfig->set_source_table('assign_plugin_config', array('assignment' => backup::VAR_PARENTID));
 
         if ($userinfo) {
             $submission->set_source_table('assign_submission',
@@ -103,15 +104,12 @@ class backup_assign_activity_structure_step extends backup_activity_structure_st
 
             $grade->set_source_table('assign_grades',
                                      array('assignment' => backup::VAR_PARENTID));
-            $pluginconfig->set_source_table('assign_plugin_config',
-                                     array('assignment' => backup::VAR_PARENTID));
 
-            // support 2 types of subplugins
+            // Support 2 types of subplugins.
             $this->add_subplugin_structure('assignsubmission', $submission, true);
             $this->add_subplugin_structure('assignfeedback', $grade, true);
         }
 
-
         // Define id annotations
         $submission->annotate_ids('user', 'userid');
         $grade->annotate_ids('user', 'userid');
-- 
1.7.9.5


From 28ac357f866428420d2a3e5cc1f03574582c9b3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 15 Sep 2012 11:13:04 +0200
Subject: [PATCH 641/903] MDL-35454 ignore invalid $custombytes in
 get_max_upload_sizes()

This fixes installation and phpunit init regression.
---
 lib/moodlelib.php |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index ce65499..388ded6 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -5959,16 +5959,19 @@ function get_max_upload_sizes($sitebytes = 0, $coursebytes = 0, $modulebytes = 0
         return array();
     }
 
+    $filesize = array();
     $filesize[intval($maxsize)] = display_size($maxsize);
 
     $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152,
                       5242880, 10485760, 20971520, 52428800, 104857600);
 
-    // If custombytes is given then add it to the list.
-    if (!is_null($custombytes)) {
-        if (is_number($custombytes)) {
-            $custombytes = array((int)$custombytes);
+    // If custombytes is given and is valid then add it to the list.
+    if (is_number($custombytes) and $custombytes > 0) {
+        $custombytes = (int)$custombytes;
+        if (!in_array($custombytes, $sizelist)) {
+            $sizelist[] = $custombytes;
         }
+    } else if (is_array($custombytes)) {
         $sizelist = array_unique(array_merge($sizelist, $custombytes));
     }
 
-- 
1.7.9.5


From e4c9460c0b6d439856504fad629763ede029f0af Mon Sep 17 00:00:00 2001
From: David Monllao <davidm@moodle.com>
Date: Tue, 4 Sep 2012 15:59:07 +0800
Subject: [PATCH 642/903] MDL-30847 core Adding ARIA attribute to help windows

---
 lib/javascript-static.js |    1 +
 lib/outputrenderers.php  |    4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 6e7042d..e99e399 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1445,6 +1445,7 @@ M.util.help_icon = {
                     },
 
                     display_callback : function(content) {
+                        content = '<div role="alert">' + content + '</div>';
                         this.overlay.set('bodyContent', content);
                     },
 
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 717ad00..dd03dc8 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1727,7 +1727,7 @@ class core_renderer extends renderer_base {
         // note: this title is displayed only if JS is disabled, otherwise the link will have the new ajax tooltip
         $title = get_string('helpprefix2', '', trim($helpicon->title, ". \t"));
 
-        $attributes = array('href'=>$url, 'title'=>$title);
+        $attributes = array('href'=>$url, 'title'=>$title, 'aria-haspopup' => 'true');
         $id = html_writer::random_id('helpicon');
         $attributes['id'] = $id;
         $output = html_writer::tag('a', $output, $attributes);
@@ -1792,7 +1792,7 @@ class core_renderer extends renderer_base {
         // note: this title is displayed only if JS is disabled, otherwise the link will have the new ajax tooltip
         $title = get_string('helpprefix2', '', trim($title, ". \t"));
 
-        $attributes = array('href'=>$url, 'title'=>$title);
+        $attributes = array('href'=>$url, 'title'=>$title, 'aria-haspopup' => 'true');
         $id = html_writer::random_id('helpicon');
         $attributes['id'] = $id;
         $output = html_writer::tag('a', $output, $attributes);
-- 
1.7.9.5


From befd59097bab8dda6d7d6d648ee1e89d0f7baa42 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 13 Sep 2012 10:23:43 +0800
Subject: [PATCH 643/903] MDL-33982 TinyMCE: Media preview supports external
 URLs

---
 .../3.5.1.1/plugins/moodlemedia/js/media.js        |  115 +++++++++++---------
 .../3.5.1.1/plugins/moodlemedia/preview.php        |   22 ++--
 2 files changed, 71 insertions(+), 66 deletions(-)

diff --git a/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js b/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js
index c8520da..07e0d8b 100644
--- a/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js
+++ b/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js
@@ -23,43 +23,9 @@ function insertMedia() {
     tinyMCEPopup.close();
 }
 
-function getType(v) {
-    var fo, i, c, el, x, f = document.forms[0];
-
-    fo = ed.getParam("media_types", "flash=swf;flv=flv;shockwave=dcr;qt=mov,qt,mpg,mp3,mp4,mpeg;shockwave=dcr;wmp=avi,wmv,wm,asf,asx,wmx,wvx;rmp=rm,ra,ram").split(';');
-
-    // YouTube
-    if (v.match(/watch\?v=(.+)(.*)/)) {
-        f.src.value = 'http://www.youtube.com/v/' + v.match(/v=(.*)(.*)/)[0].split('=')[1];
-        return 'flash';
-    } else if (v.match(/v\/(.+)(.*)/)) {
-        return 'flash';
-    }
-
-    // Google video
-    if (v.indexOf('http://video.google.com/videoplay?docid=') == 0) {
-        f.src.value = 'http://video.google.com/googleplayer.swf?docId=' + v.substring('http://video.google.com/videoplay?docid='.length) + '&hl=en';
-        return 'flash';
-    }
-
-    for (i=0; i<fo.length; i++) {
-        c = fo[i].split('=');
-
-        el = c[1].split(',');
-        for (x=0; x<el.length; x++)
-            if (v.indexOf('.' + el[x]) != -1)
-                return c[0];
-    }
-
-    return null;
-}
-
-
 function serializeParameters() {
-    var d = document, f = d.forms[0], s = '';
+    var d = document, s = '';
     s += getStr(null, 'src');
-    s += 'width:300,';
-    s += 'height:225,';
 
     // delete the tail comma
     s = s.length > 0 ? s.substring(0, s.length - 1) : s;
@@ -87,10 +53,9 @@ function jsEncode(s) {
 }
 
 function generatePreview(c) {
-    var f = document.forms[0], p = document.getElementById('prev'), h = '', cls, pl, n, type, codebase, wp, hp, nw, nh;
+    var f = document.forms[0], p = document.getElementById('prev');
 
     p.innerHTML = '<!-- x --->';
-    var type = getType(f.src.value);
     var re = new RegExp("(.+)\#(.+)", "i");
     var result = f.src.value.match(re);
     if (result) {
@@ -102,7 +67,7 @@ function generatePreview(c) {
     }
 
     // After constrain
-    pl = serializeParameters();
+    var pl = serializeParameters();
     if (pl == '') {
             p.innerHTML = '';
             return;
@@ -116,22 +81,66 @@ function generatePreview(c) {
     }
 
     pl.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(pl.src);
-    pl.width = !pl.width ? 100 : pl.width;
-    pl.height = !pl.height ? 100 : pl.height;
-    pl.id = !pl.id ? 'moodlemediaid' : pl.id;
-    pl.name = !pl.name ? 'moodlemedianame' : pl.name;
-    pl.align = !pl.align ? '' : pl.align;
-
-    // Avoid annoying warning about insecure items
-    if (!tinymce.isIE || document.location.protocol != 'https:') {
-        // Include all the draftfile params after the ?
-        var draftparams = pl.src.toString().replace(/^.*\/draftfile.php\//, '');
-        h = '<iframe src="' + tinyMCE.baseURL + '/plugins/moodlemedia/preview.php?path=' +
-                draftparams + '" width="100%" height="100%"></iframe>';
-    }
+    // NOTE: Do not try to prevent https security popups here - users would get them later on real page anyway!
+
+    // We can not include URL directly in parameters because some security filters might block it.
+    p.innerHTML = '<iframe src="' + tinyMCE.baseURL + '/plugins/moodlemedia/preview.php'
+        + '?path=' + encodeURIComponent(encode64(pl.src.toString()))
+        + '&sesskey=' + encodeURIComponent(parent.M.cfg.sesskey)
+        + '" width="100%" height="100%"></iframe>';
+}
 
-    // I don't know why the HTML comment is there, but leaving it just in case
-    p.innerHTML = "<!-- x --->" + h;
+function encode64(input) {
+    /*
+      CryptoMX Tools
+      Copyright (C) 2004 - 2006 Derek Buitenhuis
+
+      This program is free software; you can redistribute it and/or
+      modify it under the terms of the GNU General Public License
+      as published by the Free Software Foundation; either version 2
+      of the License, or (at your option) any later version.
+
+      This program is distributed in the hope that it will be useful,
+      but WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+      GNU General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with this program; if not, write to the Free Software
+      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+   */
+    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+    var output = "";
+    var chr1, chr2, chr3 = "";
+    var enc1, enc2, enc3, enc4 = "";
+    var i = 0;
+
+    do {
+        chr1 = input.charCodeAt(i++);
+        chr2 = input.charCodeAt(i++);
+        chr3 = input.charCodeAt(i++);
+
+        enc1 = chr1 >> 2;
+        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+        enc4 = chr3 & 63;
+
+        if (isNaN(chr2)) {
+            enc3 = enc4 = 64;
+        } else if (isNaN(chr3)) {
+            enc4 = 64;
+        }
+
+        output = output +
+            keyStr.charAt(enc1) +
+            keyStr.charAt(enc2) +
+            keyStr.charAt(enc3) +
+            keyStr.charAt(enc4);
+        chr1 = chr2 = chr3 = "";
+        enc1 = enc2 = enc3 = enc4 = "";
+    } while (i < input.length);
+
+    return output;
 }
 
 tinyMCEPopup.onInit.add(init);
diff --git a/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php b/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php
index f26251a..a49e3c0 100644
--- a/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php
+++ b/lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php
@@ -28,18 +28,22 @@ require_once($CFG->libdir . '/filelib.php');
 require_once($CFG->libdir . '/editorlib.php');
 require_once($CFG->libdir . '/editor/tinymce/lib.php');
 
-// Must be logged in
+// Must be logged in and have a valid session key.
 require_login();
+require_sesskey();
 
-// Require path to draftfile.php file
-$path = required_param('path', PARAM_PATH);
+// URL to the media.
+$path = required_param('path', PARAM_RAW);
+$path = base64_decode($path);
+$url = clean_param($path, PARAM_URL);
+$url = new moodle_url($url);
 
 $editor = new tinymce_texteditor();
 
-// Now output this file which is super-simple
+// Now output this file which is super-simple.
 $PAGE->set_pagelayout('embedded');
 $PAGE->set_url(new moodle_url('/lib/editor/tinymce/tiny_mce/'.$editor->version.'/plugins/moodlemedia/preview.php',
-        array('path' => $path)));
+        array('path' => base64_encode($path))));
 $PAGE->set_context(context_system::instance());
 $PAGE->add_body_class('core_media_preview');
 
@@ -47,14 +51,6 @@ echo $OUTPUT->header();
 
 $mediarenderer = $PAGE->get_renderer('core', 'media');
 
-$path = '/'.trim($path, '/');
-
-if (empty($CFG->slasharguments)) {
-    $url = new moodle_url('/draftfile.php', array('file'=>$path));
-} else {
-    $url = new moodle_url('/draftfile.php');
-    $url->set_slashargument($path);
-}
 if ($mediarenderer->can_embed_url($url)) {
     echo $mediarenderer->embed_url($url);
 }
-- 
1.7.9.5


From 8e977618f8345d357c8f0677b06efb363bc2525c Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 4 Sep 2012 16:02:54 +0800
Subject: [PATCH 644/903] MDL-34975 Accessibility: Collapsible areas captions
 can be clicked to expand/collapse

---
 lib/javascript-static.js |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 6e7042d..42a2ecb 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -88,17 +88,17 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
 
     // Get the caption for the collapsible region
     var caption = this.div.one('#'+id + '_caption');
-    caption.setAttribute('title', strtooltip);
 
     // Create a link
     var a = Y.Node.create('<a href="#"></a>');
-    // Create a local scoped lamba function to move nodes to a new link
-    var movenode = function(node){
-        node.remove();
-        a.append(node);
-    };
-    // Apply the lamba function on each of the captions child nodes
-    caption.get('children').each(movenode, this);
+    a.setAttribute('title', strtooltip);
+
+    // Get all the nodes from caption, remove them and append them to <a>
+    while (caption.hasChildNodes()) {
+        child = caption.get('firstChild');
+        child.remove();
+        a.append(child);
+    }
     caption.append(a);
 
     // Get the height of the div at this point before we shrink it if required
-- 
1.7.9.5


From fd7255ace0d0b07c33ef169170a51fe8c639d559 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Mon, 21 May 2012 16:23:59 -0700
Subject: [PATCH 645/903] MDL-33166 Forum: Adding capability
 mod/forum:allowforcesubscribe

Conflicts:

	mod/forum/version.php
---
 mod/forum/db/access.php     |   10 ++++++++++
 mod/forum/db/events.php     |    4 ++--
 mod/forum/lang/en/forum.php |    1 +
 mod/forum/lib.php           |   39 +++++++++++++++++++++++++++++++++++++--
 mod/forum/version.php       |    2 +-
 5 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/mod/forum/db/access.php b/mod/forum/db/access.php
index a92df57..e14c65b 100644
--- a/mod/forum/db/access.php
+++ b/mod/forum/db/access.php
@@ -334,5 +334,15 @@ $capabilities = array(
             'manager' => CAP_ALLOW
         )
     ),
+    'mod/forum:allowforcesubscribe' => array(
+
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_MODULE,
+        'archetypes' => array(
+            'student' => CAP_ALLOW,
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW
+        )
+    ),    
 );
 
diff --git a/mod/forum/db/events.php b/mod/forum/db/events.php
index f11bd37..ded6583 100644
--- a/mod/forum/db/events.php
+++ b/mod/forum/db/events.php
@@ -25,9 +25,9 @@
 
 /* List of handlers */
 $handlers = array (
-    'user_enrolled' => array (
+    'role_assigned' => array (
         'handlerfile'      => '/mod/forum/lib.php',
-        'handlerfunction'  => 'forum_user_enrolled',
+        'handlerfunction'  => 'forum_user_role_assigned',
         'schedule'         => 'instant',
         'internal'         => 1,
     ),
diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php
index df64fc9..de2c49e 100644
--- a/mod/forum/lang/en/forum.php
+++ b/mod/forum/lang/en/forum.php
@@ -155,6 +155,7 @@ $string['forum'] = 'Forum';
 $string['forum:addinstance'] = 'Add a new forum';
 $string['forum:addnews'] = 'Add news';
 $string['forum:addquestion'] = 'Add question';
+$string['forum:allowforcesubscribe'] = 'Allow force subscribe';
 $string['forumauthorhidden'] = 'Author (hidden)';
 $string['forumblockingalmosttoomanyposts'] = 'You are approaching the posting threshold. You have posted {$a->numposts} times in the last {$a->blockperiod} and the limit is {$a->blockafter} posts.';
 $string['forumbodyhidden'] = 'This post cannot be viewed by you, probably because you have not posted in the discussion or the maximum editing time hasn\'t passed yet.';
diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 4556123..5678d9f 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -2860,7 +2860,7 @@ function forum_get_potential_subscribers($forumcontext, $groupid, $fields, $sort
     global $DB;
 
     // only active enrolled users or everybody on the frontpage
-    list($esql, $params) = get_enrolled_sql($forumcontext, '', $groupid, true);
+    list($esql, $params) = get_enrolled_sql($forumcontext, 'mod/forum:allowforcesubscribe', $groupid, true);
 
     $sql = "SELECT $fields
               FROM {user} u
@@ -4623,7 +4623,9 @@ function forum_is_subscribed($userid, $forum) {
     if (is_numeric($forum)) {
         $forum = $DB->get_record('forum', array('id' => $forum));
     }
-    if (forum_is_forcesubscribed($forum)) {
+    // If forum is force subscribed and has allowforcesubscribe, then user is subscribed.
+    if (forum_is_forcesubscribed($forum) &&
+            has_capability('mod/forum:allowforcesubscribe', context_module::instance($forum->id), $userid)) {
         return true;
     }
     return $DB->record_exists("forum_subscriptions", array("userid" => $userid, "forum" => $forum->id));
@@ -6076,6 +6078,7 @@ function forum_update_subscriptions_button($courseid, $forumid) {
 /**
  * This function gets run whenever user is enrolled into course
  *
+ * @deprecated deprecating this function as we will be using forum_user_role_assigned
  * @param stdClass $cp
  * @return void
  */
@@ -6099,6 +6102,38 @@ function forum_user_enrolled($cp) {
 }
 
 /**
+ * This function gets run whenever user is assigned role in course
+ *
+ * @param stdClass $cp
+ * @return void
+ */
+function forum_user_role_assigned($cp) {
+    global $DB;
+
+    $context = context::instance_by_id($cp->contextid, MUST_EXIST);
+
+    // If contextlevel is course then only subscribe user. Role assignment
+    // at course level means user is enroled in course and can subscribe to forum.
+    if ($context->contextlevel != CONTEXT_COURSE) {
+        return;
+    }
+
+    $sql = "SELECT f.id
+              FROM {forum} f
+         LEFT JOIN {forum_subscriptions} fs ON (fs.forum = f.id AND fs.userid = :userid)
+             WHERE f.course = :courseid AND f.forcesubscribe = :initial AND fs.id IS NULL";
+    $params = array('courseid'=>$context->instanceid, 'userid'=>$cp->userid, 'initial'=>FORUM_INITIALSUBSCRIBE);
+
+    $forums = $DB->get_records_sql($sql, $params);
+    foreach ($forums as $forum) {
+        // If user doesn't have allowforcesubscribe capability then don't subscribe.
+        if (has_capability('mod/forum:allowforcesubscribe', context_module::instance($forum->id), $cp->userid)) {
+            forum_subscribe($cp->userid, $forum->id);
+        }
+    }
+}
+
+/**
  * This function gets run whenever user is unenrolled from course
  *
  * @param stdClass $cp
diff --git a/mod/forum/version.php b/mod/forum/version.php
index 0413ee7..8a1af57 100644
--- a/mod/forum/version.php
+++ b/mod/forum/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700;    // Requires this Moodle version
 $module->component = 'mod_forum';      // Full name of the plugin (used for diagnostics)
 $module->cron      = 60;
-- 
1.7.9.5


From 29a33233fcb2446a0a26032bff972428e8ce409c Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 10 Sep 2012 15:42:38 +0800
Subject: [PATCH 646/903] MDL-30831 Accessibility: Added aria role and
 attributes to dock block

---
 blocks/dock.js |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/blocks/dock.js b/blocks/dock.js
index 5e4a56f..4eff68c 100644
--- a/blocks/dock.js
+++ b/blocks/dock.js
@@ -164,7 +164,7 @@ M.core_dock.init = function(Y) {
     var dock = Y.one('#dock');
     if (!dock) {
         // Start the construction of the dock
-        dock = Y.Node.create('<div id="dock" class="'+css.dock+' '+css.dock+'_'+this.cfg.position+'_'+this.cfg.orientation+'"></div>')
+        dock = Y.Node.create('<div id="dock" role="menubar" class="'+css.dock+' '+css.dock+'_'+this.cfg.position+'_'+this.cfg.orientation+'"></div>')
                     .append(Y.Node.create('<div class="'+css.buttonscontainer+'"></div>')
                         .append(Y.Node.create('<div class="'+css.dockeditemcontainer+'"></div>')));
         this.nodes.body.append(dock);
@@ -1036,7 +1036,7 @@ M.core_dock.item.prototype = {
         var Y = this.Y;
         var css = M.core_dock.css;
 
-        this.nodes.docktitle = Y.Node.create('<div id="dock_item_'+this.id+'_title" class="'+css.dockedtitle+'"></div>');
+        this.nodes.docktitle = Y.Node.create('<div id="dock_item_'+this.id+'_title" role="menu" aria-haspopup="true" class="'+css.dockedtitle+'"></div>');
         this.nodes.docktitle.append(this.title);
         this.nodes.dockitem = Y.Node.create('<div id="dock_item_'+this.id+'" class="'+css.dockeditem+'" tabindex="0"></div>');
         this.nodes.dockitem.on('dock:actionkey', this.toggle, this);
@@ -1065,6 +1065,8 @@ M.core_dock.item.prototype = {
         this.active = true;
         // Add active item class first up
         this.nodes.docktitle.addClass(css.activeitem);
+        // Set aria-exapanded property to true.
+        this.nodes.docktitle.set('aria-expanded', "true");
         this.fire('dockeditem:showcomplete');
         M.core_dock.resize();
         return true;
@@ -1081,6 +1083,8 @@ M.core_dock.item.prototype = {
         this.nodes.docktitle.removeClass(css.activeitem);
         // Hide the panel
         M.core_dock.getPanel().hide();
+        // Set aria-exapanded property to false
+        this.nodes.docktitle.set('aria-expanded', "false");
         this.fire('dockeditem:hidecomplete');
     },
     /**
-- 
1.7.9.5


From b7f0b0b12b603576ebefb5cd5ad41896e982f3ba Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Mon, 20 Aug 2012 12:00:13 +0800
Subject: [PATCH 647/903] MDL-34778 accessibility compliance for enrol: add
 label tag for input text

---
 enrol/authorize/locallib.php      |    4 ++--
 enrol/ldap/lang/en/enrol_ldap.php |    2 ++
 enrol/ldap/settingslib.php        |    6 ++++--
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/enrol/authorize/locallib.php b/enrol/authorize/locallib.php
index 9708408..47bd3fa 100644
--- a/enrol/authorize/locallib.php
+++ b/enrol/authorize/locallib.php
@@ -415,8 +415,8 @@ function authorize_print_order($orderid)
         }
         $a = new stdClass;
         $a->upto = $upto;
-        $extrahtml = get_string('howmuch', 'enrol_authorize') .
-                     ' <input type="text" size="5" name="amount" value="'.$amount.'" /> ' .
+        $extrahtml = '<label for="amount">'.get_string('howmuch', 'enrol_authorize').'</label>' .
+                     '<input id="amount" type="text" size="5" name="amount" value="'.$amount.'" /> ' .
                      get_string('canbecredit', 'enrol_authorize', $a) . '<br />';
         $table->data[] = array("<b>$strs->confirm:</b>",
                                authorize_print_action_button($orderid, ORDER_REFUND, 0, true, $authstrs->unenrolstudent, $strs->no, $extrahtml));
diff --git a/enrol/ldap/lang/en/enrol_ldap.php b/enrol/ldap/lang/en/enrol_ldap.php
index df3b34f..a54e35e 100644
--- a/enrol/ldap/lang/en/enrol_ldap.php
+++ b/enrol/ldap/lang/en/enrol_ldap.php
@@ -93,6 +93,8 @@ $string['pluginname'] = 'LDAP enrolments';
 $string['pluginname_desc'] = '<p>You can use an LDAP server to control your enrolments. It is assumed your LDAP tree contains groups that map to the courses, and that each of those groups/courses will have membership entries to map to students.</p><p>It is assumed that courses are defined as groups in LDAP, with each group having multiple membership fields (<em>member</em> or <em>memberUid</em>) that contain a uniqueidentification of the user.</p><p>To use LDAP enrolment, your users <strong>must</strong> to have a valid  idnumber field. The LDAP groups must have that idnumber in the member fields for a user to be enrolled in the course. This will usually work well if you are already using LDAP Authentication.</p><p>Enrolments will be updated when the user logs in. You can also run a script to keep enrolments in synch. Look in <em>enrol/ldap/cli/sync.php</em>.</p><p>This plugin can also be set to automatically create new courses when new groups appear in LDAP.</p>';
 $string['pluginnotenabled'] = 'Plugin not enabled!';
 $string['role_mapping'] = '<p>For each role that you want to assign from LDAP, you need to specify the list of contexts where the role courses\'s groups are located. Separate different contexts with \';\'.</p><p>You also need to specify the attribute your LDAP server uses to hold the members of a group. Usually \'member\' or \'memberUid\'</p>';
+$string['role_mapping_attribute'] = 'LDAP member attribute for {$a}';
+$string['role_mapping_context'] = 'LDAP contexts for {$a}';
 $string['role_mapping_key'] = 'Map roles from LDAP ';
 $string['roles'] = 'Role mapping';
 $string['server_settings'] = 'LDAP server settings';
diff --git a/enrol/ldap/settingslib.php b/enrol/ldap/settingslib.php
index 61397a6..d5a882a 100644
--- a/enrol/ldap/settingslib.php
+++ b/enrol/ldap/settingslib.php
@@ -151,7 +151,8 @@ class admin_setting_ldap_rolemapping extends admin_setting {
         foreach ($data as $role) {
             $contextid = $this->get_id().'['.$role['id'].'][contexts]';
             $contextname = $this->get_full_name().'['.$role['id'].'][contexts]';
-            $return .= '<div style="height: 2em;"><input type="text" size="40" id="'.$contextid.'" name="'.$contextname.'" value="'.s($role['contexts']).'"/></div>';
+            $return .= '<div style="height: 2em;"><label class="accesshide" for="'.$contextid.'">'.get_string('role_mapping_context', 'enrol_ldap', $role['name']).'</label>';
+            $return .= '<input type="text" size="40" id="'.$contextid.'" name="'.$contextname.'" value="'.s($role['contexts']).'"/></div>';
         }
         $return .= '</div>';
 
@@ -160,7 +161,8 @@ class admin_setting_ldap_rolemapping extends admin_setting {
         foreach ($data as $role) {
             $memberattrid = $this->get_id().'['.$role['id'].'][memberattribute]';
             $memberattrname = $this->get_full_name().'['.$role['id'].'][memberattribute]';
-            $return .= '<div style="height: 2em;"><input type="text" size="15" id="'.$memberattrid.'" name="'.$memberattrname.'" value="'.s($role['memberattribute']).'"/></div>';
+            $return .= '<div style="height: 2em;"><label class="accesshide" for="'.$memberattrid.'">'.get_string('role_mapping_attribute', 'enrol_ldap', $role['name']).'</label>';
+            $return .= '<input type="text" size="15" id="'.$memberattrid.'" name="'.$memberattrname.'" value="'.s($role['memberattribute']).'"/></div>';
         }
         $return .= '</div>';
         $return .= '<div style="clear:both;"></div>';
-- 
1.7.9.5


From 7a054265dc9d6c7ffb468ae2e1030a17818f5588 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 14 Sep 2012 17:06:07 +0800
Subject: [PATCH 648/903] MDL-34778 enrol: add a space

---
 enrol/authorize/locallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/enrol/authorize/locallib.php b/enrol/authorize/locallib.php
index 47bd3fa..04f6530 100644
--- a/enrol/authorize/locallib.php
+++ b/enrol/authorize/locallib.php
@@ -415,7 +415,7 @@ function authorize_print_order($orderid)
         }
         $a = new stdClass;
         $a->upto = $upto;
-        $extrahtml = '<label for="amount">'.get_string('howmuch', 'enrol_authorize').'</label>' .
+        $extrahtml = '<label for="amount">'.get_string('howmuch', 'enrol_authorize').'</label> ' .
                      '<input id="amount" type="text" size="5" name="amount" value="'.$amount.'" /> ' .
                      get_string('canbecredit', 'enrol_authorize', $a) . '<br />';
         $table->data[] = array("<b>$strs->confirm:</b>",
-- 
1.7.9.5


From 83fbe988f0d006c1c19b7ddda29b967b0459f18c Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 17 Aug 2012 15:35:03 +0800
Subject: [PATCH 649/903] MDL-34571 accessibility compliance for report: Add
 label to select and input text form

---
 report/courseoverview/index.php   |    9 ++++++---
 report/log/lang/en/report_log.php |    1 +
 report/log/locallib.php           |   18 ++++++++++++++++++
 report/participation/index.php    |    2 +-
 report/stats/locallib.php         |   19 ++++++++++---------
 5 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/report/courseoverview/index.php b/report/courseoverview/index.php
index 9fe5c13..637f80a 100644
--- a/report/courseoverview/index.php
+++ b/report/courseoverview/index.php
@@ -75,12 +75,15 @@ $table = new html_table();
 $table->width = '*';
 $table->align = array('left','left','left','left','left','left');
 
-$reporttypemenu = html_writer::select($reportoptions,'report',$report, false);
-$timeoptionsmenu = html_writer::select($timeoptions,'time',$time, false);
+$reporttypemenu = html_writer::label(get_string('statsreporttype'), 'menureport', false, array('class' => 'accesshide'));
+$reporttypemenu .= html_writer::select($reportoptions,'report',$report, false);
+$timeoptionsmenu = html_writer::label(get_string('time'), 'menutime', false, array('class' => 'accesshide'));
+$timeoptionsmenu .= html_writer::select($timeoptions,'time',$time, false);
 
 $table->data[] = array(get_string('statsreporttype'),$reporttypemenu,
                        get_string('statstimeperiod'),$timeoptionsmenu,
-                       '<input type="text" name="numcourses" size="3" maxlength="2" value="'.$numcourses.'" />',
+                       '<label class="accesshide" for="numcourses">' . get_string('numberofcourses') . '</label>' .
+                       '<input type="text" id="numcourses" name="numcourses" size="3" maxlength="2" value="'.$numcourses.'" />',
                        '<input type="submit" value="'.get_string('view').'" />') ;
 
 echo html_writer::table($table);
diff --git a/report/log/lang/en/report_log.php b/report/log/lang/en/report_log.php
index 677fab5..e62ad6a 100644
--- a/report/log/lang/en/report_log.php
+++ b/report/log/lang/en/report_log.php
@@ -26,6 +26,7 @@
 
 $string['log:view'] = 'View course logs';
 $string['log:viewtoday'] = 'View today\'s logs';
+$string['logsformat'] = 'Logs format';
 $string['page-report-log-x'] = 'Any log report';
 $string['page-report-log-index'] = 'Course log report';
 $string['page-report-log-user'] = 'User course log report';
diff --git a/report/log/locallib.php b/report/log/locallib.php
index dd543b0..9544e91 100644
--- a/report/log/locallib.php
+++ b/report/log/locallib.php
@@ -306,10 +306,12 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
     echo "<input type=\"hidden\" name=\"showcourses\" value=\"$showcourses\" />\n";
     if (has_capability('report/log:view', $sitecontext) && $showcourses) {
         $cid = empty($course->id)? '1' : $course->id;
+        echo html_writer::label(get_string('selectacoursesite'), 'menuhost_course', false, array('class' => 'accesshide'));
         echo html_writer::select($dropdown, "host_course", $hostid.'/'.$cid);
     } else {
         $courses = array();
         $courses[$course->id] = $course->fullname . ((empty($course->category)) ? ' ('.get_string('site').') ' : '');
+        echo html_writer::label(get_string('selectacourse'), 'menuid', false, array('class' => 'accesshide'));
         echo html_writer::select($courses,"id",$course->id, false);
         if (has_capability('report/log:view', $sitecontext)) {
             $a = new stdClass();
@@ -328,10 +330,12 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
         else {
             $groups = array();
         }
+        echo html_writer::label(get_string('selectagroup'), 'menugroup', false, array('class' => 'accesshide'));
         echo html_writer::select($groups, "group", $selectedgroup, get_string("allgroups"));
     }
 
     if ($showusers) {
+        echo html_writer::label(get_string('participantslist'), 'menuuser', false, array('class' => 'accesshide'));
         echo html_writer::select($users, "user", $selecteduser, get_string("allparticipants"));
     }
     else {
@@ -343,20 +347,25 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
         else {
             $users[0] = get_string('allparticipants');
         }
+        echo html_writer::label(get_string('participantslist'), 'menuuser', false, array('class' => 'accesshide'));
         echo html_writer::select($users, "user", $selecteduser, false);
         $a->url = "$CFG->wwwroot/report/log/index.php?chooselog=0&group=$selectedgroup&user=$selecteduser"
             ."&id=$course->id&date=$selecteddate&modid=$selectedactivity&showusers=1&showcourses=$showcourses";
         print_string('logtoomanyusers','moodle',$a);
     }
 
+    echo html_writer::label(get_string('date'), 'menudate', false, array('class' => 'accesshide'));
     echo html_writer::select($dates, "date", $selecteddate, get_string("alldays"));
+    echo html_writer::label(get_string('showreports'), 'menumodid', false, array('class' => 'accesshide'));
     echo html_writer::select($activities, "modid", $selectedactivity, get_string("allactivities"));
+    echo html_writer::label(get_string('actions'), 'menumodaction', false, array('class' => 'accesshide'));
     echo html_writer::select($actions, 'modaction', $modaction, get_string("allactions"));
 
     $logformats = array('showashtml' => get_string('displayonpage'),
                         'downloadascsv' => get_string('downloadtext'),
                         'downloadasods' => get_string('downloadods'),
                         'downloadasexcel' => get_string('downloadexcel'));
+    echo html_writer::label(get_string('logsformat', 'report_log'), 'menulogformat', false, array('class' => 'accesshide'));
     echo html_writer::select($logformats, 'logformat', $logformat, false);
     echo '<input type="submit" value="'.get_string('gettheselogs').'" />';
     echo '</div>';
@@ -546,11 +555,13 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate=
     echo "<input type=\"hidden\" name=\"showusers\" value=\"$showusers\" />\n";
     echo "<input type=\"hidden\" name=\"showcourses\" value=\"$showcourses\" />\n";
     if (has_capability('report/log:view', $sitecontext) && $showcourses) {
+        echo html_writer::label(get_string('selectacourse'), 'menuid', false, array('class' => 'accesshide'));
         echo html_writer::select($courses, "id", $course->id, false);
     } else {
         //        echo '<input type="hidden" name="id" value="'.$course->id.'" />';
         $courses = array();
         $courses[$course->id] = $course->fullname . (($course->id == SITEID) ? ' ('.get_string('site').') ' : '');
+        echo html_writer::label(get_string('selectacourse'), 'menuid', false, array('class' => 'accesshide'));
         echo html_writer::select($courses,"id",$course->id, false);
         if (has_capability('report/log:view', $sitecontext)) {
             $a = new stdClass();
@@ -569,10 +580,12 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate=
         else {
             $groups = array();
         }
+        echo html_writer::label(get_string('selectagroup'), 'menugroup', false, array('class' => 'accesshide'));
         echo html_writer::select($groups, "group", $selectedgroup, get_string("allgroups"));
     }
 
     if ($showusers) {
+        echo html_writer::label(get_string('selctauser'), 'menuuser', false, array('class' => 'accesshide'));
         echo html_writer::select($users, "user", $selecteduser, get_string("allparticipants"));
     }
     else {
@@ -584,15 +597,19 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate=
         else {
             $users[0] = get_string('allparticipants');
         }
+        echo html_writer::label(get_string('selctauser'), 'menuuser', false, array('class' => 'accesshide'));
         echo html_writer::select($users, "user", $selecteduser, false);
         $a = new stdClass();
         $a->url = "$CFG->wwwroot/report/log/index.php?chooselog=0&group=$selectedgroup&user=$selecteduser"
             ."&id=$course->id&date=$selecteddate&modid=$selectedactivity&showusers=1&showcourses=$showcourses";
         print_string('logtoomanyusers','moodle',$a);
     }
+    echo html_writer::label(get_string('date'), 'menudate', false, array('class' => 'accesshide'));
     echo html_writer::select($dates, "date", $selecteddate, get_string("alldays"));
 
+    echo html_writer::label(get_string('activities'), 'menumodid', false, array('class' => 'accesshide'));
     echo html_writer::select($activities, "modid", $selectedactivity, get_string("allactivities"));
+    echo html_writer::label(get_string('actions'), 'menumodaction', false, array('class' => 'accesshide'));
     echo html_writer::select($actions, 'modaction', $modaction, get_string("allactions"));
 
     $logformats = array('showashtml' => get_string('displayonpage'),
@@ -600,6 +617,7 @@ function report_log_print_selector_form($course, $selecteduser=0, $selecteddate=
                         'downloadasods' => get_string('downloadods'),
                         'downloadasexcel' => get_string('downloadexcel'));
 
+    echo html_writer::label(get_string('logsformat', 'report_log'), 'menulogformat', false, array('class' => 'accesshide'));
     echo html_writer::select($logformats, 'logformat', $logformat, false);
     echo '<input type="submit" value="'.get_string('gettheselogs').'" />';
     echo '</div>';
diff --git a/report/participation/index.php b/report/participation/index.php
index 50c5b6e..6fad8e4 100644
--- a/report/participation/index.php
+++ b/report/participation/index.php
@@ -311,7 +311,7 @@ if (!empty($instanceid) && !empty($roleid)) {
     }
     echo '</div>';
     echo '<div>';
-    echo '<label for="formaction">'.get_string('withselectedusers').'</label>';
+    echo '<label for="formactionselect">'.get_string('withselectedusers').'</label>';
     $displaylist['messageselect.php'] = get_string('messageselectadd');
     echo html_writer::select($displaylist, 'formaction', '', array(''=>'choosedots'), array('id'=>'formactionselect'));
     echo $OUTPUT->help_icon('withselectedusers');
diff --git a/report/stats/locallib.php b/report/stats/locallib.php
index 1b7fbec..63aa48e 100644
--- a/report/stats/locallib.php
+++ b/report/stats/locallib.php
@@ -46,6 +46,7 @@ function report_stats_mode_menu($course, $mode, $time, $url) {
     }
     $popupurl = $url."?course=$course->id&time=$time";
     $select = new single_select(new moodle_url($popupurl), 'mode', $options, $mode, null);
+    $select->set_label(get_string('reports'), array('class' => 'accesshide'));
     $select->formid = 'switchmode';
     return $OUTPUT->render($select);
 }
@@ -126,21 +127,21 @@ function report_stats_report($course, $report, $mode, $user, $roleid, $time) {
         }
 
         $table->align = array('left','left','left','left','left','left','left','left');
-        $table->data[] = array(get_string('course'),html_writer::select($courseoptions,'course',$course->id,false),
-                               get_string('users'),html_writer::select($users,'userid',$userid,false),
-                               get_string('statsreporttype'),html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
-                               get_string('statstimeperiod'),html_writer::select($timeoptions,'time',$time,false),
+        $table->data[] = array(html_writer::label(get_string('course'), 'menucourse'), html_writer::select($courseoptions, 'course', $course->id, false),
+                               html_writer::label(get_string('users'), 'menuuserid'), html_writer::select($users, 'userid', $userid, false),
+                               html_writer::label(get_string('statsreporttype'), 'menureport'), html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
+                               html_writer::label(get_string('statstimeperiod'), 'menutime') ,html_writer::select($timeoptions,'time',$time,false),
                                '<input type="submit" value="'.get_string('view').'" />') ;
     } else if ($mode == STATS_MODE_RANKED) {
         $table->align = array('left','left','left','left','left','left');
-        $table->data[] = array(get_string('statsreporttype'),html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
-                               get_string('statstimeperiod'),html_writer::select($timeoptions,'time',$time,false),
+        $table->data[] = array(html_writer::label(get_string('statsreporttype'), 'menureport'), html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
+                               html_writer::label(get_string('statstimeperiod'), 'menutime'), html_writer::select($timeoptions,'time',$time,false),
                                '<input type="submit" value="'.get_string('view').'" />') ;
     } else if ($mode == STATS_MODE_GENERAL) {
         $table->align = array('left','left','left','left','left','left','left');
-        $table->data[] = array(get_string('course'),html_writer::select($courseoptions,'course',$course->id,false),
-                               get_string('statsreporttype'),html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
-                               get_string('statstimeperiod'),html_writer::select($timeoptions,'time',$time,false),
+        $table->data[] = array(html_writer::label(get_string('course'), 'menucourse'), html_writer::select($courseoptions,'course',$course->id,false),
+                               html_writer::label(get_string('statsreporttype'), 'menureport'), html_writer::select($reportoptions,'report',($report == 5) ? $report.$roleid : $report,false),
+                               html_writer::label(get_string('statstimeperiod'), 'menutime'), html_writer::select($timeoptions,'time',$time,false),
                                '<input type="submit" value="'.get_string('view').'" />') ;
     }
 
-- 
1.7.9.5


From 1530136c2086c3d90cce63f8ca43e3ddeb871fb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Mon, 10 Sep 2012 17:29:42 +0200
Subject: [PATCH 650/903] MDL-35344 Ignore available updates info with invalid
 format

Previously when the server response validation had failed, the property
available_update_checker::recentresponse was left as NULL. This caused
problems in available_update_checker::compare_responses() that expects
proper arrays passed.

This patch makes invalid data being ignored by setting the property to
an empty array as if no data have been fetched yet. A debugging message
is thrown so the admins will be able to diagnose eventual problems in
the future.
---
 lib/pluginlib.php |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index 65e1c35..76e50eb 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -843,6 +843,11 @@ class available_update_checker {
     /**
      * Loads the most recent raw response record we have fetched
      *
+     * After this method is called, $this->recentresponse is set to an array. If the
+     * array is empty, then either no data have been fetched yet or the fetched data
+     * do not have expected format (and thence they are ignored and a debugging
+     * message is displayed).
+     *
      * This implementation uses the config_plugins table as the permanent storage.
      *
      * @param bool $forcereload reload even if it was already loaded
@@ -862,7 +867,8 @@ class available_update_checker {
                 $this->recentfetch = $config->recentfetch;
                 $this->recentresponse = $this->decode_response($config->recentresponse);
             } catch (available_update_checker_exception $e) {
-                // do not set recentresponse if the validation fails
+                debugging('Invalid info about available updates detected and will be ignored: '.$e->getMessage(), DEBUG_ALL);
+                $this->recentresponse = array();
             }
 
         } else {
-- 
1.7.9.5


From 58ee763bfb6c2425f57a32d94736357dd53e6101 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 10 Sep 2012 15:44:21 +0800
Subject: [PATCH 651/903] MDL-33198 book: Adding h tags to book titles to
 increase accessibility while printing a book

---
 mod/book/tool/print/index.php    |   13 +++++++++----
 mod/book/tool/print/locallib.php |    6 +-----
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/mod/book/tool/print/index.php b/mod/book/tool/print/index.php
index 9077b84..f33f9a1 100644
--- a/mod/book/tool/print/index.php
+++ b/mod/book/tool/print/index.php
@@ -91,6 +91,7 @@ if ($chapter) {
     </head>
     <body>
     <a name="top"></a>
+    <h1 class="book_title"><?php echo format_string($book->name, true, array('context'=>$context)) ?></h1>
     <div class="chapter">
     <?php
 
@@ -98,11 +99,11 @@ if ($chapter) {
     if (!$book->customtitles) {
         if (!$chapter->subchapter) {
             $currtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
-            echo '<p class="book_chapter_title">'.$currtitle.'</p>';
+            echo '<h2 class="book_chapter_title">'.$currtitle.'</h2>';
         } else {
             $currtitle = book_get_chapter_title($chapters[$chapter->id]->parent, $chapters, $book, $context);
             $currsubtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
-            echo '<p class="book_chapter_title">'.$currtitle.'<br />'.$currsubtitle.'</p>';
+            echo '<h2 class="book_chapter_title">'.$currtitle.'</h2><h3 class="book_chapter_title">'.$currsubtitle.'</h3>';
         }
     }
 
@@ -128,7 +129,7 @@ if ($chapter) {
     </head>
     <body>
     <a name="top"></a>
-    <p class="book_title"><?php echo format_string($book->name, true, array('context'=>$context)) ?></p>
+    <h1 class="book_title"><?php echo format_string($book->name, true, array('context'=>$context)) ?></h1>
     <p class="book_summary"><?php echo format_text($book->intro, $book->introformat, array('noclean'=>true, 'context'=>$context)) ?></p>
     <div class="book_info"><table>
     <tr>
@@ -162,7 +163,11 @@ if ($chapter) {
         }
         echo '<div class="book_chapter"><a name="ch'.$ch->id.'"></a>';
         if (!$book->customtitles) {
-            echo '<p class="book_chapter_title">'.$titles[$ch->id].'</p>';
+            if (!$chapter->subchapter) {
+                echo '<h2 class="book_chapter_title">'.$titles[$ch->id].'</h2>';
+            } else {
+                echo '<h3 class="book_chapter_title">'.$titles[$ch->id].'</h3>';
+            }
         }
         $content = str_replace($link1, '#ch', $chapter->content);
         $content = str_replace($link2, '#top', $content);
diff --git a/mod/book/tool/print/locallib.php b/mod/book/tool/print/locallib.php
index 200bee7..27838a9 100644
--- a/mod/book/tool/print/locallib.php
+++ b/mod/book/tool/print/locallib.php
@@ -60,11 +60,7 @@ function booktool_print_get_toc($chapters, $book, $cm) {
 
     $toc .= html_writer::tag('a', '', array('name' => 'toc')); // Representation of toc (HTML).
 
-    if ($book->customtitles) {
-        $toc .= html_writer::tag('h1', get_string('toc', 'mod_book'));
-    } else {
-        $toc .= html_writer::tag('p', get_string('toc', 'mod_book'), array('class' => 'book_chapter_title'));
-    }
+    $toc .= html_writer::tag('h2', get_string('toc', 'mod_book'), array('class' => 'book_chapter_title'));
     $toc .= html_writer::start_tag('ul');
     foreach ($chapters as $ch) {
         if (!$ch->hidden) {
-- 
1.7.9.5


From ec5c45c4edc550825e63fb648b11426881f9bc05 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 10 Sep 2012 14:45:44 +0800
Subject: [PATCH 652/903] MDL-33198 book: Adding h tags to book title to
 increase accessibility

---
 mod/book/view.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mod/book/view.php b/mod/book/view.php
index f5643d3..91b83b8 100644
--- a/mod/book/view.php
+++ b/mod/book/view.php
@@ -181,11 +181,12 @@ if (!$book->customtitles) {
     $hidden = $chapter->hidden ? 'dimmed_text' : '';
     if (!$chapter->subchapter) {
         $currtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
-        echo '<p class="book_chapter_title '.$hidden.'">'.$currtitle.'</p>';
+        echo $OUTPUT->heading($currtitle, 2, array('class' => 'book_chapter_title '.$hidden));
     } else {
         $currtitle = book_get_chapter_title($chapters[$chapter->id]->parent, $chapters, $book, $context);
         $currsubtitle = book_get_chapter_title($chapter->id, $chapters, $book, $context);
-        echo '<p class="book_chapter_title '.$hidden.'">'.$currtitle.'<br />'.$currsubtitle.'</p>';
+        echo $OUTPUT->heading($currtitle, 2, array('class' => 'book_chapter_title '.$hidden));
+        echo $OUTPUT->heading($currsubtitle, 3, array('class' => 'book_chapter_title '.$hidden));
     }
 }
 $chaptertext = file_rewrite_pluginfile_urls($chapter->content, 'pluginfile.php', $context->id, 'mod_book', 'chapter', $chapter->id);
-- 
1.7.9.5


From 97b53d6c05baf92874e63dc75c15f65beec2187e Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Tue, 18 Sep 2012 14:49:52 +0800
Subject: [PATCH 653/903] MDL-35398: Quick grading feedback is now pushed to
 the gradebook

---
 mod/assign/locallib.php |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index e1e5104..7bed4c1 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -2623,21 +2623,29 @@ class assign {
         }
         $currentgrades->close();
 
+        $adminconfig = $this->get_admin_config();
+        $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
+
         // ok - ready to process the updates
         foreach ($modifiedusers as $userid => $modified) {
             $grade = $this->get_user_grade($userid, true);
             $grade->grade= grade_floatval(unformat_float($modified->grade));
             $grade->grader= $USER->id;
 
-            $this->update_grade($grade);
-
             // save plugins data
             foreach ($this->feedbackplugins as $plugin) {
                 if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->supports_quickgrading()) {
                     $plugin->save_quickgrading_changes($userid, $grade);
+                    if (('assignfeedback_' . $plugin->get_type()) == $gradebookplugin) {
+                        // This is the feedback plugin chose to push comments to the gradebook.
+                        $grade->feedbacktext = $plugin->text_for_gradebook($grade);
+                        $grade->feedbackformat = $plugin->format_for_gradebook($grade);
+                    }
                 }
             }
 
+            $this->update_grade($grade);
+
             // save outcomes
             if ($CFG->enableoutcomes) {
                 $data = array();
-- 
1.7.9.5


From 6d3249780b401d7864ba61b57f55b4290f811e69 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 6 Sep 2012 13:24:37 +0800
Subject: [PATCH 654/903] MDL-30909 Accessibility: Improved access to reply
 form in forums

---
 mod/forum/lib.php  |    2 +-
 mod/forum/post.php |    5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 4556123..e12f066 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -3344,7 +3344,7 @@ function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=fa
     }
 
     if ($reply) {
-        $commands[] = array('url'=>new moodle_url('/mod/forum/post.php', array('reply'=>$post->id)), 'text'=>$str->reply);
+        $commands[] = array('url'=>new moodle_url('/mod/forum/post.php#mform1', array('reply'=>$post->id)), 'text'=>$str->reply);
     }
 
     if ($CFG->enableportfolios && ($cm->cache->caps['mod/forum:exportpost'] || ($ownpost && $cm->cache->caps['mod/forum:exportownpost']))) {
diff --git a/mod/forum/post.php b/mod/forum/post.php
index a71d7d1..51b837e 100644
--- a/mod/forum/post.php
+++ b/mod/forum/post.php
@@ -528,8 +528,10 @@ if ($USER->id != $post->userid) {   // Not the original author, so add a message
     unset($data);
 }
 
+$formheading = '';
 if (!empty($parent)) {
     $heading = get_string("yourreply", "forum");
+    $formheading = get_string('reply', 'forum');
 } else {
     if ($forum->type == 'qanda') {
         $heading = get_string('yournewquestion', 'forum');
@@ -883,6 +885,9 @@ if (!empty($parent)) {
     }
 }
 
+if (!empty($formheading)) {
+    echo $OUTPUT->heading($formheading, 2, array('class' => 'accesshide'));
+}
 $mform_post->display();
 
 echo $OUTPUT->footer();
-- 
1.7.9.5


From ce86eb4d0833ce23b16b5a9a1ec47db81e6a90bb Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Tue, 18 Sep 2012 15:27:58 +0800
Subject: [PATCH 655/903] MDL-35202: Allow for language files that contain
 non-ascii for actions in assignment

---
 mod/assign/locallib.php |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index e1e5104..a1e24b4 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -319,18 +319,18 @@ class assign {
             $this->process_batch_grading_operation();
             $action = 'grading';
          } else if ($action == 'submitgrade') {
-            if (optional_param('saveandshownext', null, PARAM_ALPHA)) {
+            if (optional_param('saveandshownext', null, PARAM_RAW)) {
                 //save and show next
                 $action = 'grade';
                 if ($this->process_save_grade($mform)) {
                     $action = 'nextgrade';
                 }
-            } else if (optional_param('nosaveandprevious', null, PARAM_ALPHA)) {
+            } else if (optional_param('nosaveandprevious', null, PARAM_RAW)) {
                 $action = 'previousgrade';
-            } else if (optional_param('nosaveandnext', null, PARAM_ALPHA)) {
+            } else if (optional_param('nosaveandnext', null, PARAM_RAW)) {
                 //show next button
                 $action = 'nextgrade';
-            } else if (optional_param('savegrade', null, PARAM_ALPHA)) {
+            } else if (optional_param('savegrade', null, PARAM_RAW)) {
                 //save changes button
                 $action = 'grade';
                 if ($this->process_save_grade($mform)) {
-- 
1.7.9.5


From 45a6d31c4f9fec79066e2dc3f8ca198f31817b44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 18 Sep 2012 09:10:42 +0200
Subject: [PATCH 656/903] MDL-32572 always lookpup passwords only in records
 from current auth plugin

This bug should not be creating any problems thanks to our design of login process, but it should be fixed anyway.
---
 auth/db/auth.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/auth/db/auth.php b/auth/db/auth.php
index 5709513..fb0b95a 100644
--- a/auth/db/auth.php
+++ b/auth/db/auth.php
@@ -65,7 +65,7 @@ class auth_plugin_db extends auth_plugin_base {
                 $authdb->Close();
                 // user exists externally
                 // check username/password internally
-                if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
+                if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) {
                     return validate_internal_user_password($user, $password);
                 }
             } else {
-- 
1.7.9.5


From 9ac00a5394ab2973e36235bdf2fa69dee6a05f94 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 11 Sep 2012 13:04:09 +0800
Subject: [PATCH 657/903] MDL-30833 Accessibility: Added aria-expanded
 attribute on navigation nodes

---
 blocks/navigation/renderer.php                 |    4 +++-
 blocks/navigation/yui/navigation/navigation.js |    6 ++++++
 blocks/settings/renderer.php                   |    4 +++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/blocks/navigation/renderer.php b/blocks/navigation/renderer.php
index 4c3d28c..92e2831 100644
--- a/blocks/navigation/renderer.php
+++ b/blocks/navigation/renderer.php
@@ -121,18 +121,20 @@ class block_navigation_renderer extends plugin_renderer_base {
 
             // this applies to the li item which contains all child lists too
             $liclasses = array($item->get_css_type(), 'depth_'.$depth);
+            $liexpandable = array();
             if ($item->has_children() && (!$item->forceopen || $item->collapse)) {
                 $liclasses[] = 'collapsed';
             }
             if ($isbranch) {
                 $liclasses[] = 'contains_branch';
+                $liexpandable = array('aria-expanded' => in_array('collapsed', $liclasses) ? "false" : "true");
             } else if ($hasicon) {
                 $liclasses[] = 'item_with_icon';
             }
             if ($item->isactive === true) {
                 $liclasses[] = 'current_branch';
             }
-            $liattr = array('class'=>join(' ',$liclasses));
+            $liattr = array('class' => join(' ',$liclasses)) + $liexpandable;
             // class attribute on the div item which only contains the item content
             $divclasses = array('tree_item');
             if ($isbranch) {
diff --git a/blocks/navigation/yui/navigation/navigation.js b/blocks/navigation/yui/navigation/navigation.js
index 180977d..2189d51 100644
--- a/blocks/navigation/yui/navigation/navigation.js
+++ b/blocks/navigation/yui/navigation/navigation.js
@@ -162,16 +162,20 @@ TREE.prototype = {
                 switch (e.action) {
                     case 'expand' :
                         target.removeClass('collapsed');
+                        target.set('aria-expanded', true);
                         break;
                     case 'collapse' :
                         target.addClass('collapsed');
+                        target.set('aria-expanded', false);
                         break;
                     default :
                         target.toggleClass('collapsed');
+                        target.set('aria-expanded', !target.hasClass('collapsed'));
                 }
                 e.halt();
             } else {
                 target.toggleClass('collapsed');
+                target.set('aria-expanded', !target.hasClass('collapsed'));
             }
         }
 
@@ -180,6 +184,7 @@ TREE.prototype = {
             target.siblings('li').each(function(){
                 if (this.get('id') !== target.get('id') && !this.hasClass('collapsed')) {
                     this.addClass('collapsed');
+                    this.set('aria-expanded', false);
                 }
             });
         }
@@ -287,6 +292,7 @@ BRANCH.prototype = {
         }
         if (isbranch) {
             branchli.addClass('collapsed').addClass('contains_branch');
+            branchli.set('aria-expanded', false);
             branchp.addClass('branch');
         }
 
diff --git a/blocks/settings/renderer.php b/blocks/settings/renderer.php
index 41cea87..a19d41e 100644
--- a/blocks/settings/renderer.php
+++ b/blocks/settings/renderer.php
@@ -40,18 +40,20 @@ class block_settings_renderer extends plugin_renderer_base {
 
             // this applies to the li item which contains all child lists too
             $liclasses = array($item->get_css_type());
+            $liexpandable = array();
             if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count()==0  && $item->nodetype==navigation_node::NODETYPE_BRANCH)) {
                 $liclasses[] = 'collapsed';
             }
             if ($isbranch) {
                 $liclasses[] = 'contains_branch';
+                $liexpandable = array('aria-expanded' => in_array('collapsed', $liclasses) ? "false" : "true");
             } else if ($hasicon) {
                 $liclasses[] = 'item_with_icon';
             }
             if ($item->isactive === true) {
                 $liclasses[] = 'current_branch';
             }
-            $liattr = array('class'=>join(' ',$liclasses));
+            $liattr = array('class' => join(' ',$liclasses)) + $liexpandable;
             // class attribute on the div item which only contains the item content
             $divclasses = array('tree_item');
             if ($isbranch) {
-- 
1.7.9.5


From 3f22e75663be77f39afd591016ce7b0a75ddfd3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 18 Sep 2012 10:44:05 +0200
Subject: [PATCH 658/903] MDL-32572 skip problematic users in auth_db sync

---
 auth/db/auth.php |   16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/auth/db/auth.php b/auth/db/auth.php
index fb0b95a..6e29147 100644
--- a/auth/db/auth.php
+++ b/auth/db/auth.php
@@ -346,7 +346,7 @@ class auth_plugin_db extends auth_plugin_base {
             if ($verbose) {
                 mtrace(get_string('auth_dbuserstoadd','auth_db',count($add_users)));
             }
-            $transaction = $DB->start_delegated_transaction();
+            // Do not use transactions around this foreach, we want to skip problematic users, not revert everything.
             foreach($add_users as $user) {
                 $username = $user;
                 $user = $this->get_userinfo_asobj($user);
@@ -372,9 +372,16 @@ class auth_plugin_db extends auth_plugin_base {
                 } else {
                     $user->timecreated = time();
                     $user->timemodified = $user->timecreated;
-                    $id = $DB->insert_record ('user', $user); // it is truly a new user
-                    if ($verbose) {
-                        mtrace("\t".get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)));
+                    try {
+                        $id = $DB->insert_record('user', $user); // it is truly a new user
+                        if ($verbose) {
+                            mtrace("\t".get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)));
+                        }
+                    } catch (moodle_exception $e) {
+                        if ($verbose) {
+                            mtrace("\t".get_string('auth_dbinsertusererror', 'auth_db', $user->username));
+                        }
+                        continue;
                     }
                     // if relevant, tag for password generation
                     if ($this->is_internal()) {
@@ -383,7 +390,6 @@ class auth_plugin_db extends auth_plugin_base {
                     }
                 }
             }
-            $transaction->allow_commit();
             unset($add_users); // free mem
         }
         return 0;
-- 
1.7.9.5


From 88fbc9a7ef5d6d99cdab6913868ccfda80ded6d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 18 Sep 2012 13:17:35 +0200
Subject: [PATCH 659/903] MDL-32572 fix notice when changing internal auth_db
 passwords

---
 auth/db/auth.php |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/auth/db/auth.php b/auth/db/auth.php
index 6e29147..5882bcf 100644
--- a/auth/db/auth.php
+++ b/auth/db/auth.php
@@ -191,8 +191,16 @@ class auth_plugin_db extends auth_plugin_base {
      * @return bool                  True on success
      */
     function user_update_password($user, $newpassword) {
+        global $DB;
+
         if ($this->is_internal()) {
-            return update_internal_user_password($user, $newpassword);
+            $puser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
+            if (update_internal_user_password($puser, $newpassword)) {
+                $user->password = $puser->password;
+                return true;
+            } else {
+                return false;
+            }
         } else {
             // we should have never been called!
             return false;
-- 
1.7.9.5


From 119b5fdc8b32b20e41551e69611f11f7b877536f Mon Sep 17 00:00:00 2001
From: Simon Coggins <simon.coggins@totaralms.com>
Date: Wed, 19 Sep 2012 09:07:33 +1200
Subject: [PATCH 660/903] MDL-35472: Prevent html tags appearing in page
 titles Only a problem when formatstringstriptags is
 disabled

---
 lib/pagelib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/pagelib.php b/lib/pagelib.php
index 36172c7..ba0c596 100644
--- a/lib/pagelib.php
+++ b/lib/pagelib.php
@@ -1073,6 +1073,7 @@ class moodle_page {
      */
     public function set_title($title) {
         $title = format_string($title);
+        $title = strip_tags($title);
         $title = str_replace('"', '&quot;', $title);
         $this->_title = $title;
     }
-- 
1.7.9.5


From b04027c0cf0495b59ee515ff950eba5708465a21 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 19 Sep 2012 00:51:22 +0200
Subject: [PATCH 661/903] MDL-33166 Forum: whitespace fix

---
 mod/forum/db/access.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/forum/db/access.php b/mod/forum/db/access.php
index e14c65b..43151c6 100644
--- a/mod/forum/db/access.php
+++ b/mod/forum/db/access.php
@@ -343,6 +343,6 @@ $capabilities = array(
             'teacher' => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW
         )
-    ),    
+    ),
 );
 
-- 
1.7.9.5


From 9b65e5841e2811453c8b8f515e257fca359ab0a6 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 19 Sep 2012 00:34:24 +0000
Subject: [PATCH 662/903] Automatically generated installer lang files

---
 install/lang/pt/admin.php   |    6 ++----
 install/lang/pt/error.php   |    2 +-
 install/lang/pt/install.php |    4 ++--
 3 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/install/lang/pt/admin.php b/install/lang/pt/admin.php
index beeead1..09bd68f 100644
--- a/install/lang/pt/admin.php
+++ b/install/lang/pt/admin.php
@@ -32,13 +32,11 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 's';
-$string['cliincorrectvalueerror'] = 'Erro. Valor "{$a->value}" incorreto para "{$a->option}"';
+$string['cliincorrectvalueerror'] = 'Erro: o valor "{$a->value}" não é permitido para a opção "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Valor incorreto, por favor tente novamente';
 $string['clitypevalue'] = 'valor do tipo';
 $string['clitypevaluedefault'] = 'valor do tipo, pressione a tecla Enter para usar o valor predefinido ({$a})';
-$string['cliunknowoption'] = 'Opções desconhecidas:
-{$a}
-Por favor use a opção --help';
+$string['cliunknowoption'] = 'Opções desconhecidas: {$a} Por favor use a opção --help';
 $string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
 $string['environmentrequireinstall'] = 'deve estar instalada e ativa';
 $string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
diff --git a/install/lang/pt/error.php b/install/lang/pt/error.php
index 05bdef95..23e90d0 100644
--- a/install/lang/pt/error.php
+++ b/install/lang/pt/error.php
@@ -42,7 +42,7 @@ $string['componentisuptodate'] = 'O componente está atualizado.';
 $string['downloadedfilecheckfailed'] = 'A verificação do ficheiro descarregado falhou.';
 $string['invalidmd5'] = 'md5 inválido';
 $string['missingrequiredfield'] = 'Um dos campos obrigatórios está em falta';
-$string['remotedownloaderror'] = 'O download do componente para o servidor falhou. Verifique as configurações do proxy. A instalação da extensão cURL do PHP é muito recomendada.<br /><br />Terá que descarregar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copiá-lo para a pasta "{$a->dest}" no seu servidor e descompactá-lo.';
+$string['remotedownloaderror'] = 'A descarga do componente para o servidor falhou. Verifique as configurações do proxy. A instalação da extensão cURL do PHP é muito recomendada.<br /><br />Terá que descarregar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copiá-lo para a pasta "{$a->dest}" no seu servidor e descompactá-lo.';
 $string['wrongdestpath'] = 'Caminho de destino errado.';
 $string['wrongsourcebase'] = 'Base do URL de origem errada';
 $string['wrongzipfilename'] = 'Nome de ficheiro ZIP errado.';
diff --git a/install/lang/pt/install.php b/install/lang/pt/install.php
index c2d95ef..7abb930 100644
--- a/install/lang/pt/install.php
+++ b/install/lang/pt/install.php
@@ -48,14 +48,14 @@ $string['environmenthead'] = 'A verificar sistema...';
 $string['environmentsub2'] = 'Cada nova versão do Moodle tem pré-requisitos mínimos relativamente à versão do PHP e extensões necessárias para o seu correto funcionamento. Estes pré-requisitos são verificados sempre que o Moodle é instalado ou atualizado. Contacte o administrador do servidor caso seja necessário atualizar a versão do PHP ou instalar novas extensões.';
 $string['errorsinenvironment'] = 'A verificação do sistema falhou!';
 $string['installation'] = 'Instalação';
-$string['langdownloaderror'] = 'Não foi possível instalar o idioma <b>{$a}</b> por falha no download. O processo de instalação continuará em Inglês.';
+$string['langdownloaderror'] = 'Não foi possível instalar o idioma <b>{$a}</b> por falha na descarga. O processo de instalação continuará em Inglês.';
 $string['memorylimithelp'] = '<p>O limite de memória para o PHP definido atualmente no servidor é <b>{$a}</b>.</p><p>Um número elevado de módulos em utilização ou de utilizadores registados pode fazer com que o Moodle apresente problemas de falta de memória.</p><p>É recomendado que o PHP seja configurado com um limite de memória de pelo menos 40MB. Esta configuração pode ser definida de diversas formas:</p><ol><li>Compilação do PHP com o parâmetro <b>--enable-memory-limit</b>. Esta definição permitirá ao próprio Moodle definir o valor a utilizar.</li><li>Alteração do parâmetro <b>memory_limit</b> no ficheiro de configuração do PHP para um valor igual ou superior a 40MB.</li><li>Criação de um ficheiro <b>.htaccess</b> na raiz da pasta do Moodle com a linha <b>php_value memory_limit 40M</b><p>ATENÇÃO: Em alguns servidores esta configuração impedirá o funcionamento de <b>todas</b> as páginas PHP. Nestes casos, não poderá ser utilizado o ficheiro <b>.htaccess</b>.</p></li></ol>';
 $string['paths'] = 'Caminhos';
 $string['pathserrcreatedataroot'] = 'O programa de instalação não conseguiu criar a pasta de dados <b>{$a->dataroot}</b>.';
 $string['pathshead'] = 'Confirmar caminhos';
 $string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
 $string['pathsroparentdataroot'] = 'A pasta pai <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
-$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URL\'s especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso dos links para as funcionalidades de administração do Moodle.';
+$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso dos links para as funcionalidades de administração do Moodle.';
 $string['pathssubdataroot'] = 'É necessária uma pasta onde o Moodle possa gravar os ficheiros enviados para a plataforma. Esta pasta deve ter permissão de <b>leitura</b> e <b>escrita</b> pelo utilizador do web server (normalmente <b>nobody</b> ou <b>apache</b>). Por razões de segurança esta pasta não deve estar diretamente acessível através da Internet.';
 $string['pathssubdirroot'] = 'Caminho completo para a pasta de instalação do Moodle.';
 $string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redireccionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranets, então este endereço deve ser configurado no DNS de forma a que os utilizadores das Intranets possam usar este endereço público para aceder ao Moodle. Se o endereço não está correto, então altere o endereço indicado no browser para reiniciar a instalação com o URL correto.';
-- 
1.7.9.5


From 2ed38452aa126a59c0ae845d8f3ec7b66ad43436 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 19 Sep 2012 21:39:58 +0200
Subject: [PATCH 663/903] MDL-33166 forum: fetch cmid to be used by capability
 checks.

---
 mod/forum/lib.php |   16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index db3756c..9c3e801 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -4624,8 +4624,9 @@ function forum_is_subscribed($userid, $forum) {
         $forum = $DB->get_record('forum', array('id' => $forum));
     }
     // If forum is force subscribed and has allowforcesubscribe, then user is subscribed.
-    if (forum_is_forcesubscribed($forum) &&
-            has_capability('mod/forum:allowforcesubscribe', context_module::instance($forum->id), $userid)) {
+    $cm = get_coursemodule_from_instance('forum', $forum->id);
+    if (forum_is_forcesubscribed($forum) && $cm &&
+            has_capability('mod/forum:allowforcesubscribe', context_module::instance($cm->id), $userid)) {
         return true;
     }
     return $DB->record_exists("forum_subscriptions", array("userid" => $userid, "forum" => $forum->id));
@@ -6118,16 +6119,21 @@ function forum_user_role_assigned($cp) {
         return;
     }
 
-    $sql = "SELECT f.id
+    $sql = "SELECT f.id, cm.id AS cmid
               FROM {forum} f
+              JOIN {course_modules} cm ON (cm.instance = f.id)
+              JOIN {modules} m ON (m.id = cm.module)
          LEFT JOIN {forum_subscriptions} fs ON (fs.forum = f.id AND fs.userid = :userid)
-             WHERE f.course = :courseid AND f.forcesubscribe = :initial AND fs.id IS NULL";
+             WHERE f.course = :courseid
+               AND f.forcesubscribe = :initial
+               AND m.name = 'forum'
+               AND fs.id IS NULL";
     $params = array('courseid'=>$context->instanceid, 'userid'=>$cp->userid, 'initial'=>FORUM_INITIALSUBSCRIBE);
 
     $forums = $DB->get_records_sql($sql, $params);
     foreach ($forums as $forum) {
         // If user doesn't have allowforcesubscribe capability then don't subscribe.
-        if (has_capability('mod/forum:allowforcesubscribe', context_module::instance($forum->id), $cp->userid)) {
+        if (has_capability('mod/forum:allowforcesubscribe', context_module::instance($forum->cmid), $cp->userid)) {
             forum_subscribe($cp->userid, $forum->id);
         }
     }
-- 
1.7.9.5


From 5fc1b61a88a9ab322e613445da1c4f078a3e765d Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 20 Sep 2012 00:34:31 +0000
Subject: [PATCH 664/903] Automatically generated installer lang files

---
 install/lang/fi/admin.php |    2 +-
 install/lang/fi/error.php |    8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/install/lang/fi/admin.php b/install/lang/fi/admin.php
index ca02ff8..99e609e 100644
--- a/install/lang/fi/admin.php
+++ b/install/lang/fi/admin.php
@@ -38,5 +38,5 @@ $string['clitypevalue'] = 'syötä arvo';
 $string['clitypevaluedefault'] = 'syötä arvo, paina Enteriä käyttääksesi oletusarvoa ({$a})';
 $string['cliunknowoption'] = 'Tunnistamaton valinta: {$a} Ole hyvä ja käytä --help -valintaa.';
 $string['cliyesnoprompt'] = 'syötä y (kyllä) tai n (ei)';
-$string['environmentrequireinstall'] = 'vaaditaan asennettavaksi/käyttöönotettavaksi';
+$string['environmentrequireinstall'] = 'pitää olla asennettuna ja käytössä';
 $string['environmentrequireversion'] = 'versio {$a->needed} vaaditaan ja käytössä on versio {$a->current}';
diff --git a/install/lang/fi/error.php b/install/lang/fi/error.php
index 8b7de2a..d15d0be 100644
--- a/install/lang/fi/error.php
+++ b/install/lang/fi/error.php
@@ -30,18 +30,18 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['cannotcreatelangdir'] = 'Kielihakemistoa ei voitu luoda';
+$string['cannotcreatelangdir'] = 'Kielihakemistoa ei voida luoda';
 $string['cannotcreatetempdir'] = 'Temp-hakemistoa ei voitu luoda';
 $string['cannotdownloadcomponents'] = 'Komponentteja ei voitu ladata';
 $string['cannotdownloadzipfile'] = 'ZIP-tiedostoa ei voitu ladata';
 $string['cannotfindcomponent'] = 'Komponenttia ei löytynyt';
 $string['cannotsavemd5file'] = 'MD5-tiedostoa ei voitu tallentaa';
-$string['cannotsavezipfile'] = 'Zip-tiedosta ei voitu tallentaa';
+$string['cannotsavezipfile'] = 'Zip-tiedostoa ei voitu tallentaa';
 $string['cannotunzipfile'] = 'Zip-tiedostoa ei voitu purkaa';
 $string['componentisuptodate'] = 'Komponentti on ajan tasalla';
 $string['downloadedfilecheckfailed'] = 'Ladatun tiedoston tarkistus epäonnistui';
-$string['invalidmd5'] = 'Virheellinen MD5';
-$string['missingrequiredfield'] = 'JOitakin vaadituista kentistä puuttuu';
+$string['invalidmd5'] = 'Tarkistusmuuttuja oli väärin - yritä uudelleen';
+$string['missingrequiredfield'] = 'Joitakin vaadituista kentistä puuttuu';
 $string['remotedownloaderror'] = 'Komponentin lataaminen palvelimelle epäonnistui, ole hyvä ja varmista välityspalvelimen asetukset, PHP cURL -laajennus on suositeltu.<br /><br />Sinun täytyy ladata <a href="{$a->url}">{$a->url}</a> -tiedosto manuaalisesti, kopioi se kohteeseen "{$a->dest}" serverilläsi ja pura se sinne.';
 $string['wrongdestpath'] = 'Virheellinen kohdekansio';
 $string['wrongsourcebase'] = 'Väärä lähteen web-osoitteen kanta';
-- 
1.7.9.5


From c366bea3cfc5229717d9fff59197d336306d758b Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 20 Sep 2012 14:10:34 +0800
Subject: [PATCH 665/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index d032d57..601517c 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.01;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.02;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20120914)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20120920)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From ed7e6a735663de70df69d4d759550cbf11383a3d Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 20 Sep 2012 15:47:52 +0800
Subject: [PATCH 666/903] MDL-33857 Increase performance of queries for Server
 files repository (small improvements)

---
 lib/filebrowser/file_info.php                   |   39 ++++++++-------
 lib/filebrowser/file_info_context_course.php    |   59 ++++++++++++++---------
 lib/filebrowser/file_info_context_coursecat.php |   54 +++++++++++++--------
 lib/filebrowser/file_info_context_module.php    |   20 ++++----
 lib/filebrowser/file_info_stored.php            |   30 +++++++++---
 mod/book/locallib.php                           |   17 +++----
 mod/data/locallib.php                           |   17 +++----
 mod/forum/locallib.php                          |   17 +++----
 mod/glossary/locallib.php                       |   17 +++----
 mod/imscp/locallib.php                          |   21 ++++----
 mod/workshop/fileinfolib.php                    |   19 +++++---
 repository/local/lib.php                        |   17 +++----
 12 files changed, 183 insertions(+), 144 deletions(-)

diff --git a/lib/filebrowser/file_info.php b/lib/filebrowser/file_info.php
index 9ad0364..0900d68 100644
--- a/lib/filebrowser/file_info.php
+++ b/lib/filebrowser/file_info.php
@@ -143,7 +143,7 @@ abstract class file_info {
                 $nonemptylist[] = $fileinfo;
             } else {
                 $filename = $fileinfo->get_visible_name();
-                $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+                $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
                 if (!empty($extension) && in_array('.'.$extension, $extensions)) {
                     $nonemptylist[] = $fileinfo;
                 }
@@ -156,7 +156,7 @@ abstract class file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
+     * We usually don't need the exact number of non empty children if it is >=2 (see param $limit)
      * This function is used by repository_local to evaluate if the folder is empty. But
      * it also can be used to check if folder has only one subfolder because in some cases
      * this subfolder can be skipped.
@@ -166,27 +166,32 @@ abstract class file_info {
      * and memory usage on big sites).
      *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         $list = $this->get_children();
         $cnt = 0;
+        // first loop through files
         foreach ($list as $fileinfo) {
-            if ($cnt > 1) {
-                // it only matters if it is 0, 1 or 2+
-                return $cnt;
-            }
-            if ($fileinfo->is_directory()) {
-                if ($fileinfo->count_non_empty_children($extensions)) {
-                    $cnt++;
+            if (!$fileinfo->is_directory()) {
+                if ($extensions !== '*') {
+                    $filename = $fileinfo->get_visible_name();
+                    $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+                    if (empty($extension) || !in_array('.'.$extension, $extensions)) {
+                        continue;
+                    }
                 }
-            } else if ($extensions === '*') {
-                $cnt++;
-            } else {
-                $filename = $fileinfo->get_visible_name();
-                $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-                if (!empty($extension) && in_array('.'.$extension, $extensions)) {
-                    $cnt++;
+                if ((++$cnt) >= $limit) {
+                    return $cnt;
+                }
+            }
+        }
+        // now loop through directories
+        foreach ($list as $fileinfo) {
+            if ($fileinfo->is_directory() && $fileinfo->count_non_empty_children($extensions)) {
+                if ((++$cnt) >= $limit) {
+                    return $cnt;
                 }
             }
         }
diff --git a/lib/filebrowser/file_info_context_course.php b/lib/filebrowser/file_info_context_course.php
index 0ee7402..c88740a 100644
--- a/lib/filebrowser/file_info_context_course.php
+++ b/lib/filebrowser/file_info_context_course.php
@@ -357,7 +357,8 @@ class file_info_context_course extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -375,8 +376,8 @@ class file_info_context_course extends file_info {
             if ($child = $this->get_file_info($area[0], $area[1], 0, '/', '.')) {
                 if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
                     $children[] = $child;
-                    if ($countonly && count($children)>1) {
-                        return 2;
+                    if (($countonly !== false) && count($children)>=$countonly) {
+                        return $countonly;
                     }
                 }
             }
@@ -396,15 +397,15 @@ class file_info_context_course extends file_info {
                 if ($child = $this->browser->get_file_info($modcontext)) {
                     if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
                         $children[] = $child;
-                        if ($countonly && count($children)>1) {
-                            return 2;
+                        if (($countonly !== false) && count($children)>=$countonly) {
+                            return $countonly;
                         }
                     }
                 }
             }
         }
 
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -425,14 +426,12 @@ class file_info_context_course extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
@@ -535,7 +534,7 @@ class file_info_area_course_legacy extends file_info_stored {
         $storedfiles = $fs->get_directory_files($this->context->id, 'course', 'legacy', 0,
                                                 $this->lf->get_filepath(), false, true, "filepath, filename");
         foreach ($storedfiles as $file) {
-            $extension = strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+            $extension = textlib::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
             if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
                 $fileinfo = new file_info_area_course_legacy($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
                                                  $this->itemidused, $this->readaccess, $this->writeaccess, false);
@@ -656,13 +655,11 @@ class file_info_area_course_section extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         global $DB;
         $params1 = array(
             'courseid' => $this->course->id,
@@ -670,7 +667,7 @@ class file_info_area_course_section extends file_info {
             'component' => 'course',
             'filearea' => 'section',
             'emptyfilename' => '.');
-        $sql1 = "SELECT 1 from {files} f, {course_sections} cs
+        $sql1 = "SELECT DISTINCT cs.id FROM {files} f, {course_sections} cs
             WHERE cs.course = :courseid
             AND f.contextid = :contextid
             AND f.component = :component
@@ -678,7 +675,15 @@ class file_info_area_course_section extends file_info {
             AND f.itemid = cs.id
             AND f.filename <> :emptyfilename";
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
-        return $DB->record_exists_sql($sql1.' '.$sql2, array_merge($params1, $params2)) ? 2 : 0;
+        $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
+        $cnt = 0;
+        foreach ($rs as $record) {
+            if ((++$cnt) >= $limit) {
+                break;
+            }
+        }
+        $rs->close();
+        return $cnt;
     }
 
     /**
@@ -796,13 +801,11 @@ class file_info_area_backup_section extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         global $DB;
         $params1 = array(
             'courseid' => $this->course->id,
@@ -810,7 +813,7 @@ class file_info_area_backup_section extends file_info {
             'component' => 'backup',
             'filearea' => 'section',
             'emptyfilename' => '.');
-        $sql1 = "SELECT 1 from {files} f, {course_sections} cs
+        $sql1 = "SELECT DISTINCT cs.id sectionid FROM {files} f, {course_sections} cs
             WHERE cs.course = :courseid
             AND f.contextid = :contextid
             AND f.component = :component
@@ -818,7 +821,15 @@ class file_info_area_backup_section extends file_info {
             AND f.itemid = cs.id
             AND f.filename <> :emptyfilename";
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
-        return $DB->record_exists_sql($sql1.' '.$sql2, array_merge($params1, $params2)) ? 2 : 0;
+        $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
+        $cnt = 0;
+        foreach ($rs as $record) {
+            if ((++$cnt) >= $limit) {
+                break;
+            }
+        }
+        $rs->close();
+        return $cnt;
     }
 
     /**
diff --git a/lib/filebrowser/file_info_context_coursecat.php b/lib/filebrowser/file_info_context_coursecat.php
index 97e3d91..e8d542c 100644
--- a/lib/filebrowser/file_info_context_coursecat.php
+++ b/lib/filebrowser/file_info_context_coursecat.php
@@ -192,44 +192,60 @@ class file_info_context_coursecat extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         global $DB;
+        $cnt = 0;
         if (($child = $this->get_area_coursecat_description(0, '/', '.'))
-                && $child->count_non_empty_children($extensions)) {
-            return 2;
+                && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+            return $cnt;
         }
 
-        $course_cats = $DB->get_records('course_categories', array('parent'=>$this->category->id), 'sortorder', 'id,visible');
-        foreach ($course_cats as $category) {
-            $context = context_coursecat::instance($category->id);
-            if (!$category->visible and !has_capability('moodle/category:viewhiddencategories', $context)) {
+        $rs = $DB->get_recordset_sql('SELECT ctx.id contextid, c.visible
+                FROM {context} ctx, {course} c
+                WHERE ctx.instanceid = c.id
+                AND ctx.contextlevel = :courselevel
+                AND c.category = :categoryid
+                ORDER BY c.visible DESC', // retrieve visible courses first
+                array('categoryid' => $this->category->id, 'courselevel' => CONTEXT_COURSE));
+        foreach ($rs as $record) {
+            $context = context::instance_by_id($record->contextid);
+            if (!$record->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
                 continue;
             }
             if (($child = $this->browser->get_file_info($context))
-                    && $child->count_non_empty_children($extensions)) {
-                return 2;
+                    && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+                break;
             }
         }
+        $rs->close();
+        if ($cnt >= $limit) {
+            return $cnt;
+        }
 
-        $courses = $DB->get_records('course', array('category'=>$this->category->id), 'sortorder', 'id,visible');
-        foreach ($courses as $course) {
-            $context = context_course::instance($course->id);
-            if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
+        $rs = $DB->get_recordset_sql('SELECT ctx.id contextid, cat.visible
+                FROM {context} ctx, {course_categories} cat
+                WHERE ctx.instanceid = cat.id
+                AND ctx.contextlevel = :catlevel
+                AND cat.parent = :categoryid
+                ORDER BY cat.visible DESC', // retrieve visible categories first
+                array('categoryid' => $this->category->id, 'catlevel' => CONTEXT_COURSECAT));
+        foreach ($rs as $record) {
+            $context = context::instance_by_id($record->contextid);
+            if (!$record->visible and !has_capability('moodle/category:viewhiddencategories', $context)) {
                 continue;
             }
             if (($child = $this->browser->get_file_info($context))
-                    && $child->count_non_empty_children($extensions)) {
-                return 2;
+                    && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+                break;
             }
         }
+        $rs->close();
 
-        return 0;
+        return $cnt;
     }
 
     /**
diff --git a/lib/filebrowser/file_info_context_module.php b/lib/filebrowser/file_info_context_module.php
index a873737..5636503 100644
--- a/lib/filebrowser/file_info_context_module.php
+++ b/lib/filebrowser/file_info_context_module.php
@@ -268,7 +268,8 @@ class file_info_context_module extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -303,13 +304,13 @@ class file_info_context_module extends file_info {
             if ($child = $this->get_file_info($area[0], $area[1], null, null, null)) {
                 if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
                     $children[] = $child;
-                    if ($countonly && count($children)>1) {
+                    if ($countonly !== false && count($children) >= $countonly) {
                         break;
                     }
                 }
             }
         }
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -319,11 +320,10 @@ class file_info_context_module extends file_info {
      * Returns list of children which are either files matching the specified extensions
      * or folders that contain at least one such file.
      *
-     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+     * @param string|array $extensions either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
      * @return array of file_info instances
      */
     public function get_non_empty_children($extensions = '*') {
-        global $DB;
         if ($this->nonemptychildren !== null) {
             return $this->nonemptychildren;
         }
@@ -335,17 +335,15 @@ class file_info_context_module extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     *
-     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param string|array $extensions for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        global $DB;
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         if ($this->nonemptychildren !== null) {
             return count($this->nonemptychildren);
         }
-        return $this->get_filtered_children($extensions, true);
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/lib/filebrowser/file_info_stored.php b/lib/filebrowser/file_info_stored.php
index 1c4d2d2..e9caf4c 100644
--- a/lib/filebrowser/file_info_stored.php
+++ b/lib/filebrowser/file_info_stored.php
@@ -368,7 +368,7 @@ class file_info_stored extends file_info {
         $storedfiles = $fs->get_directory_files($this->context->id, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(),
                                                 $this->lf->get_filepath(), false, true, "filepath, filename");
         foreach ($storedfiles as $file) {
-            $extension = strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+            $extension = textlib::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
             if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
                 $fileinfo = new file_info_stored($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
                                                  $this->itemidused, $this->readaccess, $this->writeaccess, false);
@@ -385,13 +385,11 @@ class file_info_stored extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
         global $DB;
         if (!$this->lf->is_directory()) {
             return 0;
@@ -399,7 +397,7 @@ class file_info_stored extends file_info {
 
         $filepath = $this->lf->get_filepath();
         $length = textlib::strlen($filepath);
-        $sql = "SELECT 1
+        $sql = "SELECT filepath, filename
                   FROM {files} f
                  WHERE f.contextid = :contextid AND f.component = :component AND f.filearea = :filearea AND f.itemid = :itemid
                        AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
@@ -410,8 +408,24 @@ class file_info_stored extends file_info {
             'itemid' => $this->lf->get_itemid(),
             'filepath' => $filepath);
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
-        // we don't need to check access to individual files here, since the user can access parent
-        return $DB->record_exists_sql($sql.' '.$sql2, array_merge($params, $params2)) ? 2 : 0;
+        $rs = $DB->get_recordset_sql($sql.' '.$sql2, array_merge($params, $params2));
+        $children = array();
+        foreach ($rs as $record) {
+            // we don't need to check access to individual files here, since the user can access parent
+            if ($record->filepath === $filepath) {
+                $children[] = $record->filename;
+            } else {
+                $path = explode('/', textlib::substr($record->filepath, $length));
+                if (!in_array($path[0], $children)) {
+                    $children[] = $path[0];
+                }
+            }
+            if (count($children) >= $limit) {
+                break;
+            }
+        }
+        $rs->close();
+        return count($children);
     }
 
     /**
diff --git a/mod/book/locallib.php b/mod/book/locallib.php
index eba2e52..9502805 100644
--- a/mod/book/locallib.php
+++ b/mod/book/locallib.php
@@ -455,7 +455,8 @@ class book_file_info extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -479,7 +480,7 @@ class book_file_info extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly === false) {
             $sql .= ' ORDER BY bc.pagenum';
         }
 
@@ -491,12 +492,12 @@ class book_file_info extends file_info {
                     $children[] = $child;
                 }
             }
-            if ($countonly && count($children)>1) {
+            if ($countonly !== false && count($children) >= $countonly) {
                 break;
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -517,14 +518,12 @@ class book_file_info extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/mod/data/locallib.php b/mod/data/locallib.php
index 16c25c7..55a2070 100644
--- a/mod/data/locallib.php
+++ b/mod/data/locallib.php
@@ -500,7 +500,8 @@ class data_file_info_container extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -521,7 +522,7 @@ class data_file_info_container extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly === false) {
             $sql .= ' ORDER BY itemid DESC';
         }
 
@@ -531,12 +532,12 @@ class data_file_info_container extends file_info {
             if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $record->itemid)) {
                 $children[] = $child;
             }
-            if ($countonly && count($children)>1) {
+            if ($countonly !== false && count($children) >= $countonly) {
                 break;
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -557,14 +558,12 @@ class data_file_info_container extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/mod/forum/locallib.php b/mod/forum/locallib.php
index f8840b6..406352a 100644
--- a/mod/forum/locallib.php
+++ b/mod/forum/locallib.php
@@ -490,7 +490,8 @@ class forum_file_info_container extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -511,7 +512,7 @@ class forum_file_info_container extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly !== false) {
             $sql .= ' ORDER BY itemid DESC';
         }
 
@@ -522,12 +523,12 @@ class forum_file_info_container extends file_info {
                     && ($returnemptyfolders || $child->count_non_empty_children($extensions))) {
                 $children[] = $child;
             }
-            if ($countonly && count($children)>1) {
+            if ($countonly !== false && count($children) >= $countonly) {
                 break;
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -548,14 +549,12 @@ class forum_file_info_container extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/mod/glossary/locallib.php b/mod/glossary/locallib.php
index e848138..26dee0f 100644
--- a/mod/glossary/locallib.php
+++ b/mod/glossary/locallib.php
@@ -547,7 +547,8 @@ class glossary_file_info_container extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -575,7 +576,7 @@ class glossary_file_info_container extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly !== false) {
             $sql .= ' ORDER BY ge.concept, f.itemid';
         }
 
@@ -585,12 +586,12 @@ class glossary_file_info_container extends file_info {
             if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $record->itemid)) {
                 $children[] = $child;
             }
-            if ($countonly && count($children)>1) {
+            if ($countonly !== false && count($children) >= $countonly) {
                 break;
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -611,14 +612,12 @@ class glossary_file_info_container extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/mod/imscp/locallib.php b/mod/imscp/locallib.php
index bff1b0e..04b16fb 100644
--- a/mod/imscp/locallib.php
+++ b/mod/imscp/locallib.php
@@ -280,7 +280,8 @@ class imscp_file_info extends file_info {
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -301,7 +302,7 @@ class imscp_file_info extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly !== false) {
             $sql .= ' ORDER BY itemid';
         }
 
@@ -310,13 +311,13 @@ class imscp_file_info extends file_info {
         foreach ($rs as $record) {
             if ($child = $this->browser->get_file_info($this->context, 'mod_imscp', $this->filearea, $record->itemid)) {
                 $children[] = $child;
-            }
-            if ($countonly && count($children)>1) {
-                break;
+                if ($countonly !== false && count($children) >= $countonly) {
+                    break;
+                }
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -337,14 +338,12 @@ class imscp_file_info extends file_info {
      * Returns the number of children which are either files matching the specified extensions
      * or folders containing at least one such file.
      *
-     * NOTE: We don't need the exact number of non empty children if it is >=2
-     * In this function 1 is never returned to avoid skipping the single subfolder
-     *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/mod/workshop/fileinfolib.php b/mod/workshop/fileinfolib.php
index eb1a3bf..35afd24 100644
--- a/mod/workshop/fileinfolib.php
+++ b/mod/workshop/fileinfolib.php
@@ -96,11 +96,13 @@ class workshop_file_info_submissions_container extends file_info {
     public function get_children() {
         return $this->get_filtered_children('*', false, true);
     }
+
     /**
      * Help function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
-     * @param bool $countonly if true returns the count of children (0, 1 or 2 if more than 1)
+     * @param bool|int $countonly if false returns the children, if an int returns just the
+     *    count of children but stops counting when $countonly number of children is reached
      * @param bool $returnemptyfolders if true returns items that don't have matching files inside
      * @return array|int array of file_info instances or the count
      */
@@ -121,7 +123,7 @@ class workshop_file_info_submissions_container extends file_info {
         list($sql2, $params2) = $this->build_search_files_sql($extensions);
         $sql .= ' '.$sql2;
         $params = array_merge($params, $params2);
-        if (!$countonly) {
+        if ($countonly !== false) {
             $sql .= ' ORDER BY itemid DESC';
         }
 
@@ -131,13 +133,13 @@ class workshop_file_info_submissions_container extends file_info {
             if (($child = $this->browser->get_file_info($this->context, 'mod_workshop', $this->filearea, $record->itemid))
                     && ($returnemptyfolders || $child->count_non_empty_children($extensions))) {
                 $children[] = $child;
-            }
-            if ($countonly && count($children)>1) {
-                break;
+                if ($countonly !== false && count($children) >= $countonly) {
+                    break;
+                }
             }
         }
         $rs->close();
-        if ($countonly) {
+        if ($countonly !== false) {
             return count($children);
         }
         return $children;
@@ -162,10 +164,11 @@ class workshop_file_info_submissions_container extends file_info {
      * In this function 1 is never returned to avoid skipping the single subfolder
      *
      * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+     * @param int $limit stop counting after at least $limit non-empty children are found
      * @return int
      */
-    public function count_non_empty_children($extensions = '*') {
-        return $this->get_filtered_children($extensions, true);
+    public function count_non_empty_children($extensions = '*', $limit = 1) {
+        return $this->get_filtered_children($extensions, $limit);
     }
 
     /**
diff --git a/repository/local/lib.php b/repository/local/lib.php
index a0b77a5..b41100c 100644
--- a/repository/local/lib.php
+++ b/repository/local/lib.php
@@ -67,10 +67,7 @@ class repository_local extends repository {
             }
         }
         if (empty($context) && !empty($this->context)) {
-            list($repositorycontext, $course, $cm) = get_context_info_array($this->context->id);
-            if (isset($course->id)) {
-                $context = context_course::instance($course->id);
-            }
+            $context = $this->context->get_course_context(false);
         }
         if (empty($context)) {
             $context = context_system::instance();
@@ -85,7 +82,7 @@ class repository_local extends repository {
             if (!is_array($extensions)) {
                 $extensions = array($extensions);
             }
-            $extensions = array_map('strtolower', $extensions);
+            $extensions = array_map('textlib::strtolower', $extensions);
         }
 
         // build file tree
@@ -143,7 +140,7 @@ class repository_local extends repository {
     /**
      * Returns all children elements that have one of the specified extensions
      *
-     * This function may skip subfolers and recursively add their children
+     * This function may skip subfolders and recursively add their children
      * {@link repository_local::can_skip()}
      *
      * @param file_info $fileinfo
@@ -164,7 +161,7 @@ class repository_local extends repository {
     }
 
     /**
-     * Wether this folder may be skipped in folder hierarchy
+     * Whether this folder may be skipped in folder hierarchy
      *
      * 1. Skip the name of a single filearea in a module
      * 2. Skip course categories for non-admins who do not have navshowmycoursecategories setting
@@ -176,7 +173,6 @@ class repository_local extends repository {
      */
     private function can_skip(file_info $fileinfo, $extensions, $parent = -1) {
         global $CFG;
-        static $skipcategories = null;
         if (!$fileinfo->is_directory()) {
             // do not skip files
             return false;
@@ -196,13 +192,14 @@ class repository_local extends repository {
             $params = $fileinfo->get_params();
             if (strlen($params['filearea']) &&
                     ($params['filepath'] === '/' || empty($params['filepath'])) &&
-                    ($params['filename'] === '.' || empty($params['filename']))) {
+                    ($params['filename'] === '.' || empty($params['filename'])) &&
+                    context::instance_by_id($params['contextid'])->contextlevel == CONTEXT_MODULE) {
                 if ($parent === -1) {
                     $parent = $fileinfo->get_parent();
                 }
                 // This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
                 if ($parent && ($parent instanceof file_info_context_module)) {
-                    if ($parent->count_non_empty_children($extensions) <= 1) {
+                    if ($parent->count_non_empty_children($extensions, 2) <= 1) {
                         return true;
                     }
                 }
-- 
1.7.9.5


From 7116aca6aff7c950e2be05a570d4c5c4003a018f Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 13 Sep 2012 10:29:21 +0800
Subject: [PATCH 667/903] MDL-35001 removed cycle detection from
 convert_to_array because it causes error in data

---
 lib/moodlelib.php |    7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 388ded6..167a653 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -10431,17 +10431,12 @@ function object_property_exists( $obj, $property ) {
  */
 function convert_to_array($var) {
     $result = array();
-    $references = array();
 
     // loop over elements/properties
     foreach ($var as $key => $value) {
         // recursively convert objects
         if (is_object($value) || is_array($value)) {
-            // but prevent cycles
-            if (!in_array($value, $references)) {
-                $result[$key] = convert_to_array($value);
-                $references[] = $value;
-            }
+            $result[$key] = convert_to_array($value);
         } else {
             // simple values are untouched
             $result[$key] = $value;
-- 
1.7.9.5


From 093825d81ede9260427c0938ec44c4338911da2a Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 19 Sep 2012 16:15:10 +0800
Subject: [PATCH 668/903] MDL-35001 added unit test for function
 convert_to_array()

---
 lib/tests/moodlelib_test.php |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 1abdf80..6beb856 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -1970,4 +1970,27 @@ class moodlelib_testcase extends advanced_testcase {
         $result = delete_user($admin);
         $this->assertFalse($result);
     }
+
+    /**
+     * Test function convert_to_array()
+     */
+    public function test_convert_to_array() {
+        // check that normal classes are converted to arrays the same way as (array) would do
+        $obj = new stdClass();
+        $obj->prop1 = 'hello';
+        $obj->prop2 = array('first', 'second', 13);
+        $obj->prop3 = 15;
+        $this->assertEquals(convert_to_array($obj), (array)$obj);
+
+        // check that context object (with iterator) is converted to array properly
+        $obj = get_system_context();
+        $ar = array(
+            'id'           => $obj->id,
+            'contextlevel' => $obj->contextlevel,
+            'instanceid'   => $obj->instanceid,
+            'path'         => $obj->path,
+            'depth'        => $obj->depth
+        );
+        $this->assertEquals(convert_to_array($obj), $ar);
+    }
 }
-- 
1.7.9.5


From a7783bf260d28c7ea781db36d8c657b27810554a Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 20 Sep 2012 10:21:42 +0800
Subject: [PATCH 669/903] MDL-35542 Fixed a bug when trying to directly link
 to a file from Dropbox

---
 repository/dropbox/lib.php |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/repository/dropbox/lib.php b/repository/dropbox/lib.php
index 768580e..508c05e 100644
--- a/repository/dropbox/lib.php
+++ b/repository/dropbox/lib.php
@@ -506,6 +506,10 @@ class repository_dropbox extends repository {
      */
     public function get_link($reference) {
         $ref = unserialize($reference);
+        if (!isset($ref->url)) {
+            $this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
+            $ref->url = $this->dropbox->get_file_share_link($ref->path, self::GETFILE_TIMEOUT);
+        }
         return $this->get_file_download_link($ref->url);
     }
 
-- 
1.7.9.5


From 2974030611430a060025254e381248c020e60e65 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 19 Sep 2012 17:24:38 +0200
Subject: [PATCH 670/903] MDL-35517 course: Handle non-existing
 $course->maxbytes on course creation.

---
 course/edit_form.php |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/course/edit_form.php b/course/edit_form.php
index 319bdac..20a010e 100644
--- a/course/edit_form.php
+++ b/course/edit_form.php
@@ -156,7 +156,11 @@ class course_edit_form extends moodleform {
         $mform->addHelpButton('showreports', 'showreports');
         $mform->setDefault('showreports', $courseconfig->showreports);
 
-        $choices = get_max_upload_sizes($CFG->maxbytes, 0, 0, $course->maxbytes);
+        // Handle non-existing $course->maxbytes on course creation.
+        $coursemaxbytes = !isset($course->maxbytes) ? null : $course->maxbytes;
+
+        // Let's prepare the maxbytes popup.
+        $choices = get_max_upload_sizes($CFG->maxbytes, 0, 0, $coursemaxbytes);
         $mform->addElement('select', 'maxbytes', get_string('maximumupload'), $choices);
         $mform->addHelpButton('maxbytes', 'maximumupload');
         $mform->setDefault('maxbytes', $courseconfig->maxbytes);
-- 
1.7.9.5


From 7ab5b064a6a23ec79b90c747a7d45c69ec383521 Mon Sep 17 00:00:00 2001
From: Michael Aherne <Michael Aherne>
Date: Wed, 19 Sep 2012 12:56:08 +0100
Subject: [PATCH 671/903] MDL-35321 course sections Enable reset of grouping
 access

---
 course/editsection.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/editsection.php b/course/editsection.php
index e4d6bea..c307a6d 100644
--- a/course/editsection.php
+++ b/course/editsection.php
@@ -78,7 +78,7 @@ if ($mform->is_cancelled()){
     if (!empty($CFG->enableavailability)) {
         $section->availablefrom = $data->availablefrom;
         $section->availableuntil = $data->availableuntil;
-        if (!empty($data->groupingid)) {
+        if (isset($data->groupingid)) {
             $section->groupingid = $data->groupingid;
         }
         $section->showavailability = $data->showavailability;
-- 
1.7.9.5


From 58f8b73f26c0e558d4dae5add1054bf847478cac Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 21 Sep 2012 00:34:52 +0000
Subject: [PATCH 672/903] Automatically generated installer lang files

---
 install/lang/fi/install.php    |    4 ++--
 install/lang/fo/langconfig.php |    3 ++-
 install/lang/fo/moodle.php     |   33 +++++++++++++++++++++++++++++++++
 install/lang/ko/install.php    |    2 +-
 install/lang/pt/error.php      |    2 +-
 5 files changed, 39 insertions(+), 5 deletions(-)
 create mode 100644 install/lang/fo/moodle.php

diff --git a/install/lang/fi/install.php b/install/lang/fi/install.php
index 61496e6..cffb9b0 100644
--- a/install/lang/fi/install.php
+++ b/install/lang/fi/install.php
@@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die();
 $string['admindirname'] = 'Ylläpitohakemisto';
 $string['availablelangs'] = 'Saatavilla olevat kielipaketit';
 $string['chooselanguagehead'] = 'Valitse kieli';
-$string['chooselanguagesub'] = 'Valitse kieli asennusohjelmaa varten. Voit valita muita kieliä käyttöösi myöhemmin.';
+$string['chooselanguagesub'] = 'Valitse kieli asennusohjelmaa varten. Tätä kieltä käytetään sivuston oletuskielenä, jonka voi vaihtaa tarpeen mukaan. Myöhemmin voit myös lisätä käyttöön muitakin kieliä.';
 $string['clialreadyconfigured'] = 'Tiedosto config.php on jo olemassa, käytä admin/cli/install_database.php -tiedostoa jos haluat asentaa tämän sivuston.';
 $string['clialreadyinstalled'] = 'Tiedosto config.php on jo olemassa, ole hyvä ja käytä admin/cli/upgrade.php:ta jos haluat päivittää sivustosi';
 $string['cliinstallheader'] = 'Moodlen {$a} komentoriviasennusohjelma';
@@ -43,7 +43,7 @@ $string['databasetypehead'] = 'Valitse tietokannan ajuri';
 $string['dataroot'] = 'Datahakemisto';
 $string['datarootpermission'] = 'Datahakemistojen oikeudet';
 $string['dbprefix'] = 'Taulukon etumerkki';
-$string['dirroot'] = 'Moodle hakemisto';
+$string['dirroot'] = 'Moodle-hakemisto';
 $string['environmenthead'] = 'Ympäristön tarkistus';
 $string['environmentsub2'] = 'Jokaisessa Moodle-julkaisussa on joitakin vähimmäisvaatimuksia PHP-versiolta sekä joitakin pakollisia PHP-lisäosia.
 Ennen jokaista asennusta ja päivitystä suoritetaan täysi ympäristön tarkistus. Ole hyvä ja ota yhteyttä palvelimen ylläpitoon jos et tiedä kuinka asentaa uutta versiota tai PHP-lisäosia.';
diff --git a/install/lang/fo/langconfig.php b/install/lang/fo/langconfig.php
index 9395d7d..f6af31f 100644
--- a/install/lang/fo/langconfig.php
+++ b/install/lang/fo/langconfig.php
@@ -30,4 +30,5 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['thislanguage'] = 'Faroese';
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = 'Føroyskt';
diff --git a/install/lang/fo/moodle.php b/install/lang/fo/moodle.php
new file mode 100644
index 0000000..be63909
--- /dev/null
+++ b/install/lang/fo/moodle.php
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Tungumál';
diff --git a/install/lang/ko/install.php b/install/lang/ko/install.php
index 5dfca0c..cff6e23 100644
--- a/install/lang/ko/install.php
+++ b/install/lang/ko/install.php
@@ -87,7 +87,7 @@ $string['welcomep20'] = '당신의 컴퓨터에 <strong>{$a->packname} {$a->pack
 $string['welcomep30'] = '<strong>{$a->installername}</strong> 판본은 <strong>무들</strong>이 동작하는 환경을 생성하기 위한 어플리케이션을 포함하고 있습니다.';
 $string['welcomep40'] = '이 패키지는 <strong>무들 {$a->moodlerelease} ({$a->moodleversion})</strong> 을 포함하고 있습니다.';
 $string['welcomep50'] = '이 패키지에 있는 모든 어플리케이션을 사용하는 것은 각각의 라이센스에의해 지배받습니다. 완전한<strong>{$a->installername}</strong> 패키지는
-<a href="http://www.opensource.org/docs/definition_plain.html">공개 소스이며 </a> <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 라이선스에 의해 배포됩니다.';
+<a href="http://www.opensource.org/docs/definition_plain.html">공개 소스</a>이며 <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> 라이선스에 의해 배포됩니다.';
 $string['welcomep60'] = '다음 페이지들은 컴퓨터에 <strong>무들</strong>을 설치하고 설정하는 길라잡이 역할을 할 것입니다. 기본 설정을 선택하거나 목적에 맞게 선택적으로 수정할 수 있습니다.';
 $string['welcomep70'] = '<strong>무들</strong> 설정을 계속하기 위해서는 "다음" 버튼을 클릭하세요.';
 $string['wwwroot'] = '웹 주소';
diff --git a/install/lang/pt/error.php b/install/lang/pt/error.php
index 23e90d0..e400a6c 100644
--- a/install/lang/pt/error.php
+++ b/install/lang/pt/error.php
@@ -40,7 +40,7 @@ $string['cannotsavezipfile'] = 'Não é possível gravar o ficheiro ZIP';
 $string['cannotunzipfile'] = 'Não é possível descompactar o ficheiro ZIP';
 $string['componentisuptodate'] = 'O componente está atualizado.';
 $string['downloadedfilecheckfailed'] = 'A verificação do ficheiro descarregado falhou.';
-$string['invalidmd5'] = 'md5 inválido';
+$string['invalidmd5'] = 'A variável de verificação está errada - tente novamente.';
 $string['missingrequiredfield'] = 'Um dos campos obrigatórios está em falta';
 $string['remotedownloaderror'] = 'A descarga do componente para o servidor falhou. Verifique as configurações do proxy. A instalação da extensão cURL do PHP é muito recomendada.<br /><br />Terá que descarregar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copiá-lo para a pasta "{$a->dest}" no seu servidor e descompactá-lo.';
 $string['wrongdestpath'] = 'Caminho de destino errado.';
-- 
1.7.9.5


From 7be6c09db583976c5402b8f21fe88774ebe72103 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 17 Sep 2012 16:57:05 +0800
Subject: [PATCH 673/903] MDL-34607 File API: Removed ordering by sortorder in
 area tree

---
 lib/filestorage/file_storage.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/filestorage/file_storage.php b/lib/filestorage/file_storage.php
index 917705b..c34ebe6 100644
--- a/lib/filestorage/file_storage.php
+++ b/lib/filestorage/file_storage.php
@@ -443,7 +443,7 @@ class file_storage {
      */
     public function get_area_tree($contextid, $component, $filearea, $itemid) {
         $result = array('dirname'=>'', 'dirfile'=>null, 'subdirs'=>array(), 'files'=>array());
-        $files = $this->get_area_files($contextid, $component, $filearea, $itemid, "sortorder, itemid, filepath, filename", true);
+        $files = $this->get_area_files($contextid, $component, $filearea, $itemid, "itemid, filepath, filename", true);
         // first create directory structure
         foreach ($files as $hash=>$dir) {
             if (!$dir->is_directory()) {
-- 
1.7.9.5


From 7ae2136b3fc1bd575cac7dd7a5b3dc69e216488c Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 17 Sep 2012 17:02:30 +0800
Subject: [PATCH 674/903] MDL-34607 Folder: Remove any sort order during
 upgrade

---
 lib/db/upgrade.php |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 97f3fb2..386792c 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -959,5 +959,15 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.14);
     }
 
+    if ($oldversion < 2012062502.02) {
+        // Some folders still have a sortorder set, which is used for main files but is not
+        // supported by the folder resource. We reset the value here.
+        $sql = 'UPDATE {files} SET sortorder = ? WHERE component = ? AND filearea = ? AND sortorder <> ?';
+        $DB->execute($sql, array(0, 'mod_folder', 'content', 0));
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2012062502.02);
+    }
+
     return true;
 }
-- 
1.7.9.5


From aa578540751385bde731f726c38744228e94026a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 17 Sep 2012 11:54:37 +0800
Subject: [PATCH 675/903] MDL-35242 Web Services: Removed translation causing
 error in add_to_log

---
 login/token.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/login/token.php b/login/token.php
index adfe1d4..9194de2 100644
--- a/login/token.php
+++ b/login/token.php
@@ -160,7 +160,7 @@ if (!empty($user)) {
             $token->timecreated = time();
             $token->externalserviceid = $service_record->id;
             $tokenid = $DB->insert_record('external_tokens', $token);
-            add_to_log(SITEID, 'webservice', get_string('createtokenforuserauto', 'webservice'), '' , 'User ID: ' . $user->id);
+            add_to_log(SITEID, 'webservice', 'automatically create user token', '' , 'User ID: ' . $user->id);
             $token->id = $tokenid;
         } else {
             throw new moodle_exception('cannotcreatetoken', 'webservice', '', $serviceshortname);
-- 
1.7.9.5


From 6b15d50a60fd49cc68d98dffd632f00a9d0206c3 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Mon, 17 Sep 2012 11:38:43 +0800
Subject: [PATCH 676/903] MDL-35312 Web Services: Fixed typo in capability of
 course update

---
 lib/db/services.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/db/services.php b/lib/db/services.php
index 4df607a..dbbc38b 100644
--- a/lib/db/services.php
+++ b/lib/db/services.php
@@ -522,7 +522,7 @@ $functions = array(
         'classpath'   => 'course/externallib.php',
         'description' => 'Update categories',
         'type'        => 'write',
-        'capabilities'=> 'moodle:category/manage',
+        'capabilities'=> 'moodle/category:manage',
     ),
 
     'core_course_delete_categories' => array(
-- 
1.7.9.5


From 05daea0f6d8f3b8673755762c96554837d7e70a2 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 11 Sep 2012 14:53:15 +0800
Subject: [PATCH 677/903] MDL-31976 Accessbility: Action icons on course page
 do not need title attributes

---
 course/format/renderer.php        |    3 ++-
 course/lib.php                    |   33 +++++++++++++++------------------
 course/yui/toolboxes/toolboxes.js |    6 ------
 lib/outputcomponents.php          |    4 ++++
 lib/yui/dragdrop/dragdrop.js      |    3 +--
 5 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index c758cac..26f7824 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -168,7 +168,8 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
             $url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
             $o.= html_writer::link($url,
-                html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'), 'class' => 'iconsmall edit')),
+                html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'),
+                    'class' => 'iconsmall edit', 'alt' => get_string('editsummary'))),
                 array('title' => get_string('editsummary')));
         }
         $o.= html_writer::end_tag('div');
diff --git a/course/lib.php b/course/lib.php
index ac7a957..c3fa3cb 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1572,8 +1572,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     // Display link itself
                     echo '<a ' . $linkcss . $mod->extra . $onclick .
                             ' href="' . $url . '"><img src="' . $mod->get_icon_url() .
-                            '" class="activityicon" alt="' .
-                            $modulename . '" /> ' .
+                            '" class="activityicon" alt="" /> ' .
                             $accesstext . '<span class="instancename">' .
                             $instancename . $altname . '</span></a>';
 
@@ -1608,9 +1607,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     // Display greyed-out text of link
                     echo '<div ' . $textcss . $mod->extra .
                             ' >' . '<img src="' . $mod->get_icon_url() .
-                            '" class="activityicon" alt="' .
-                            $modulename .
-                            '" /> <span>'. $instancename . $altname .
+                            '" class="activityicon" alt="" /> <span>'. $instancename . $altname .
                             '</span></div>';
 
                     // Do not display content after link when it is greyed out like this.
@@ -3204,7 +3201,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if ($mod->modname !== 'label' && $hasmanageactivities && course_ajax_enabled($COURSE)) {
         $actions[] = new action_link(
             new moodle_url($baseurl, array('update' => $mod->id)),
-            new pix_icon('t/editstring', $str->edittitle, 'moodle', array('class' => 'iconsmall visibleifjs')),
+            new pix_icon('t/editstring', $str->edittitle, 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')),
             null,
             array('class' => 'editing_title', 'title' => $str->edittitle)
         );
@@ -3223,7 +3220,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         if ($indent > 0) {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')),
-                new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_moveleft', 'title' => $str->moveleft)
             );
@@ -3231,7 +3228,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         if ($indent >= 0) {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')),
-                new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_moveright', 'title' => $str->moveright)
             );
@@ -3243,20 +3240,20 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         if ($moveselect) {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('copy' => $mod->id)),
-                new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_move', 'title' => $str->move)
             );
         } else {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('id' => $mod->id, 'move' => '-1')),
-                new pix_icon('t/up', $str->moveup, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon('t/up', $str->moveup, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_moveup', 'title' => $str->moveup)
             );
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('id' => $mod->id, 'move' => '1')),
-                new pix_icon('t/down', $str->movedown, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon('t/down', $str->movedown, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_movedown', 'title' => $str->movedown)
             );
@@ -3267,7 +3264,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if ($hasmanageactivities) {
         $actions[] = new action_link(
             new moodle_url($baseurl, array('update' => $mod->id)),
-            new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall')),
+            new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall', 'title' => '')),
             null,
             array('class' => 'editing_update', 'title' => $str->update)
         );
@@ -3277,7 +3274,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) {
         $actions[] = new action_link(
             new moodle_url($baseurl, array('duplicate' => $mod->id)),
-            new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall')),
+            new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')),
             null,
             array('class' => 'editing_duplicate', 'title' => $str->duplicate)
         );
@@ -3287,7 +3284,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if ($hasmanageactivities) {
         $actions[] = new action_link(
             new moodle_url($baseurl, array('delete' => $mod->id)),
-            new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall')),
+            new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')),
             null,
             array('class' => 'editing_delete', 'title' => $str->delete)
         );
@@ -3298,14 +3295,14 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         if ($mod->visible) {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('hide' => $mod->id)),
-                new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_hide', 'title' => $str->hide)
             );
         } else {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('show' => $mod->id)),
-                new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => 'editing_show', 'title' => $str->show)
             );
@@ -3336,7 +3333,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
         if ($mod->groupmodelink) {
             $actions[] = new action_link(
                 new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $groupmode)),
-                new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall')),
+                new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall', 'title' => '')),
                 null,
                 array('class' => $groupclass, 'title' => $grouptitle)
             );
@@ -3349,7 +3346,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
     if (has_capability('moodle/role:assign', $modcontext)){
         $actions[] = new action_link(
             new moodle_url('/'.$CFG->admin.'/roles/assign.php', array('contextid' => $modcontext->id)),
-            new pix_icon('i/roles', $str->assign, 'moodle', array('class' => 'iconsmall')),
+            new pix_icon('i/roles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')),
             null,
             array('class' => 'editing_assign', 'title' => $str->assign)
         );
diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
index 024785e..2b92347 100644
--- a/course/yui/toolboxes/toolboxes.js
+++ b/course/yui/toolboxes/toolboxes.js
@@ -106,7 +106,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             var newstring = M.util.get_string(status, 'moodle');
             hideicon.setAttrs({
                 'alt' : newstring,
-                'title' : newstring,
                 'src'   : M.util.image_url('t/' + status)
             });
             button.set('title', newstring);
@@ -446,7 +445,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             // Change the UI
             icon.setAttrs({
                 'alt' : newtitle,
-                'title' : newtitle,
                 'src' : iconsrc
             });
             button.setAttribute('title', newtitle);
@@ -473,7 +471,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 .addClass(CSS.GENERICICONCLASS)
                 .setAttrs({
                     'src'   : M.util.image_url('t/left', 'moodle'),
-                    'title' : left_string,
                     'alt'   : left_string
                 });
             var moveright = target.one(CSS.MOVERIGHT);
@@ -682,7 +679,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             var newstring = M.util.get_string(status + 'fromothers', 'format_' + this.get('format'));
             hideicon.setAttrs({
                 'alt' : newstring,
-                'title' : newstring,
                 'src'   : M.util.image_url('i/' + status)
             });
             button.set('title', newstring);
@@ -740,7 +736,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 .set('title', old_string);
             Y.one(CSS.PAGECONTENT)
                 .all(M.course.format.get_section_selector(Y) + '.current ' + CSS.HIGHLIGHT + ' img')
-                .set('title', old_string)
                 .set('alt', old_string)
                 .set('src', M.util.image_url('i/marker'));
 
@@ -756,7 +751,6 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 button
                     .set('title', new_string);
                 buttonicon
-                    .set('title', new_string)
                     .set('alt', new_string)
                     .set('src', M.util.image_url('i/marked'));
             }
diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index 6b760c2..a20bd7c 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -550,6 +550,10 @@ class pix_icon implements renderable {
         }
         if (!isset($this->attributes['title'])) {
             $this->attributes['title'] = $this->attributes['alt'];
+        } else if (empty($this->attributes['title'])) {
+            // Remove the title attribute if empty, we probably want to use the parent node's title
+            // and some browsers might overwrite it with an empty title.
+            unset($this->attributes['title']);
         }
     }
 }
diff --git a/lib/yui/dragdrop/dragdrop.js b/lib/yui/dragdrop/dragdrop.js
index 6669f37..17b368c 100644
--- a/lib/yui/dragdrop/dragdrop.js
+++ b/lib/yui/dragdrop/dragdrop.js
@@ -36,8 +36,7 @@ YUI.add('moodle-core-dragdrop', function(Y) {
                 .setStyle('cursor', 'move')
                 .setAttrs({
                     'src' : M.util.image_url(MOVEICON.pix, MOVEICON.component),
-                    'alt' : title,
-                    'title' : M.str.moodle.move
+                    'alt' : title
                 });
             if (iconclass) {
                 dragicon.addClass(iconclass);
-- 
1.7.9.5


From 7cdb7250812cad36ffc384d94375cec8b836ef01 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 6 Sep 2012 15:13:38 +0800
Subject: [PATCH 678/903] MDL-30889 calendar: Adding focus and blur events to
 calendar renderer

---
 calendar/yui/eventmanager/eventmanager.js |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/calendar/yui/eventmanager/eventmanager.js b/calendar/yui/eventmanager/eventmanager.js
index 578ba81..7230dd2 100644
--- a/calendar/yui/eventmanager/eventmanager.js
+++ b/calendar/yui/eventmanager/eventmanager.js
@@ -24,6 +24,8 @@ YUI.add('moodle-calendar-eventmanager', function(Y) {
             this.publish('hideevent');
             td.on('mouseenter', this.startShow, this);
             td.on('mouseleave', this.startHide, this);
+            td.on('focus', this.startShow, this);
+            td.on('blur', this.startHide, this);
             return true;
         },
         initPanel : function() {
-- 
1.7.9.5


From 94167a2dee8bcaaa764c7289603684c534cd06be Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Fri, 21 Sep 2012 13:25:20 +0800
Subject: [PATCH 679/903] MDL-34476 - Course Completeion, Blocks - Allowing
 teachers to access the Full Course Report from the
 Course Completion Block -- Initial patch provided
 by Nadav Kavalerchik

---
 blocks/completionstatus/block_completionstatus.php |  223 ++++++++++----------
 1 file changed, 110 insertions(+), 113 deletions(-)

diff --git a/blocks/completionstatus/block_completionstatus.php b/blocks/completionstatus/block_completionstatus.php
index 449e632..2e00684 100644
--- a/blocks/completionstatus/block_completionstatus.php
+++ b/blocks/completionstatus/block_completionstatus.php
@@ -83,148 +83,145 @@ class block_completionstatus extends block_base {
         }
 
         // Check this user is enroled
-        if (!$info->is_tracked_user($USER->id)) {
-            // If not enrolled, but are can view the report:
-            if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $course->id))) {
-                $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
-                $this->content->text = '<a href="'.$report->out().'">'.get_string('viewcoursereport', 'completion').'</a>';
-                return $this->content;
-            }
+        if ($info->is_tracked_user($USER->id)) {
 
-            // Otherwise, show error
-            $this->content->text = get_string('notenroled', 'completion');
-            return $this->content;
-        }
+            // Generate markup for criteria statuses
+            $shtml = '';
 
-        // Generate markup for criteria statuses
-        $shtml = '';
+            // For aggregating activity completion
+            $activities = array();
+            $activities_complete = 0;
 
-        // For aggregating activity completion
-        $activities = array();
-        $activities_complete = 0;
+            // For aggregating course prerequisites
+            $prerequisites = array();
+            $prerequisites_complete = 0;
 
-        // For aggregating course prerequisites
-        $prerequisites = array();
-        $prerequisites_complete = 0;
+            // Flag to set if current completion data is inconsistent with
+            // what is stored in the database
+            $pending_update = false;
 
-        // Flag to set if current completion data is inconsistent with
-        // what is stored in the database
-        $pending_update = false;
+            // Loop through course criteria
+            foreach ($completions as $completion) {
 
-        // Loop through course criteria
-        foreach ($completions as $completion) {
+                $criteria = $completion->get_criteria();
+                $complete = $completion->is_complete();
 
-            $criteria = $completion->get_criteria();
-            $complete = $completion->is_complete();
+                if (!$pending_update && $criteria->is_pending($completion)) {
+                    $pending_update = true;
+                }
 
-            if (!$pending_update && $criteria->is_pending($completion)) {
-                $pending_update = true;
-            }
+                // Activities are a special case, so cache them and leave them till last
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
+                    $activities[$criteria->moduleinstance] = $complete;
 
-            // Activities are a special case, so cache them and leave them till last
-            if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
-                $activities[$criteria->moduleinstance] = $complete;
+                    if ($complete) {
+                        $activities_complete++;
+                    }
 
-                if ($complete) {
-                    $activities_complete++;
+                    continue;
                 }
 
-                continue;
-            }
+                // Prerequisites are also a special case, so cache them and leave them till last
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
+                    $prerequisites[$criteria->courseinstance] = $complete;
 
-            // Prerequisites are also a special case, so cache them and leave them till last
-            if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
-                $prerequisites[$criteria->courseinstance] = $complete;
+                    if ($complete) {
+                        $prerequisites_complete++;
+                    }
 
-                if ($complete) {
-                    $prerequisites_complete++;
+                    continue;
                 }
 
-                continue;
+                $shtml .= '<tr><td>';
+                $shtml .= $criteria->get_title();
+                $shtml .= '</td><td style="text-align: right">';
+                $shtml .= $completion->get_status();
+                $shtml .= '</td></tr>';
             }
 
-            $shtml .= '<tr><td>';
-            $shtml .= $criteria->get_title();
-            $shtml .= '</td><td style="text-align: right">';
-            $shtml .= $completion->get_status();
-            $shtml .= '</td></tr>';
-        }
+            // Aggregate activities
+            if (!empty($activities)) {
+
+                $shtml .= '<tr><td>';
+                $shtml .= get_string('activitiescompleted', 'completion');
+                $shtml .= '</td><td style="text-align: right">';
+                $a = new stdClass();
+                $a->first = $activities_complete;
+                $a->second = count($activities);
+                $shtml .= get_string('firstofsecond', 'block_completionstatus', $a);
+                $shtml .= '</td></tr>';
+            }
 
-        // Aggregate activities
-        if (!empty($activities)) {
-
-            $shtml .= '<tr><td>';
-            $shtml .= get_string('activitiescompleted', 'completion');
-            $shtml .= '</td><td style="text-align: right">';
-            $a = new stdClass();
-            $a->first = $activities_complete;
-            $a->second = count($activities);
-            $shtml .= get_string('firstofsecond', 'block_completionstatus', $a);
-            $shtml .= '</td></tr>';
-        }
+            // Aggregate prerequisites
+            if (!empty($prerequisites)) {
 
-        // Aggregate prerequisites
-        if (!empty($prerequisites)) {
+                $phtml  = '<tr><td>';
+                $phtml .= get_string('prerequisitescompleted', 'completion');
+                $phtml .= '</td><td style="text-align: right">';
+                $a = new stdClass();
+                $a->first = $prerequisites_complete;
+                $a->second = count($prerequisites);
+                $phtml .= get_string('firstofsecond', 'block_completionstatus', $a);
+                $phtml .= '</td></tr>';
 
-            $phtml  = '<tr><td>';
-            $phtml .= get_string('prerequisitescompleted', 'completion');
-            $phtml .= '</td><td style="text-align: right">';
-            $a = new stdClass();
-            $a->first = $prerequisites_complete;
-            $a->second = count($prerequisites);
-            $phtml .= get_string('firstofsecond', 'block_completionstatus', $a);
-            $phtml .= '</td></tr>';
+                $shtml = $phtml . $shtml;
+            }
 
-            $shtml = $phtml . $shtml;
-        }
+            // Display completion status
+            $this->content->text  = '<table width="100%" style="font-size: 90%;"><tbody>';
+            $this->content->text .= '<tr><td colspan="2"><b>'.get_string('status').':</b> ';
+
+            // Is course complete?
+            $coursecomplete = $info->is_course_complete($USER->id);
+
+            // Load course completion
+            $params = array(
+                'userid' => $USER->id,
+                'course' => $course->id
+            );
+            $ccompletion = new completion_completion($params);
+
+            // Has this user completed any criteria?
+            $criteriacomplete = $info->count_course_user_data($USER->id);
+
+            if ($pending_update) {
+                $this->content->text .= '<i>'.get_string('pending', 'completion').'</i>';
+            } else if ($coursecomplete) {
+                $this->content->text .= get_string('complete');
+            } else if (!$criteriacomplete && !$ccompletion->timestarted) {
+                $this->content->text .= '<i>'.get_string('notyetstarted', 'completion').'</i>';
+            } else {
+                $this->content->text .= '<i>'.get_string('inprogress','completion').'</i>';
+            }
 
-        // Display completion status
-        $this->content->text  = '<table width="100%" style="font-size: 90%;"><tbody>';
-        $this->content->text .= '<tr><td colspan="2"><b>'.get_string('status').':</b> ';
-
-        // Is course complete?
-        $coursecomplete = $info->is_course_complete($USER->id);
-
-        // Load course completion
-        $params = array(
-            'userid' => $USER->id,
-            'course' => $course->id
-        );
-        $ccompletion = new completion_completion($params);
-
-        // Has this user completed any criteria?
-        $criteriacomplete = $info->count_course_user_data($USER->id);
-
-        if ($pending_update) {
-            $this->content->text .= '<i>'.get_string('pending', 'completion').'</i>';
-        } else if ($coursecomplete) {
-            $this->content->text .= get_string('complete');
-        } else if (!$criteriacomplete && !$ccompletion->timestarted) {
-            $this->content->text .= '<i>'.get_string('notyetstarted', 'completion').'</i>';
-        } else {
-            $this->content->text .= '<i>'.get_string('inprogress','completion').'</i>';
-        }
+            $this->content->text .= '</td></tr>';
+            $this->content->text .= '<tr><td colspan="2">';
+
+            // Get overall aggregation method
+            $overall = $info->get_aggregation_method();
 
-        $this->content->text .= '</td></tr>';
-        $this->content->text .= '<tr><td colspan="2">';
+            if ($overall == COMPLETION_AGGREGATION_ALL) {
+                $this->content->text .= get_string('criteriarequiredall', 'completion');
+            } else {
+                $this->content->text .= get_string('criteriarequiredany', 'completion');
+            }
 
-        // Get overall aggregation method
-        $overall = $info->get_aggregation_method();
+            $this->content->text .= ':</td></tr>';
+            $this->content->text .= '<tr><td><b>'.get_string('requiredcriteria', 'completion').'</b></td><td style="text-align: right"><b>'.get_string('status').'</b></td></tr>';
+            $this->content->text .= $shtml.'</tbody></table>';
 
-        if ($overall == COMPLETION_AGGREGATION_ALL) {
-            $this->content->text .= get_string('criteriarequiredall', 'completion');
+            // Display link to detailed view
+            $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+            $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
         } else {
-            $this->content->text .= get_string('criteriarequiredany', 'completion');
+            // If user is not enrolled, show error
+            $this->content->text = get_string('notenroled', 'completion');
         }
 
-        $this->content->text .= ':</td></tr>';
-        $this->content->text .= '<tr><td><b>'.get_string('requiredcriteria', 'completion').'</b></td><td style="text-align: right"><b>'.get_string('status').'</b></td></tr>';
-        $this->content->text .= $shtml.'</tbody></table>';
-
-        // Display link to detailed view
-        $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
-        $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
-
+        if (has_capability('report/completion:view', $context)) {
+            $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
+            $this->content->footer .= '<br /><a href="'.$report->out().'">'.get_string('viewcoursereport', 'completion').'</a>';
+        }
         return $this->content;
     }
 }
-- 
1.7.9.5


From 99cd723af5117e4388b5519da1aca1ad17327ba4 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Fri, 24 Aug 2012 15:23:03 +1200
Subject: [PATCH 680/903] MDL-34328: course dragdrop - performance rewrite

Use YUI's DragDrop delegates for course dragdrop, rather than initialising a Drag object for each individual section and each individual activity/resource.  Also, clone a single drag handle for activities/resources, rather than repeatedly creating a whole new one with the same parameters for each activity/resource.
---
 course/yui/dragdrop/dragdrop.js |   87 ++++++++++++++++++++++-----------------
 1 file changed, 49 insertions(+), 38 deletions(-)

diff --git a/course/yui/dragdrop/dragdrop.js b/course/yui/dragdrop/dragdrop.js
index 435b355..f52497e 100644
--- a/course/yui/dragdrop/dragdrop.js
+++ b/course/yui/dragdrop/dragdrop.js
@@ -41,6 +41,26 @@ YUI.add('moodle-course-dragdrop', function(Y) {
             if (this.sectionlistselector) {
                 this.sectionlistselector = '.'+CSS.COURSECONTENT+' '+this.sectionlistselector;
                 this.setup_for_section(this.sectionlistselector);
+
+                // Make each li element in the lists of sections draggable
+                var nodeselector = this.sectionlistselector.slice(CSS.COURSECONTENT.length+2);
+                var del = new Y.DD.Delegate({
+                    container: '.'+CSS.COURSECONTENT,
+                    nodes: nodeselector,
+                    target: true,
+                    handles: ['.'+CSS.LEFT],
+                    dragConfig: {groups: this.groups}
+                });
+                del.dd.plug(Y.Plugin.DDProxy, {
+                    // Don't move the node at the end of the drag
+                    moveOnEnd: false
+                });
+                del.dd.plug(Y.Plugin.DDConstrained, {
+                    // Keep it inside the .course-content
+                    constrain: '#'+CSS.PAGECONTENT,
+                    stickY: true
+                });
+                del.dd.plug(Y.Plugin.DDWinScroll);
             }
         },
 
@@ -76,22 +96,6 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                         if (movedown) {
                             movedown.remove();
                         }
-
-                        // Make each li element in the lists of sections draggable
-                        var dd = new Y.DD.Drag({
-                            node: sectionnode,
-                            // Make each li a Drop target too
-                            groups: this.groups,
-                            target: true,
-                            handles: ['.'+CSS.LEFT]
-                        }).plug(Y.Plugin.DDProxy, {
-                            // Don't move the node at the end of the drag
-                            moveOnEnd: false
-                        }).plug(Y.Plugin.DDConstrained, {
-                            // Keep it inside the .course-content
-                            constrain: '#'+CSS.PAGECONTENT,
-                            stickY: true
-                        }).plug(Y.Plugin.DDWinScroll);
                     }
                 }
             }, this);
@@ -244,12 +248,33 @@ YUI.add('moodle-course-dragdrop', function(Y) {
             this.groups = ['resource'];
             this.samenodeclass = CSS.ACTIVITY;
             this.parentnodeclass = CSS.SECTION;
+            this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS);
 
             // Go through all sections
             var sectionlistselector = M.course.format.get_section_selector(Y);
             if (sectionlistselector) {
                 sectionlistselector = '.'+CSS.COURSECONTENT+' '+sectionlistselector;
                 this.setup_for_section(sectionlistselector);
+
+                // Initialise drag & drop for all resources/activities
+                var nodeselector = sectionlistselector.slice(CSS.COURSECONTENT.length+2)+' li.'+CSS.ACTIVITY;
+                var del = new Y.DD.Delegate({
+                    container: '.'+CSS.COURSECONTENT,
+                    nodes: nodeselector,
+                    target: true,
+                    handles: ['.' + CSS.EDITINGMOVE],
+                    dragConfig: {groups: this.groups}
+                });
+                del.dd.plug(Y.Plugin.DDProxy, {
+                    // Don't move the node at the end of the drag
+                    moveOnEnd: false
+                });
+                del.dd.plug(Y.Plugin.DDConstrained, {
+                    // Keep it inside the .course-content
+                    constrain: '#'+CSS.PAGECONTENT
+                });
+                del.dd.plug(Y.Plugin.DDWinScroll);
+
                 M.course.coursebase.register_module(this);
                 M.course.dragres = this;
             }
@@ -269,15 +294,15 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                     var resources = Y.Node.create('<ul></ul>');
                     resources.addClass(CSS.SECTION);
                     sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
+                    // Define empty ul as droptarget, so that item could be moved to empty list
+                    var tar = new Y.DD.Drop({
+                        node: resources,
+                        groups: this.groups,
+                        padding: '20 0 20 0'
+                    });
                 }
 
-                // Define each ul as droptarget, so that item could be moved to empty list
-                var tar = new Y.DD.Drop({
-                    node: resources,
-                    groups: this.groups,
-                    padding: '20 0 20 0'
-                });
-                // Go through each li element and make them draggable
+                // Initialise each resource/activity in this section
                 this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY);
             }, this);
         },
@@ -292,21 +317,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                 // Replace move icons
                 var move = resourcesnode.one('a.'+CSS.EDITINGMOVE);
                 if (move) {
-                    move.replace(this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS));
-                    // Make each li element in the lists of sections draggable
-                    var dd = new Y.DD.Drag({
-                        node: resourcesnode,
-                        groups: this.groups,
-                        // Make each li a Drop target too
-                        target: true,
-                        handles: ['.' + CSS.EDITINGMOVE]
-                    }).plug(Y.Plugin.DDProxy, {
-                        // Don't move the node at the end of the drag
-                        moveOnEnd: false
-                    }).plug(Y.Plugin.DDConstrained, {
-                        // Keep it inside the .course-content
-                        constrain: '#'+CSS.PAGECONTENT
-                    }).plug(Y.Plugin.DDWinScroll);
+                    move.replace(this.resourcedraghandle.cloneNode(true));
                 }
             }, this);
         },
-- 
1.7.9.5


From e4db46b4d9130dc4f8c757b4e2e489ae507e35c8 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Fri, 24 Aug 2012 15:50:08 +1200
Subject: [PATCH 681/903] MDL-34328: course resource "toolboxes" - performance
 rewrite

Use YUI event delegation to handle events in course resource "toolboxes" (sets of editing icons) rather than attaching event handlers to each individual button we care about.  Don't waste time setting the CSS cursor to what it already is, use .all() rather than replace_button() if we just need the node.

Section toolboxes could probably also be done this way to some extent, but the payoff may not be worth the effort - they're so minimal that they don't tend to cause issues.
---
 course/yui/toolboxes/toolboxes.js |   42 +++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
index 024785e..321ce8c 100644
--- a/course/yui/toolboxes/toolboxes.js
+++ b/course/yui/toolboxes/toolboxes.js
@@ -241,6 +241,17 @@ YUI.add('moodle-course-toolboxes', function(Y) {
         initializer : function(config) {
             this.setup_for_resource();
             M.course.coursebase.register_module(this);
+
+            var prefix = CSS.ACTIVITYLI + ' ' + CSS.COMMANDSPAN + ' ';
+            Y.delegate('click', this.edit_resource_title, CSS.PAGECONTENT, prefix + CSS.EDITTITLE, this);
+            Y.delegate('click', this.move_left, CSS.PAGECONTENT, prefix + CSS.MOVELEFT, this);
+            Y.delegate('click', this.move_right, CSS.PAGECONTENT, prefix + CSS.MOVERIGHT, this);
+            Y.delegate('click', this.delete_resource, CSS.PAGECONTENT, prefix + CSS.DELETE, this);
+            Y.delegate('click', this.toggle_hide_resource, CSS.PAGECONTENT, prefix + CSS.HIDE, this);
+            Y.delegate('click', this.toggle_hide_resource, CSS.PAGECONTENT, prefix + CSS.SHOW, this);
+            Y.delegate('click', this.toggle_groupmode, CSS.PAGECONTENT, prefix + CSS.GROUPSNONE, this);
+            Y.delegate('click', this.toggle_groupmode, CSS.PAGECONTENT, prefix + CSS.GROUPSSEPARATE, this);
+            Y.delegate('click', this.toggle_groupmode, CSS.PAGECONTENT, prefix + CSS.GROUPSVISIBLE, this);
         },
 
         /**
@@ -252,27 +263,16 @@ YUI.add('moodle-course-toolboxes', function(Y) {
          */
         setup_for_resource : function(baseselector) {
             if (!baseselector) {
-                var baseselector = CSS.PAGECONTENT + ' ' + CSS.ACTIVITYLI;;
+                var baseselector = CSS.PAGECONTENT + ' ' + CSS.ACTIVITYLI;
             }
 
             Y.all(baseselector).each(this._setup_for_resource, this);
         },
         _setup_for_resource : function(toolboxtarget) {
-            // Edit Title
-            this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.EDITTITLE, this.edit_resource_title);
-
-            // Move left and right
-            this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.MOVELEFT, this.move_left);
-            this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.MOVERIGHT, this.move_right);
-
-            // Delete
-            this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.DELETE, this.delete_resource);
-
-            // Show/Hide
-            var showhide = this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.HIDE, this.toggle_hide_resource);
-            var shown = this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.SHOW, this.toggle_hide_resource);
-
-            showhide = showhide.concat(shown);
+            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)) {
@@ -280,15 +280,15 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 }
             });
 
-            // Change Group Mode
+            // Set groupmode attribute for use by this.toggle_groupmode()
             var groups;
-            groups = this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.GROUPSNONE, this.toggle_groupmode);
+            groups = toolboxtarget.all(CSS.COMMANDSPAN + ' ' + CSS.GROUPSNONE);
             groups.setAttribute('groupmode', this.GROUPS_NONE);
 
-            groups = this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.GROUPSSEPARATE, this.toggle_groupmode);
+            groups = toolboxtarget.all(CSS.COMMANDSPAN + ' ' + CSS.GROUPSSEPARATE);
             groups.setAttribute('groupmode', this.GROUPS_SEPARATE);
 
-            groups = this.replace_button(toolboxtarget, CSS.COMMANDSPAN + ' ' + CSS.GROUPSVISIBLE, this.toggle_groupmode);
+            groups = toolboxtarget.all(CSS.COMMANDSPAN + ' ' + CSS.GROUPSVISIBLE);
             groups.setAttribute('groupmode', this.GROUPS_VISIBLE);
         },
         move_left : function(e) {
@@ -405,6 +405,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             };
             var spinner = M.util.add_spinner(Y, element.one(CSS.SPINNERCOMMANDSPAN));
             this.send_request(data, spinner);
+            return false; // Need to return false to stop the delegate for the new state firing
         },
         toggle_groupmode : function(e) {
             // Prevent the default button action
@@ -460,6 +461,7 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             };
             var spinner = M.util.add_spinner(Y, element.one(CSS.SPINNERCOMMANDSPAN));
             this.send_request(data, spinner);
+            return false; // Need to return false to stop the delegate for the new state firing
         },
         /**
          * Add the moveleft button
-- 
1.7.9.5


From a573a5157e5fbf399c1c970ab1bc6fb27cecaa21 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Wed, 5 Sep 2012 11:59:11 +1200
Subject: [PATCH 682/903] MDL-34328: course section "toolboxes" - performance
 rewrite

Use YUI event delegation to handle events in course section "toolboxes" (visibility and highlight toggles) rather than attaching event handlers to each individual button we care about.  Also remove the (now unused) replace_button() function.
---
 course/yui/toolboxes/toolboxes.js |   43 ++++++++++---------------------------
 1 file changed, 11 insertions(+), 32 deletions(-)

diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
index 321ce8c..6954890 100644
--- a/course/yui/toolboxes/toolboxes.js
+++ b/course/yui/toolboxes/toolboxes.js
@@ -49,32 +49,9 @@ YUI.add('moodle-course-toolboxes', function(Y) {
 
     Y.extend(TOOLBOX, Y.Base, {
         /**
-         * Replace the button click at the selector with the specified
-         * callback
-         *
-         * @param toolboxtarget The selector of the working area
-         * @param selector The 'button' to replace
-         * @param callback The callback to apply
-         * @param cursor An optional cursor style to apply
+         * Toggle the visibility and availability for the specified
+         * resource show/hide button
          */
-        replace_button : function(toolboxtarget, selector, callback, cursor) {
-            if (!cursor) {
-                // Set the default cursor type to pointer to match the
-                // anchor
-                cursor = 'pointer';
-            }
-            var button = Y.one(toolboxtarget).all(selector)
-                .setStyle('cursor', cursor);
-
-            // on isn't chainable and will return an event
-            button.on('click', callback, this);
-
-            return button;
-        },
-          /**
-           * Toggle the visibility and availability for the specified
-           * resource show/hide button
-           */
         toggle_hide_resource_ui : function(button) {
             var element = button.ancestor(CSS.ACTIVITYLI);
             var hideicon = button.one('img');
@@ -634,6 +611,11 @@ YUI.add('moodle-course-toolboxes', function(Y) {
         initializer : function(config) {
             this.setup_for_section();
             M.course.coursebase.register_module(this);
+
+            // Section Highlighting
+            Y.delegate('click', this.toggle_highlight, CSS.PAGECONTENT, CSS.SECTIONLI + ' ' + CSS.HIGHLIGHT, this);
+            // Section Visibility
+            Y.delegate('click', this.toggle_hide_section, CSS.PAGECONTENT, CSS.SECTIONLI + ' ' + CSS.SHOWHIDE, this);
         },
         /**
          * Update any section areas within the scope of the specified
@@ -643,18 +625,15 @@ YUI.add('moodle-course-toolboxes', function(Y) {
          * @return void
          */
         setup_for_section : function(baseselector) {
-            if (!baseselector) {
+            // Left here for potential future use - not currently needed due to YUI delegation in initializer()
+            /*if (!baseselector) {
                 var baseselector = CSS.PAGECONTENT;
             }
 
-            Y.all(baseselector).each(this._setup_for_section, this);
+            Y.all(baseselector).each(this._setup_for_section, this);*/
         },
         _setup_for_section : function(toolboxtarget) {
-            // Section Highlighting
-            this.replace_button(toolboxtarget, CSS.RIGHTSIDE + ' ' + CSS.HIGHLIGHT, this.toggle_highlight);
-
-            // Section Visibility
-            this.replace_button(toolboxtarget, CSS.RIGHTSIDE + ' ' + CSS.SHOWHIDE, this.toggle_hide_section);
+            // Left here for potential future use - not currently needed due to YUI delegation in initializer()
         },
         toggle_hide_section : function(e) {
             // Prevent the default button action
-- 
1.7.9.5


From 65c8ccc02ed4124ce07eefe6d5a1b985e0fad7c3 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Wed, 5 Sep 2012 14:14:39 +1200
Subject: [PATCH 683/903] MDL-34328: block dragdrop - performance rewrite

Use YUI's DragDrop delegates for block dragdrop - one per block region - rather than initialising a Drag object for each individual block.
---
 lib/yui/blocks/blocks.js |   25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/lib/yui/blocks/blocks.js b/lib/yui/blocks/blocks.js
index cec719f..b0835f6 100644
--- a/lib/yui/blocks/blocks.js
+++ b/lib/yui/blocks/blocks.js
@@ -68,23 +68,26 @@ YUI.add('moodle-core-blocks', function(Y) {
                     padding: '40 240 40 240'
                 });
 
+                // Make each div element in the list of blocks draggable
+                var del = new Y.DD.Delegate({
+                    container: blockregionnode,
+                    nodes: '.'+CSS.BLOCK,
+                    target: true,
+                    handles: ['.'+CSS.HEADER],
+                    dragConfig: {groups: this.groups}
+                });
+                del.dd.plug(Y.Plugin.DDProxy, {
+                    // Don't move the node at the end of the drag
+                    moveOnEnd: false
+                });
+                del.dd.plug(Y.Plugin.DDWinScroll);
+
                 var blocklist = blockregionnode.all('.'+CSS.BLOCK);
                 blocklist.each(function(blocknode) {
                     var move = blocknode.one('a.'+CSS.EDITINGMOVE);
                     if (move) {
                         move.remove();
                         blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
-                        // Make each div element in the list of blocks draggable
-                        var dd = new Y.DD.Drag({
-                            node: blocknode,
-                            groups: this.groups,
-                            // Make each div a Drop target too
-                            target: true,
-                            handles: ['.'+CSS.HEADER]
-                        }).plug(Y.Plugin.DDProxy, {
-                            // Don't move the node at the end of the drag
-                            moveOnEnd: false
-                        }).plug(Y.Plugin.DDWinScroll);
                     }
                 }, this);
             }, this);
-- 
1.7.9.5


From 3f6970bf9205f6b058ad9daa9ffae9a2ba70d654 Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Wed, 5 Sep 2012 14:50:40 +1200
Subject: [PATCH 684/903] MDL-34328: block dragdrop - disallow dragging from
 show/hide and dock icons

Tell the YUI drag/drop delegate that the show/hide and dock icons are not valid drag handles.  Otherwise, a drag can be initiated by showing or hiding a block (probably not from docking one, but better safe than sorry).  Not strictly related to MDL-34328, but likely to be encountered whilst testing - and closely related to another patch for MDL-34328.

Note that the "invalid" config option for the delegate takes a string - not an array - but can have multiple selectors separated by commas.
---
 lib/yui/blocks/blocks.js |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/yui/blocks/blocks.js b/lib/yui/blocks/blocks.js
index b0835f6..2147502 100644
--- a/lib/yui/blocks/blocks.js
+++ b/lib/yui/blocks/blocks.js
@@ -74,6 +74,7 @@ YUI.add('moodle-core-blocks', function(Y) {
                     nodes: '.'+CSS.BLOCK,
                     target: true,
                     handles: ['.'+CSS.HEADER],
+                    invalid: '.block-hider-hide, .block-hider-show, .moveto',
                     dragConfig: {groups: this.groups}
                 });
                 del.dd.plug(Y.Plugin.DDProxy, {
-- 
1.7.9.5


From cffbc80ac70501098b0fe82efe182e506f77630d Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Tue, 18 Sep 2012 11:17:28 +0100
Subject: [PATCH 685/903] MDL-34328 Correct usage of e.drop when catching
 missed drag/drop events

---
 lib/yui/dragdrop/dragdrop.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/yui/dragdrop/dragdrop.js b/lib/yui/dragdrop/dragdrop.js
index 6669f37..4abbe55 100644
--- a/lib/yui/dragdrop/dragdrop.js
+++ b/lib/yui/dragdrop/dragdrop.js
@@ -167,11 +167,11 @@ YUI.add('moodle-core-dragdrop', function(Y) {
             // we substitute them for the ease of use. For e.drop we use,
             // this.lastdroptarget (ghost node we use for indicating where to drop)
             e.drag = e.target;
+            e.drop = this.lastdroptarget;
             // Check that drop object belong to correct group
             if (!e.drop || !e.drop.inGroup(this.groups)) {
                 return;
             }
-            e.drop = this.lastdroptarget;
             this.drag_dropmiss(e);
         },
 
-- 
1.7.9.5


From e36ab386423d7b19326391808ceea948154ebeb7 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rexlorenzo@gmail.com>
Date: Sun, 23 Sep 2012 01:14:14 -0700
Subject: [PATCH 686/903] MDL-35587 - Display grouping name for Drag and
 Dropped resources

---
 course/dndupload.js     |   18 ++++++++++++++++++
 course/dnduploadlib.php |    6 ++++++
 2 files changed, 24 insertions(+)

diff --git a/course/dndupload.js b/course/dndupload.js
index 7bfef1d..e410d40 100644
--- a/course/dndupload.js
+++ b/course/dndupload.js
@@ -445,6 +445,7 @@ M.course_dndupload = {
             a: document.createElement('a'),
             icon: document.createElement('img'),
             namespan: document.createElement('span'),
+            groupingspan: document.createElement('span'),
             progressouter: document.createElement('span'),
             progress: document.createElement('span')
         };
@@ -469,6 +470,9 @@ M.course_dndupload = {
 
         resel.div.appendChild(document.createTextNode(' '));
 
+        resel.groupingspan.className = 'groupinglabel';
+        resel.div.appendChild(resel.groupingspan);
+
         resel.progressouter.className = 'dndupload-progress-outer';
         resel.progress.className = 'dndupload-progress-inner';
         resel.progress.innerHTML = '&nbsp;';
@@ -724,6 +728,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+                            
+                            if (result.groupingname) {
+                                resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+                            } else {
+                                resel.div.removeChild(resel.groupingspan);
+                            }
+                            
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
@@ -904,6 +915,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+                            
+                            if (result.groupingname) {
+                                resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+                            } else {
+                                resel.div.removeChild(resel.groupingspan);
+                            }                            
+                            
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
diff --git a/course/dnduploadlib.php b/course/dnduploadlib.php
index 816924b..043b6c7 100644
--- a/course/dnduploadlib.php
+++ b/course/dnduploadlib.php
@@ -667,6 +667,12 @@ class dndupload_ajax_processor {
         $resp->commands = make_editing_buttons($mod, true, true, 0, $mod->sectionnum);
         $resp->onclick = $mod->get_on_click();
 
+        // if using groupings, then display grouping name
+        if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
+            $groupings = groups_get_all_groupings($this->course->id);
+            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);        
+        }
+   
         echo $OUTPUT->header();
         echo json_encode($resp);
         die();
-- 
1.7.9.5


From 2b7024847d8aa1faaeea2746b7157106fb06df63 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Tue, 18 Sep 2012 11:17:18 +0800
Subject: [PATCH 687/903] MDL-35427: Remove resetting of $_POST - use
 $mform->setConstant to force update to rownum
 instead.

Conflicts:

	mod/assign/locallib.php
---
 mod/assign/locallib.php |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index e1e5104..5ca90c2 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -1629,11 +1629,7 @@ class assign {
         if ($rownum == count($useridlist) - 1) {
             $last = true;
         }
-        // the placement of this is important so can pass the list of userids above
-        if ($offset) {
-            $_POST = array();
-        }
-        if(!$userid){
+        if (!$userid) {
             throw new coding_exception('Row is out of bounds for the current grading table: ' . $rownum);
         }
         $user = $DB->get_record('user', array('id' => $userid));
@@ -2941,6 +2937,7 @@ class assign {
         $mform->setType('id', PARAM_INT);
         $mform->addElement('hidden', 'rownum', $rownum);
         $mform->setType('rownum', PARAM_INT);
+        $mform->setConstant('rownum', $rownum);
         $mform->addElement('hidden', 'useridlist', implode(',', $useridlist));
         $mform->setType('useridlist', PARAM_TEXT);
         $mform->addElement('hidden', 'ajax', optional_param('ajax', 0, PARAM_INT));
-- 
1.7.9.5


From 3e8d7ca16e02062d5a4bb04115890531b5469bff Mon Sep 17 00:00:00 2001
From: Ruslan Kabalin <r.kabalin@lancaster.ac.uk>
Date: Fri, 14 Sep 2012 09:33:02 +0100
Subject: [PATCH 688/903] MDL-35442 Add settings and uninstall link for local
 plugins

---
 lib/pluginlib.php |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index 76e50eb..b224d6d 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -2504,3 +2504,22 @@ class plugininfo_report extends plugininfo_base {
         return new moodle_url('/admin/reports.php', array('delete' => $this->name, 'sesskey' => sesskey()));
     }
 }
+
+
+/**
+ * Class for local plugins
+ */
+class plugininfo_local extends plugininfo_base {
+
+    public function get_uninstall_url() {
+        return new moodle_url('/admin/localplugins.php', array('delete' => $this->name, 'sesskey' => sesskey()));
+    }
+
+    public function get_settings_url() {
+        if (file_exists($this->full_path('settings.php'))) {
+            return new moodle_url('/admin/settings.php', array('section' => 'local_' . $this->name));
+        } else {
+            return parent::get_settings_url();
+        }
+    }
+}
-- 
1.7.9.5


From b666bddae27ec46c5ea113c652b08c0d6ed2f188 Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Wed, 19 Sep 2012 12:56:51 +0800
Subject: [PATCH 689/903] MDL-35375: Ensure the assignment grading table is
 always sorted by at least one unique column

Conflicts:

	mod/assign/gradingtable.php
---
 lib/tablelib.php            |   10 +++++++---
 mod/assign/gradingtable.php |   16 +++++++++-------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/lib/tablelib.php b/lib/tablelib.php
index 04daa06..6de22af 100644
--- a/lib/tablelib.php
+++ b/lib/tablelib.php
@@ -451,9 +451,13 @@ class flexible_table {
             $this->sess->sortby = array_slice($this->sess->sortby, 0, $this->maxsortkeys);
         }
 
-        // If we didn't sort just now, then use the default sort order if one is defined and the column exists
-        if (empty($this->sess->sortby) && !empty($this->sort_default_column))  {
-            $this->sess->sortby = array ($this->sort_default_column => ($this->sort_default_order == SORT_DESC ? SORT_DESC : SORT_ASC));
+        // MDL-35375 - If a default order is defined and it is not in the current list of order by columns, add it at the end.
+        // This prevents results from being returned in a random order if the only order by column contains equal values.
+        if (!empty($this->sort_default_column))  {
+            if (!array_key_exists($this->sort_default_column, $this->sess->sortby)) {
+                $defaultsort = array($this->sort_default_column => $this->sort_default_order);
+                $this->sess->sortby = array_merge($this->sess->sortby, $defaultsort);
+            }
         }
 
         $ilast = optional_param($this->request[TABLE_VAR_ILAST], null, PARAM_RAW);
diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index 40bed66..fce13ea 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -118,12 +118,12 @@ class assign_grading_table extends table_sql implements renderable {
         $headers = array();
 
         // Select
-        $columns[] = 'select';
-        $headers[] = get_string('select') . '<div class="selectall"><input type="checkbox" name="selectall" title="' . get_string('selectall') . '"/></div>';
-
-        // Edit links
         if (!$this->is_downloading()) {
-            $columns[] = 'edit';
+            $columns[] = 'select';
+            $headers[] = get_string('select') . '<div class="selectall"><input type="checkbox" name="selectall" title="' . get_string('selectall') . '"/></div>';
+
+            // We have to call this column userid so we can use userid as a default sortable column.
+            $columns[] = 'userid';
             $headers[] = get_string('edit');
         }
 
@@ -187,8 +187,10 @@ class assign_grading_table extends table_sql implements renderable {
         // set the columns
         $this->define_columns($columns);
         $this->define_headers($headers);
+        // We require at least one unique column for the sort.
+        $this->sortable(true, 'userid');
         $this->no_sorting('finalgrade');
-        $this->no_sorting('edit');
+        $this->no_sorting('userid');
         $this->no_sorting('select');
         $this->no_sorting('outcomes');
 
@@ -430,7 +432,7 @@ class assign_grading_table extends table_sql implements renderable {
      * @param stdClass $row
      * @return string
      */
-    function col_edit(stdClass $row) {
+    function col_userid(stdClass $row) {
         $edit = '';
         if ($this->rownum < 0) {
             $this->rownum = $this->currpage * $this->pagesize;
-- 
1.7.9.5


From a1db00dd1aa0a593fe34cfb2a1b341639c49a9c1 Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Thu, 13 Sep 2012 12:30:32 +0800
Subject: [PATCH 690/903] MDL-32184 - Course - Fixing incorrect redirect when
 toggling course edit while inside an activity --
 Patch provided by Kanika Goyal

---
 course/view.php       |    3 +++
 lib/navigationlib.php |    2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/course/view.php b/course/view.php
index cb978d8..d9d0bdd 100644
--- a/course/view.php
+++ b/course/view.php
@@ -20,6 +20,7 @@
     $marker      = optional_param('marker',-1 , PARAM_INT);
     $switchrole  = optional_param('switchrole',-1, PARAM_INT);
     $modchooser  = optional_param('modchooser', -1, PARAM_BOOL);
+    $return      = optional_param('return', 0, PARAM_LOCALURL);
 
     $params = array();
     if (!empty($name)) {
@@ -152,6 +153,8 @@
             // Redirect to site root if Editing is toggled on frontpage
             if ($course->id == SITEID) {
                 redirect($CFG->wwwroot .'/?redirect=0');
+            } else if (!empty($return)) {
+                redirect($CFG->wwwroot . $return);
             } else {
                 redirect($PAGE->url);
             }
diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 84ca77f..d9cd546 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -3563,7 +3563,7 @@ class settings_navigation extends navigation_node {
                 $baseurl->param('sesskey', sesskey());
             } else {
                 // Edit on the main course page.
-                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'sesskey'=>sesskey()));
+                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'return'=>$this->page->url->out_as_local_url(false), 'sesskey'=>sesskey()));
             }
 
             $editurl = clone($baseurl);
-- 
1.7.9.5


From fede879cf238e919776cb351dd0f1b42a8ce1da0 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 13 Sep 2012 16:51:45 +0800
Subject: [PATCH 691/903] MDL-31499 Javascript: Handle invalid window names in
 openpopup

---
 lib/javascript-static.js |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 812fe07..068fb98 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1178,6 +1178,15 @@ function openpopup(event, args) {
         }
     }
 
+    // Cleans window name because IE does not support funky ones.
+    var nameregex = /[^a-z0-9_]/i;
+    if (args.name.match(nameregex)) {
+        args.name = args.name.replace(nameregex, '_');
+        if (M.cfg.developerdebug) {
+            alert('DEVELOPER NOTICE: Invalid \'name\' passed to openpopup()');
+        }
+    }
+
     var fullurl = args.url;
     if (!args.url.match(/https?:\/\//)) {
         fullurl = M.cfg.wwwroot + args.url;
-- 
1.7.9.5


From 6b69bf463a626904a780d390223b3017fb5248dd Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Tue, 25 Sep 2012 09:56:11 +1200
Subject: [PATCH 692/903] MDL-34607 files: post integration version bump

---
 lib/db/upgrade.php |    4 ++--
 version.php        |    2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index 386792c..e617e1b 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -959,14 +959,14 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062501.14);
     }
 
-    if ($oldversion < 2012062502.02) {
+    if ($oldversion < 2012062502.03) {
         // Some folders still have a sortorder set, which is used for main files but is not
         // supported by the folder resource. We reset the value here.
         $sql = 'UPDATE {files} SET sortorder = ? WHERE component = ? AND filearea = ? AND sortorder <> ?';
         $DB->execute($sql, array(0, 'mod_folder', 'content', 0));
 
         // Main savepoint reached.
-        upgrade_main_savepoint(true, 2012062502.02);
+        upgrade_main_savepoint(true, 2012062502.03);
     }
 
     return true;
diff --git a/version.php b/version.php
index 601517c..a3d1c38 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.02;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.03;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 2bb3259fc30bb2333d28f0c52b86a240e1dbcb9d Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Wed, 19 Sep 2012 22:23:33 +0300
Subject: [PATCH 693/903] MDL-35537 - Right align registration text on login
 page, when in RTL mode

---
 theme/base/style/core.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 9661206..ca41690 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -284,6 +284,7 @@ input#id_externalurl {direction:ltr;}
 .loginbox .subcontent {margin:5px;padding:10px;text-align:center;}
 .loginbox .loginpanel .desc {margin:0;padding:0;margin-bottom:5px;}
 .loginbox .signuppanel .subcontent {text-align:left;}
+.dir-rtl .loginbox .signuppanel .subcontent {text-align: right;}
 .loginbox .loginsub {margin-left:0;margin-right:0;}
 .loginbox .guestsub,
 .loginbox .forgotsub,
-- 
1.7.9.5


From a2b837e5becbf18cca12dc4c4fbb719e1b3a10f8 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 22 Sep 2012 17:19:18 +0300
Subject: [PATCH 694/903] MDL-35576 - Right padding is missing on Date
 field/element, when in RTL mode (minor fix)

---
 theme/base/style/core.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index ca41690..e930e07 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -211,6 +211,7 @@ a.skip:active {position: static;display: block;}
 .mform .fitem .fitemtitle div {display: inline;}
 .mform .fitem .felement {border-width: 0;width:80%;margin-left:16%;}
 .mform .fitem fieldset.felement {margin-left:15%;padding-left:1%;margin-bottom:0}
+.dir-rtl .mform .fitem fieldset.felement {padding-right: 1%;margin-right: 15%;}
 .mform .error,
 .mform .required {color:#A00;}
 .mform .required .fgroup span label {color:#000;}
-- 
1.7.9.5


From ff61f14c0454f1a7e05ecd47f7f74d5528fcca31 Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Wed, 12 Sep 2012 14:19:32 +0800
Subject: [PATCH 695/903] MDL-35252: Fix a bug that creates unneccessary rows
 in grade_grades table when unchecking 'overridden'
 check box in gradebook update

---
 mod/assign/locallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index d248681..8ba72d4 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -3380,7 +3380,7 @@ class assign {
         $graderesults = $DB->get_recordset_sql('SELECT u.id as userid, s.timemodified as datesubmitted, g.grade as rawgrade, g.timemodified as dategraded, g.grader as usermodified
                             FROM {user} u
                             LEFT JOIN {assign_submission} s ON u.id = s.userid and s.assignment = ?
-                            LEFT JOIN {assign_grades} g ON u.id = g.userid and g.assignment = ?
+                            JOIN {assign_grades} g ON u.id = g.userid and g.assignment = ?
                             ' . $where, array($assignmentid, $assignmentid, $userid));
 
 
-- 
1.7.9.5


From 792a3c4ea91bc96542606e74e36c671709621a19 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Wed, 26 Sep 2012 08:23:55 +1200
Subject: [PATCH 696/903] MDL-31976 course: Better alt for edit section icon

---
 course/format/renderer.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index 26f7824..53891bc 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -169,7 +169,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
             $url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
             $o.= html_writer::link($url,
                 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'),
-                    'class' => 'iconsmall edit', 'alt' => get_string('editsummary'))),
+                    'class' => 'iconsmall edit', 'alt' => get_string('edit'))),
                 array('title' => get_string('editsummary')));
         }
         $o.= html_writer::end_tag('div');
-- 
1.7.9.5


From f0f3338000d29837203863a0d965671de7481fe1 Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Wed, 26 Sep 2012 10:17:21 +0800
Subject: [PATCH 697/903] MDL-34476 - Blocks - Fixing context issue

---
 blocks/completionstatus/block_completionstatus.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/blocks/completionstatus/block_completionstatus.php b/blocks/completionstatus/block_completionstatus.php
index 2e00684..5caf743 100644
--- a/blocks/completionstatus/block_completionstatus.php
+++ b/blocks/completionstatus/block_completionstatus.php
@@ -51,8 +51,10 @@ class block_completionstatus extends block_base {
         // Create empty content
         $this->content = new stdClass();
 
+        $context = get_context_instance(CONTEXT_COURSE, $course->id);
+
         // Can edit settings?
-        $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id));
+        $can_edit = has_capability('moodle/course:update', $context);
 
         // Get course completion data
         $info = new completion_info($course);
-- 
1.7.9.5


From 583c0cf67fd43967fa4b0e2d0033581a3175a930 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 13 Sep 2012 11:00:34 +0800
Subject: [PATCH 698/903] MDL-35276 fix redirect to course/section pages

---
 course/format/renderer.php |   25 ++++++++++++-----------
 course/lib.php             |   44 +++++++++++++++++++++++++++++++---------
 course/mod.php             |   48 +++++++++++++-------------------------------
 course/modduplicate.php    |   13 ++++++------
 course/modedit.php         |    6 +++---
 lib/navigationlib.php      |    4 +---
 6 files changed, 72 insertions(+), 68 deletions(-)

diff --git a/course/format/renderer.php b/course/format/renderer.php
index c758cac..4bb5a3a 100644
--- a/course/format/renderer.php
+++ b/course/format/renderer.php
@@ -65,8 +65,9 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      */
     public function section_title($section, $course) {
         $title = get_section_name($course, $section);
-        if ($section->section != 0 && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
-            $title = html_writer::link(course_get_url($course, $section->section), $title);
+        $url = course_get_url($course, $section->section, array('navigation' => true));
+        if ($url) {
+            $title = html_writer::link($url, $title);
         }
         return $title;
     }
@@ -125,7 +126,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param int $sectionreturn The section to return to after an action
      * @return string HTML to output.
      */
-    protected function section_header($section, $course, $onsectionpage, $sectionreturn=0) {
+    protected function section_header($section, $course, $onsectionpage, $sectionreturn=null) {
         global $PAGE;
 
         $o = '';
@@ -413,7 +414,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param int $sectionno The section number in the coruse which is being dsiplayed
      * @return string HTML to output.
      */
-    protected function course_activity_clipboard($course, $sectionno = 0) {
+    protected function course_activity_clipboard($course, $sectionno = null) {
         global $USER;
 
         $o = '';
@@ -642,7 +643,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         echo $this->output->heading($this->page_title(), 2, 'accesshide');
 
         // Copy activity clipboard..
-        echo $this->course_activity_clipboard($course);
+        echo $this->course_activity_clipboard($course, 0);
 
         // Now the list of sections..
         echo $this->start_section_list();
@@ -651,10 +652,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         unset($sections[0]);
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
-            echo $this->section_header($thissection, $course, false);
-            print_section($course, $thissection, $mods, $modnamesused, true);
+            echo $this->section_header($thissection, $course, false, 0);
+            print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, 0);
             if ($PAGE->user_is_editing()) {
-                print_section_add_menus($course, 0, $modnames);
+                print_section_add_menus($course, 0, $modnames, false, false, 0);
             }
             echo $this->section_footer();
         }
@@ -693,11 +694,11 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                 // Display section summary only.
                 echo $this->section_summary($thissection, $course, $mods);
             } else {
-                echo $this->section_header($thissection, $course, false);
+                echo $this->section_header($thissection, $course, false, 0);
                 if ($thissection->uservisible) {
-                    print_section($course, $thissection, $mods, $modnamesused);
+                    print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, 0);
                     if ($PAGE->user_is_editing()) {
-                        print_section_add_menus($course, $section, $modnames);
+                        print_section_add_menus($course, $section, $modnames, false, false, 0);
                     }
                 }
                 echo $this->section_footer();
@@ -714,7 +715,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
                     continue;
                 }
                 echo $this->stealth_section_header($section);
-                print_section($course, $thissection, $mods, $modnamesused);
+                print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, $displaysection);
                 echo $this->stealth_section_footer();
             }
 
diff --git a/course/lib.php b/course/lib.php
index ac7a957..4ae8492 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1384,7 +1384,7 @@ function get_print_section_cm_text(cm_info $cm, $course) {
  * @param int $sectionreturn The section to return to
  * @return void
  */
-function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=0) {
+function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=null) {
     global $CFG, $USER, $DB, $PAGE, $OUTPUT;
 
     static $initialised;
@@ -1765,14 +1765,14 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
  * Prints the menus to add activities and resources.
  *
  * @param stdClass $course The course
- * @param stdClass $section The section
+ * @param int $section relative section number (field course_sections.section)
  * @param array $modnames An array containing the list of modules and their names
  * @param bool $vertical Vertical orientation
  * @param bool $return Return the menus or send them to output
  * @param int $sectionreturn The section to link back to
  * @return void|string depending on $return
  */
-function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=0) {
+function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=null) {
     global $CFG, $OUTPUT;
 
     // check to see if user can add menus
@@ -1781,7 +1781,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
     }
 
     // Retrieve all modules with associated metadata
-    $modules = get_module_metadata($course, $modnames);
+    $modules = get_module_metadata($course, $modnames, $sectionreturn);
 
     // We'll sort resources and activities into two lists
     $resources = array();
@@ -1894,7 +1894,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
  * @return array A list of stdClass objects containing metadata about each
  * module
  */
-function get_module_metadata($course, $modnames, $sectionreturn = 0) {
+function get_module_metadata($course, $modnames, $sectionreturn = null) {
     global $CFG, $OUTPUT;
 
     // get_module_metadata will be called once per section on the page and courses may show
@@ -3153,7 +3153,7 @@ function moveto_module($mod, $section, $beforemod=NULL) {
  * @param int $section The section to link back to
  * @return string XHTML for the editing buttons
  */
-function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $moveselect = true, $indent=-1, $section=-1) {
+function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $moveselect = true, $indent=-1, $section=null) {
     global $CFG, $OUTPUT, $COURSE;
 
     static $str;
@@ -3195,7 +3195,7 @@ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $movesele
 
     $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
 
-    if ($section >= 0) {
+    if ($section !== null) {
         $baseurl->param('sr', $section);
     }
     $actions = array();
@@ -4589,15 +4589,39 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
  *
  * @param stdClass $course The course to get the section name for
  * @param int $sectionno The section number to return a link to
+ *     if omitted the course view page is returned
+ * @param array $options options for view URL. At the moment core uses:
+ *     'navigation' (bool) if true and section has no separate page, the function returns null
+ *     'sr' (int) used by multipage formats to specify to which section to return
  * @return moodle_url The url of course
  */
-function course_get_url($course, $sectionno = null) {
+function course_get_url($course, $sectionno = null, $options = array()) {
+    if ($course->id == SITEID) {
+        return new moodle_url('/');
+    }
     $url = new moodle_url('/course/view.php', array('id' => $course->id));
 
-    if (!is_null($sectionno)) {
-        if ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+    $sr = null;
+    if (array_key_exists('sr', $options)) {
+        $sr = $options['sr'];
+    }
+    if ($sectionno !== null) {
+        if ($sr !== null) {
+            if ($sr) {
+                $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE;
+                $sectionno = $sr;
+            } else {
+                $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE;
+            }
+        } else {
+            $usercoursedisplay = $course->coursedisplay;
+        }
+        if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) {
             $url->param('section', $sectionno);
         } else {
+            if (!empty($options['navigation'])) {
+                return null;
+            }
             $url->set_anchor('section-'.$sectionno);
         }
     }
diff --git a/course/mod.php b/course/mod.php
index 181c6c9..beb665c 100644
--- a/course/mod.php
+++ b/course/mod.php
@@ -26,7 +26,7 @@
 require("../config.php");
 require_once("lib.php");
 
-$sectionreturn = optional_param('sr', 0, PARAM_INT);
+$sectionreturn = optional_param('sr', null, PARAM_INT);
 $add           = optional_param('add', '', PARAM_ALPHA);
 $type          = optional_param('type', '', PARAM_ALPHA);
 $indent        = optional_param('indent', 0, PARAM_INT);
@@ -50,9 +50,7 @@ foreach (compact('indent','update','hide','show','copy','moveto','movetosection'
         $url->param($key, $value);
     }
 }
-if ($sectionreturn) {
-    $url->param('sr', $sectionreturn);
-}
+$url->param('sr', $sectionreturn);
 if ($add !== '') {
     $url->param('add', $add);
 }
@@ -109,7 +107,7 @@ if (!empty($add)) {
                 get_string('continue'),
                 'post'),
             new single_button(
-                course_get_url($course, $sectionreturn),
+                course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)),
                 get_string('cancel'),
                 'get')
         );
@@ -126,7 +124,7 @@ if (!empty($add)) {
     $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
     require_capability('moodle/course:manageactivities', $modcontext);
 
-    $return = course_get_url($course, $sectionreturn);
+    $return = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
 
     if (!$confirm or !confirm_sesskey()) {
         $fullmodulename = get_string('modulename', $cm->modname);
@@ -234,11 +232,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
 
     rebuild_course_cache($section->course);
 
-    if (SITEID == $section->course) {
-        redirect($CFG->wwwroot);
-    } else {
-        redirect(course_get_url($course, $sectionreturn));
-    }
+    redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
 
 } else if (!empty($indent) and confirm_sesskey()) {
     $id = required_param('id', PARAM_INT);
@@ -261,11 +255,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
 
     rebuild_course_cache($cm->course);
 
-    if (SITEID == $cm->course) {
-        redirect($CFG->wwwroot);
-    } else {
-        redirect(course_get_url($course, $sectionreturn));
-    }
+    redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
 
 } else if (!empty($hide) and confirm_sesskey()) {
     $cm     = get_coursemodule_from_id('', $hide, 0, true, MUST_EXIST);
@@ -280,11 +270,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
 
     rebuild_course_cache($cm->course);
 
-    if (SITEID == $cm->course) {
-        redirect($CFG->wwwroot);
-    } else {
-        redirect(course_get_url($course, $sectionreturn));
-    }
+    redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
 
 } else if (!empty($show) and confirm_sesskey()) {
     $cm     = get_coursemodule_from_id('', $show, 0, true, MUST_EXIST);
@@ -304,11 +290,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
         rebuild_course_cache($cm->course);
     }
 
-    if (SITEID == $cm->course) {
-        redirect($CFG->wwwroot);
-    } else {
-        redirect(course_get_url($course, $sectionreturn));
-    }
+    redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
 
 } else if ($groupmode > -1 and confirm_sesskey()) {
     $id = required_param('id', PARAM_INT);
@@ -325,11 +307,7 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
 
     rebuild_course_cache($cm->course);
 
-    if (SITEID == $cm->course) {
-        redirect($CFG->wwwroot);
-    } else {
-        redirect(course_get_url($course, $sectionreturn));
-    }
+    redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
 
 } else if (!empty($copy) and confirm_sesskey()) { // value = course module
     $cm     = get_coursemodule_from_id('', $copy, 0, true, MUST_EXIST);
@@ -347,18 +325,20 @@ if ((!empty($movetosection) or !empty($moveto)) and confirm_sesskey()) {
     $USER->activitycopyname          = $cm->name;
     $USER->activitycopysectionreturn = $sectionreturn;
 
-    redirect(course_get_url($course, $sectionreturn));
+    redirect(course_get_url($course, $section->section, array('sr' => $sectionreturn)));
 
 } else if (!empty($cancelcopy) and confirm_sesskey()) { // value = course module
 
     $courseid = $USER->activitycopycourse;
     $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
 
+    $cm     = get_coursemodule_from_id('', $USER->activitycopy, 0, true, IGNORE_MISSING);
+    $sectionreturn = $USER->activitycopysectionreturn;
     unset($USER->activitycopy);
     unset($USER->activitycopycourse);
     unset($USER->activitycopyname);
-
-    redirect(course_get_url($course, $sectionreturn));
+    unset($USER->activitycopysectionreturn);
+    redirect(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
 } else {
     print_error('unknowaction');
 }
diff --git a/course/modduplicate.php b/course/modduplicate.php
index 30c9aaf..2f51ff9 100644
--- a/course/modduplicate.php
+++ b/course/modduplicate.php
@@ -34,7 +34,7 @@ require_once($CFG->libdir . '/filelib.php');
 
 $cmid           = required_param('cmid', PARAM_INT);
 $courseid       = required_param('course', PARAM_INT);
-$sectionreturn  = optional_param('sr', 0, PARAM_INT);
+$sectionreturn  = optional_param('sr', null, PARAM_INT);
 
 $course     = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
 $cm         = get_coursemodule_from_id('', $cmid, $course->id, true, MUST_EXIST);
@@ -61,8 +61,8 @@ $a->modtype = get_string('modulename', $cm->modname);
 $a->modname = format_string($cm->name);
 
 if (!plugin_supports('mod', $cm->modname, FEATURE_BACKUP_MOODLE2)) {
-    $url = new moodle_url('/course/view.php#section-' . $cm->sectionnum, array('id' => $course->id));
-    print_error('duplicatenosupport', 'core', $url, $a);
+    $url = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
+    print_error('duplicatenosupport', 'error', $url, $a);
 }
 
 // backup the activity
@@ -91,7 +91,8 @@ if (!$rc->execute_precheck()) {
 
         echo $output->header();
         echo $output->precheck_notices($precheckresults);
-        echo $output->continue_button(new moodle_url('/course/view.php', array('id' => $course->id)));
+        $url = course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn));
+        echo $output->continue_button($url);
         echo $output->footer();
         die();
     }
@@ -137,14 +138,14 @@ if ($newcmid) {
             get_string('duplicatecontedit'),
             'get'),
         new single_button(
-            course_get_url($course, $sectionreturn),
+            course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)),
             get_string('duplicatecontcourse'),
             'get')
     );
 
 } else {
     echo $output->notification(get_string('duplicatesuccess', 'core', $a), 'notifysuccess');
-    echo $output->continue_button(course_get_url($course, $sectionreturn));
+    echo $output->continue_button(course_get_url($course, $cm->sectionnum, array('sr' => $sectionreturn)));
 }
 
 echo $output->footer();
diff --git a/course/modedit.php b/course/modedit.php
index ff98613..7aa8667 100644
--- a/course/modedit.php
+++ b/course/modedit.php
@@ -35,7 +35,7 @@ $add    = optional_param('add', '', PARAM_ALPHA);     // module name
 $update = optional_param('update', 0, PARAM_INT);
 $return = optional_param('return', 0, PARAM_BOOL);    //return to course/view.php if false or mod/modname/view.php if true
 $type   = optional_param('type', '', PARAM_ALPHANUM); //TODO: hopefully will be removed in 2.0
-$sectionreturn = optional_param('sr', 0, PARAM_INT);
+$sectionreturn = optional_param('sr', null, PARAM_INT);
 
 $url = new moodle_url('/course/modedit.php');
 $url->param('sr', $sectionreturn);
@@ -264,7 +264,7 @@ if ($mform->is_cancelled()) {
     if ($return && !empty($cm->id)) {
         redirect("$CFG->wwwroot/mod/$module->name/view.php?id=$cm->id");
     } else {
-        redirect(course_get_url($course, $sectionreturn));
+        redirect(course_get_url($course, $cw->section, array('sr' => $sectionreturn)));
     }
 } else if ($fromform = $mform->get_data()) {
     if (empty($fromform->coursemodule)) {
@@ -633,7 +633,7 @@ if ($mform->is_cancelled()) {
             redirect($gradingman->get_management_url($returnurl));
         }
     } else {
-        redirect(course_get_url($course, $sectionreturn));
+        redirect(course_get_url($course, $cw->section, array('sr' => $sectionreturn)));
     }
     exit;
 
diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index 84ca77f..b24c112 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -2026,9 +2026,7 @@ class global_navigation extends navigation_node {
                     // pre 2.3 style format url
                     $url = $urlfunction($course->id, $section->section);
                 }else{
-                    if ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
-                        $url = course_get_url($course, $section->section);
-                    }
+                    $url = course_get_url($course, $section->section, array('navigation' => true));
                 }
                 $sectionnode = $coursenode->add($sectionname, $url, navigation_node::TYPE_SECTION, null, $section->id);
                 $sectionnode->nodetype = navigation_node::NODETYPE_BRANCH;
-- 
1.7.9.5


From 3f676aa5bdbd3b6e5edbb09dfe66c8217b232169 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Wed, 26 Sep 2012 14:24:29 +0800
Subject: [PATCH 699/903] MDL-35644 user_get_details: admin should be able to
 see description

---
 user/lib.php |   16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/user/lib.php b/user/lib.php
index 0da89c7..2f8bc60 100644
--- a/user/lib.php
+++ b/user/lib.php
@@ -324,15 +324,13 @@ function user_get_user_details($user, $course = null, array $userfields = array(
         $userdetails['phone2'] = $user->phone2;
     }
 
-    if (isset($user->description) && (!isset($hiddenfields['description']) or $isadmin)) {
-        if (!$cannotviewdescription) {
-
-            if (in_array('description', $userfields)) {
-                // Always return the descriptionformat if description is requested.
-                list($userdetails['description'], $userdetails['descriptionformat']) =
-                        external_format_text($user->description, $user->descriptionformat,
-                                $usercontext->id, 'user', 'profile', null);
-            }
+    if (isset($user->description) &&
+        ((!isset($hiddenfields['description']) && !$cannotviewdescription) or $isadmin)) {
+        if (in_array('description', $userfields)) {
+            // Always return the descriptionformat if description is requested.
+            list($userdetails['description'], $userdetails['descriptionformat']) =
+                    external_format_text($user->description, $user->descriptionformat,
+                            $usercontext->id, 'user', 'profile', null);
         }
     }
 
-- 
1.7.9.5


From 25878bcd22bed18c9bc9e7904503eb4b0df7d7ca Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Wed, 26 Sep 2012 15:16:24 +0800
Subject: [PATCH 700/903] MDL-35276 fix redirect to course/section pages

---
 course/modduplicate.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/modduplicate.php b/course/modduplicate.php
index 2f51ff9..e72f0d0 100644
--- a/course/modduplicate.php
+++ b/course/modduplicate.php
@@ -134,7 +134,7 @@ if ($newcmid) {
     echo $output->confirm(
         get_string('duplicatesuccess', 'core', $a),
         new single_button(
-            new moodle_url('/course/modedit.php', array('update' => $newcmid)),
+            new moodle_url('/course/modedit.php', array('update' => $newcmid, 'sr' => $sectionreturn)),
             get_string('duplicatecontedit'),
             'get'),
         new single_button(
-- 
1.7.9.5


From 3147b59c8af3a18ae4f0c0476279e519f3b3ad87 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 22 Sep 2012 17:58:20 +0300
Subject: [PATCH 701/903] MDL-35578 - Left justify LTR Form input fields
 (email, idnumber, url, phone...), when in RTL mode

---
 theme/base/style/core.css |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index e930e07..5c0e78e 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -666,6 +666,11 @@ body.tag .managelink {padding: 5px;}
 
 .dir-rtl .felement.feditor select {margin-right:18.75%;margin-left:auto;}
 .dir-rtl .mform .fitem .felement {margin-right: 16%;margin-left:auto;text-align: right;}
+.dir-rtl .mform .fitem .felement input[name=email],
+.dir-rtl .mform .fitem .felement input[name=url],
+.dir-rtl .mform .fitem .felement input[name=idnumber],
+.dir-rtl .mform .fitem .felement input[name=phone1],
+.dir-rtl .mform .fitem .felement input[name=phone2] {text-align: left; direction: ltr;}
 
 /* Audio player size in 'block' mode (can only change width, height is hardcoded in JS) */
 .resourcecontent .mediaplugin_mp3 object {height:25px; width: 600px}
-- 
1.7.9.5


From 249d0730584aafc74ff1f49a0c50581de857ed81 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 26 Sep 2012 19:48:06 +0200
Subject: [PATCH 702/903] MDL-35578 - Also justify email2, used in signup

---
 theme/base/style/core.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 5c0e78e..6a7abea 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -667,6 +667,7 @@ body.tag .managelink {padding: 5px;}
 .dir-rtl .felement.feditor select {margin-right:18.75%;margin-left:auto;}
 .dir-rtl .mform .fitem .felement {margin-right: 16%;margin-left:auto;text-align: right;}
 .dir-rtl .mform .fitem .felement input[name=email],
+.dir-rtl .mform .fitem .felement input[name=email2],
 .dir-rtl .mform .fitem .felement input[name=url],
 .dir-rtl .mform .fitem .felement input[name=idnumber],
 .dir-rtl .mform .fitem .felement input[name=phone1],
-- 
1.7.9.5


From 68164ad218c54fedacca860a62b4f3933a1a12d7 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Wed, 19 Sep 2012 22:43:45 +0300
Subject: [PATCH 703/903] MDL-35527 - Left justify CLOSE button on modal
 dialog boxes, when in RTL mode

---
 theme/base/style/core.css |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 6a7abea..3aec3d8 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -863,6 +863,10 @@ sup {vertical-align: super;}
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#CCCCCC')!important;
     filter: dropshadow(color=#FFFFFF, offx=1, offy=1);
 }
+/* Activity Chooser "Close" button */
+.dir-rtl .moodle-dialogue-base .closebutton {float: left;}
+/* Question Bank - Question Chooser "Close" button */
+#page-question-edit.dir-rtl a.container-close {right:auto;left:6px;}
 
 .chooserdialogue .moodle-dialogue-bd {
     font-size: 12px;
-- 
1.7.9.5


From 2a8690dab5e7ae6410145ec37e1a26ef16e6cd32 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 22 Sep 2012 21:42:12 +0300
Subject: [PATCH 704/903] MDL-35246 - Invert all action arrows in Question
 Bank categories management, when in RTL mode

---
 lib/listlib.php |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/lib/listlib.php b/lib/listlib.php
index 7a3979b..9cc815b 100644
--- a/lib/listlib.php
+++ b/lib/listlib.php
@@ -548,6 +548,14 @@ abstract class list_item {
         $strmovedown = get_string('movedown');
         $strmoveleft = get_string('maketoplevelitem', 'question');
 
+        if (right_to_left()) {   // Exchange arrows on RTL
+            $rightarrow = 'left';
+            $leftarrow  = 'right';
+        } else {
+            $rightarrow = 'right';
+            $leftarrow  = 'left';
+        }
+
         if (isset($this->parentlist->parentitem)) {
             $parentitem = $this->parentlist->parentitem;
             if (isset($parentitem->parentlist->parentitem)) {
@@ -556,7 +564,7 @@ abstract class list_item {
                 $action = $strmoveleft;
             }
             $url = new moodle_url($this->parentlist->pageurl, (array('sesskey'=>sesskey(), 'left'=>$this->id)));
-            $this->icons['left'] = $this->image_icon($action, $url, 'left');
+            $this->icons['left'] = $this->image_icon($action, $url, $leftarrow);
         } else {
             $this->icons['left'] =  $this->image_spacer();
         }
@@ -578,7 +586,7 @@ abstract class list_item {
         if (!empty($lastitem)) {
             $makechildof = get_string('makechildof', 'question', $lastitem->name);
             $url = new moodle_url($this->parentlist->pageurl, (array('sesskey'=>sesskey(), 'right'=>$this->id)));
-            $this->icons['right'] = $this->image_icon($makechildof, $url, 'right');
+            $this->icons['right'] = $this->image_icon($makechildof, $url, $rightarrow);
         } else {
             $this->icons['right'] =  $this->image_spacer();
         }
-- 
1.7.9.5


From 20a1f8a9c512e79fe87c9c7723cbbb6efbe64d74 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 22 Sep 2012 21:05:14 +0300
Subject: [PATCH 705/903] MDL-35481 - Invert "search option" listbox "open"
 arrow, when in RTL mode (page: manual user course
 registration ) and Personal Blog page

---
 comment/comment.js                                |    8 +++++++-
 comment/lib.php                                   |    8 +++++++-
 enrol/manual/yui/quickenrolment/quickenrolment.js |   11 +++++++++--
 lib/javascript-static.js                          |   16 ++++++++++++++--
 4 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/comment/comment.js b/comment/comment.js
index a16b83a..f137299 100644
--- a/comment/comment.js
+++ b/comment/comment.js
@@ -361,7 +361,13 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
                 } else {
                     // hide
                     container.setStyle('display', 'none');
-                    img.set('src', M.util.image_url('t/collapsed', 'core'));
+                    var collapsedimage = 't/collapsed'; // ltr mode
+                    if ( Y.one(document.body).hasClass('dir-rtl') ) {
+                        collapsedimage = 't/collapsed_rtl';
+                    } else {
+                        collapsedimage = 't/collapsed';
+                    }
+                    img.set('src', M.util.image_url(collapsedimage, 'core'));
                     if (ta) {
                         ta.set('value','');
                     }
diff --git a/comment/lib.php b/comment/lib.php
index dbf1058..d1b6dd5 100644
--- a/comment/lib.php
+++ b/comment/lib.php
@@ -422,8 +422,14 @@ class comment {
                 if ($this->displaytotalcount) {
                     $countstring = '('.$this->count().')';
                 }
+                $collapsedimage= 't/collapsed';
+                if (right_to_left()) {
+                    $collapsedimage= 't/collapsed_rtl';
+                } else {
+                    $collapsedimage= 't/collapsed';
+                }
                 $html .= html_writer::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid, 'href' => '#'));
-                $html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url('t/collapsed'), 'alt' => $this->linktext, 'title' => $this->linktext));
+                $html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url($collapsedimage), 'alt' => $this->linktext, 'title' => $this->linktext));
                 $html .= html_writer::tag('span', $this->linktext.' '.$countstring, array('id' => 'comment-link-text-'.$this->cid));
                 $html .= html_writer::end_tag('a');
             }
diff --git a/enrol/manual/yui/quickenrolment/quickenrolment.js b/enrol/manual/yui/quickenrolment/quickenrolment.js
index 5f4efe6..c1963aa 100644
--- a/enrol/manual/yui/quickenrolment/quickenrolment.js
+++ b/enrol/manual/yui/quickenrolment/quickenrolment.js
@@ -141,12 +141,19 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
             base.dd.addHandle('.'+CSS.HEADER+' h2');
             base.one('.'+CSS.HEADER+' h2').setStyle('cursor', 'move');
 
-            this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle'));
+            var collapsedimage = 't/collapsed'; // ltr mode
+            if ( Y.one(document.body).hasClass('dir-rtl') ) {
+                collapsedimage = 't/collapsed_rtl';
+            } else {
+                collapsedimage = 't/collapsed';
+            }
+
+            this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url(collapsedimage, 'moodle'));
             this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).on('click', function(){
                 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).toggleClass(CSS.ACTIVE);
                 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).toggleClass(CSS.HIDDEN);
                 if (this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).hasClass(CSS.HIDDEN)) {
-                    this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/collapsed', 'moodle'));
+                    this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url(collapsedimage, 'moodle'));
                 } else {
                     this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url('t/expanded', 'moodle'));
                 }
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 068fb98..24ac3fa 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -103,9 +103,15 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
 
     // Get the height of the div at this point before we shrink it if required
     var height = this.div.get('offsetHeight');
+    var collapsedimage = 't/collapsed'; // ltr mode
+    if ( Y.one(document.body).hasClass('dir-rtl') ) {
+        collapsedimage = 't/collapsed_rtl';
+    } else {
+        collapsedimage = 't/collapsed';
+    }
     if (this.div.hasClass('collapsed')) {
         // Add the correct image and record the YUI node created in the process
-        this.icon = Y.Node.create('<img src="'+M.util.image_url('t/collapsed', 'moodle')+'" alt="" />');
+        this.icon = Y.Node.create('<img src="'+M.util.image_url(collapsedimage, 'moodle')+'" alt="" />');
         // Shrink the div as it is collapsed by default
         this.div.setStyle('height', caption.get('offsetHeight')+'px');
     } else {
@@ -126,8 +132,14 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
     // Handler for the animation finishing.
     animation.on('end', function() {
         this.div.toggleClass('collapsed');
+        var collapsedimage = 't/collapsed'; // ltr mode
+        if ( Y.one(document.body).hasClass('dir-rtl') ) {
+            collapsedimage = 't/collapsed_rtl';
+            } else {
+            collapsedimage = 't/collapsed';
+            }
         if (this.div.hasClass('collapsed')) {
-            this.icon.set('src', M.util.image_url('t/collapsed', 'moodle'));
+            this.icon.set('src', M.util.image_url(collapsedimage, 'moodle'));
         } else {
             this.icon.set('src', M.util.image_url('t/expanded', 'moodle'));
         }
-- 
1.7.9.5


From 66652c60c080eea9bac0e25785df9a23186a8e54 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 27 Sep 2012 00:34:44 +0000
Subject: [PATCH 706/903] Automatically generated installer lang files

---
 install/lang/no/install.php |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/install/lang/no/install.php b/install/lang/no/install.php
index 795f77d..bd29cd8 100644
--- a/install/lang/no/install.php
+++ b/install/lang/no/install.php
@@ -34,12 +34,14 @@ $string['admindirname'] = 'Adminmappe';
 $string['availablelangs'] = 'Tilgjengelige språkpakker';
 $string['chooselanguagehead'] = 'Velg et språk';
 $string['chooselanguagesub'] = 'Velg språk (bare for INSTALLASJONEN). Du vil kunne velge språk for nettsted og bruker på et skjermbilde senere.';
-$string['clialreadyinstalled'] = 'Filen config.php eksisterer allerede, vær vennlig å bruk admin/cli/upgrade.php hvis du vil oppgradere nettstedet ditt.';
+$string['clialreadyconfigured'] = 'Filen config.php finnes allerede. Vennligst bruk admin/cli/install_database.php hvis du vil installere denne portalen.';
+$string['clialreadyinstalled'] = 'Filen config.php eksisterer allerede. Vennligst bruk admin/cli/upgrade.php hvis du vil oppgradere denne portalen.';
 $string['cliinstallheader'] = 'Moodle {$a} kommandolinje installasjonsprogram';
 $string['databasehost'] = 'Databasevert';
 $string['databasename'] = 'Databasenavn';
 $string['databasetypehead'] = 'Velg databasedriver';
 $string['dataroot'] = 'Dataområde';
+$string['datarootpermission'] = 'Tillatelse for datakatalog';
 $string['dbprefix'] = 'Tabellprefix';
 $string['dirroot'] = 'Moodles filområde';
 $string['environmenthead'] = 'Sjekker "omgivelsene" dine...';
@@ -76,11 +78,10 @@ $string['phpversionhelp'] = '<p>Moodle trenger en PHP versjon minst 4.3.0 eller
 <Du kjører nå versjon {$a}</p>
 <p>Du må oppgradere PHP eller flytte til en server med en nyere versjon av PHP!<br /> (I forhold til 5.0.x kan du også nedgradere til versjon 4.4.x)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
-$string['welcomep20'] = 'Du ser denne siden fordi du nå med hell har installert og kjørt <strong>{$a->packname} {$a->packversion}</strong>pakke på datamaskinen din. Gratulerer!';
+$string['welcomep20'] = 'Du ser denne siden fordi du nå med hell har installert og kjørt <strong>{$a->packname} {$a->packversion}</strong>pakken på datamaskinen din. Gratulerer!';
 $string['welcomep30'] = 'Denne versjonen av <strong>{$a->installername}</strong> inkluderer programmer for å lage et miljø som <strong>Moodle</strong> jobber i, nemlig:';
 $string['welcomep40'] = 'Denne pakken inkluderer også  <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
-$string['welcomep50'] = 'Bruken av alle applikasjoner i denne pakken er administrert av egne lisenser. Hele <strong>{$a->installername}</strong> pakken er <a href="http://www.opensource.org/docs/definition_plain.html">
-åpen kildekode</a> og er distribuert under  <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> lisensen.';
-$string['welcomep60'] = 'De følgende sidene vil vise deg gjennom noen enkle steg for å konfigurere og sette opp <strong>Moodle</strong> på datamaskinen din. Du kan akseptere standard innstillinger, eller, hvis du vil, justere dem etter egne behov.';
+$string['welcomep50'] = 'Bruken av alle applikasjoner i denne pakken er styrt av egne lisenser. Hele <strong>{$a->installername}</strong> pakken er <a href="http://www.opensource.org/docs/definition_plain.html">åpen kildekode</a> og er distribuert under  <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> lisensen.';
+$string['welcomep60'] = 'De følgende sidene vil vise deg gjennom noen enkle steg for å konfigurere og sette opp <strong>Moodle</strong> på datamaskinen din. Du kan akseptere standardinnstillingene, eller, hvis du vil, justere dem etter egne behov.';
 $string['welcomep70'] = 'Klikk på "Neste" knappen under for å fortsette med <strong>Moodle</strong>-installasjonen';
 $string['wwwroot'] = 'Web addresse';
-- 
1.7.9.5


From 12f9c36df8ca11a5aa53672442b71cc76c47814d Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 27 Sep 2012 11:32:02 +0800
Subject: [PATCH 707/903] Revert "MDL-32184 - Course - Fixing incorrect
 redirect when toggling course edit while inside an
 activity -- Patch provided by Kanika Goyal"

This reverts commit a1db00dd1aa0a593fe34cfb2a1b341639c49a9c1.
---
 course/view.php       |    3 ---
 lib/navigationlib.php |    2 +-
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/course/view.php b/course/view.php
index d9d0bdd..cb978d8 100644
--- a/course/view.php
+++ b/course/view.php
@@ -20,7 +20,6 @@
     $marker      = optional_param('marker',-1 , PARAM_INT);
     $switchrole  = optional_param('switchrole',-1, PARAM_INT);
     $modchooser  = optional_param('modchooser', -1, PARAM_BOOL);
-    $return      = optional_param('return', 0, PARAM_LOCALURL);
 
     $params = array();
     if (!empty($name)) {
@@ -153,8 +152,6 @@
             // Redirect to site root if Editing is toggled on frontpage
             if ($course->id == SITEID) {
                 redirect($CFG->wwwroot .'/?redirect=0');
-            } else if (!empty($return)) {
-                redirect($CFG->wwwroot . $return);
             } else {
                 redirect($PAGE->url);
             }
diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index dcf466a..b24c112 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -3561,7 +3561,7 @@ class settings_navigation extends navigation_node {
                 $baseurl->param('sesskey', sesskey());
             } else {
                 // Edit on the main course page.
-                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'return'=>$this->page->url->out_as_local_url(false), 'sesskey'=>sesskey()));
+                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'sesskey'=>sesskey()));
             }
 
             $editurl = clone($baseurl);
-- 
1.7.9.5


From 40755f958417db53b662217b42502281fd5ea5b1 Mon Sep 17 00:00:00 2001
From: Mark Nelson <markn@moodle.com>
Date: Thu, 27 Sep 2012 11:58:47 +0800
Subject: [PATCH 708/903] MDL-35637 group: Fix form submission error that
 occurs when GD version is not set.

---
 group/lib.php |   21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/group/lib.php b/group/lib.php
index 8addc93..024e81b 100644
--- a/group/lib.php
+++ b/group/lib.php
@@ -239,17 +239,18 @@ function groups_update_group_icon($group, $data, $editform) {
     $context = get_context_instance(CONTEXT_COURSE, $group->courseid, MUST_EXIST);
 
     //TODO: it would make sense to allow picture deleting too (skodak)
-
-    if ($iconfile = $editform->save_temp_file('imagefile')) {
-        if (process_new_icon($context, 'group', 'icon', $group->id, $iconfile)) {
-            $DB->set_field('groups', 'picture', 1, array('id'=>$group->id));
-            $group->picture = 1;
-        } else {
-            $fs->delete_area_files($context->id, 'group', 'icon', $group->id);
-            $DB->set_field('groups', 'picture', 0, array('id'=>$group->id));
-            $group->picture = 0;
+    if (!empty($CFG->gdversion)) {
+        if ($iconfile = $editform->save_temp_file('imagefile')) {
+            if (process_new_icon($context, 'group', 'icon', $group->id, $iconfile)) {
+                $DB->set_field('groups', 'picture', 1, array('id'=>$group->id));
+                $group->picture = 1;
+            } else {
+                $fs->delete_area_files($context->id, 'group', 'icon', $group->id);
+                $DB->set_field('groups', 'picture', 0, array('id'=>$group->id));
+                $group->picture = 0;
+            }
+            @unlink($iconfile);
         }
-        @unlink($iconfile);
     }
 }
 
-- 
1.7.9.5


From 786b83165334d3d8f0574ca006ebd9e9bc11fe59 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Wed, 26 Sep 2012 15:20:18 +0800
Subject: [PATCH 709/903] MDL-35198 replace key_exists by array_key_exists

---
 admin/webservice/service_users.php |    2 +-
 blocks/community/forms.php         |    2 +-
 course/externallib.php             |   10 +++++-----
 enrol/externallib.php              |    4 ++--
 enrol/manual/externallib.php       |    2 +-
 lib/adminlib.php                   |    2 +-
 lib/upgradelib.php                 |    4 ++--
 webservice/lib.php                 |    2 +-
 8 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/admin/webservice/service_users.php b/admin/webservice/service_users.php
index 12db2b0..ad67c668 100644
--- a/admin/webservice/service_users.php
+++ b/admin/webservice/service_users.php
@@ -97,7 +97,7 @@ $usersmissingcaps = $webservicemanager->get_missing_capabilities_by_users($allow
 
 //add the missing capabilities to the allowed users object to be displayed by renderer
 foreach ($allowedusers as &$alloweduser) {
-    if (!is_siteadmin($alloweduser->id) and key_exists($alloweduser->id, $usersmissingcaps)) {
+    if (!is_siteadmin($alloweduser->id) and array_key_exists($alloweduser->id, $usersmissingcaps)) {
         $alloweduser->missingcapabilities = implode(', ', $usersmissingcaps[$alloweduser->id]);
     }
 }
diff --git a/blocks/community/forms.php b/blocks/community/forms.php
index fafab8a..5026d5b 100644
--- a/blocks/community/forms.php
+++ b/blocks/community/forms.php
@@ -140,7 +140,7 @@ class community_hub_search_form extends moodleform {
             $options = array();
             $firsthub = false;
             foreach ($hubs as $hub) {
-                if (key_exists('id', $hub)) {
+                if (array_key_exists('id', $hub)) {
                     $params = array('hubid' => $hub['id'],
                         'filetype' => HUB_HUBSCREENSHOT_FILE_TYPE);
                     $imgurl = new moodle_url(HUB_HUBDIRECTORYURL .
diff --git a/course/externallib.php b/course/externallib.php
index b18c0a4..88fd0fa 100644
--- a/course/externallib.php
+++ b/course/externallib.php
@@ -285,7 +285,7 @@ class core_course_external extends external_api {
                         array('options' => $options));
 
         //retrieve courses
-        if (!key_exists('ids', $params['options'])
+        if (!array_key_exists('ids', $params['options'])
                 or empty($params['options']['ids'])) {
             $courses = $DB->get_records('course');
         } else {
@@ -523,12 +523,12 @@ class core_course_external extends external_api {
             require_capability('moodle/course:create', $context);
 
             // Make sure lang is valid
-            if (key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
+            if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
                 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
             }
 
             // Make sure theme is valid
-            if (key_exists('forcetheme', $course)) {
+            if (array_key_exists('forcetheme', $course)) {
                 if (!empty($CFG->allowcoursethemes)) {
                     if (empty($availablethemes[$course['forcetheme']])) {
                         throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
@@ -547,10 +547,10 @@ class core_course_external extends external_api {
             //set default value for completion
             $courseconfig = get_config('moodlecourse');
             if (completion_info::is_enabled_for_site()) {
-                if (!key_exists('enablecompletion', $course)) {
+                if (!array_key_exists('enablecompletion', $course)) {
                     $course['enablecompletion'] = $courseconfig->enablecompletion;
                 }
-                if (!key_exists('completionstartonenrol', $course)) {
+                if (!array_key_exists('completionstartonenrol', $course)) {
                     $course['completionstartonenrol'] = $courseconfig->completionstartonenrol;
                 }
             } else {
diff --git a/enrol/externallib.php b/enrol/externallib.php
index 7d2fb5a..7e8dd4c 100644
--- a/enrol/externallib.php
+++ b/enrol/externallib.php
@@ -388,7 +388,7 @@ class core_role_external extends external_api {
             // throw an exception if user is not able to assign the role in this context
             $roles = get_assignable_roles($context, ROLENAME_SHORT);
 
-            if (!key_exists($assignment['roleid'], $roles)) {
+            if (!array_key_exists($assignment['roleid'], $roles)) {
                 throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']);
             }
 
@@ -451,7 +451,7 @@ class core_role_external extends external_api {
 
             // throw an exception if user is not able to unassign the role in this context
             $roles = get_assignable_roles($context, ROLENAME_SHORT);
-            if (!key_exists($unassignment['roleid'], $roles)) {
+            if (!array_key_exists($unassignment['roleid'], $roles)) {
                 throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']);
             }
 
diff --git a/enrol/manual/externallib.php b/enrol/manual/externallib.php
index 44d90ac..81907a8 100644
--- a/enrol/manual/externallib.php
+++ b/enrol/manual/externallib.php
@@ -101,7 +101,7 @@ class enrol_manual_external extends external_api {
 
             //throw an exception if user is not able to assign the role
             $roles = get_assignable_roles($context);
-            if (!key_exists($enrolment['roleid'], $roles)) {
+            if (!array_key_exists($enrolment['roleid'], $roles)) {
                 $errorparams = new stdClass();
                 $errorparams->roleid = $enrolment['roleid'];
                 $errorparams->courseid = $enrolment['courseid'];
diff --git a/lib/adminlib.php b/lib/adminlib.php
index 2e8121b..c74e557 100644
--- a/lib/adminlib.php
+++ b/lib/adminlib.php
@@ -7561,7 +7561,7 @@ class admin_setting_managewebservicetokens extends admin_setting {
                         array(array('id' => $token->userid)), $token->serviceid);
 
                 if (!is_siteadmin($token->userid) and
-                        key_exists($token->userid, $usermissingcaps)) {
+                        array_key_exists($token->userid, $usermissingcaps)) {
                     $missingcapabilities = implode(', ',
                             $usermissingcaps[$token->userid]);
                     if (!empty($missingcapabilities)) {
diff --git a/lib/upgradelib.php b/lib/upgradelib.php
index c299ffe..cde67d9 100644
--- a/lib/upgradelib.php
+++ b/lib/upgradelib.php
@@ -964,7 +964,7 @@ function external_update_descriptions($component) {
             $dbfunction->classpath = $function['classpath'];
             $update = true;
         }
-        $functioncapabilities = key_exists('capabilities', $function)?$function['capabilities']:'';
+        $functioncapabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
         if ($dbfunction->capabilities != $functioncapabilities) {
             $dbfunction->capabilities = $functioncapabilities;
             $update = true;
@@ -980,7 +980,7 @@ function external_update_descriptions($component) {
         $dbfunction->methodname = $function['methodname'];
         $dbfunction->classpath  = empty($function['classpath']) ? null : $function['classpath'];
         $dbfunction->component  = $component;
-        $dbfunction->capabilities = key_exists('capabilities', $function)?$function['capabilities']:'';
+        $dbfunction->capabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
         $dbfunction->id = $DB->insert_record('external_functions', $dbfunction);
     }
     unset($functions);
diff --git a/webservice/lib.php b/webservice/lib.php
index 5a14d57..326091a 100644
--- a/webservice/lib.php
+++ b/webservice/lib.php
@@ -564,7 +564,7 @@ class webservice {
             //detect the missing capabilities
             foreach ($servicecaps as $functioname => $functioncaps) {
                 foreach ($functioncaps as $functioncap) {
-                    if (!key_exists($functioncap, $usercaps)) {
+                    if (!array_key_exists($functioncap, $usercaps)) {
                         if (!isset($usersmissingcaps[$user->id])
                                 or array_search($functioncap, $usersmissingcaps[$user->id]) === false) {
                             $usersmissingcaps[$user->id][] = $functioncap;
-- 
1.7.9.5


From 9273bd1abb534cbcc02cd5baf1482165fcbae2b5 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 27 Sep 2012 18:51:24 +0800
Subject: [PATCH 710/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index a3d1c38..48fc6b2 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.03;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.04;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20120920)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20120927)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From d205afe662ba306833a525d87714d1994467dba7 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 12 Jul 2012 18:39:01 +0100
Subject: [PATCH 711/903] MDL-34257 quiz 'secure' mode: PAGE initialisation
 order issues.

---
 mod/quiz/attempt.php |    4 ++--
 mod/quiz/review.php  |    3 ++-
 mod/quiz/summary.php |    4 ++--
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php
index 135ae14..1cbda08 100644
--- a/mod/quiz/attempt.php
+++ b/mod/quiz/attempt.php
@@ -76,8 +76,9 @@ if ($attemptobj->is_finished()) {
 
 // Check the access rules.
 $accessmanager = $attemptobj->get_access_manager(time());
-$messages = $accessmanager->prevent_access();
+$accessmanager->setup_attempt_page($PAGE);
 $output = $PAGE->get_renderer('mod_quiz');
+$messages = $accessmanager->prevent_access();
 if (!$attemptobj->is_preview_user() && $messages) {
     print_error('attempterror', 'quiz', $attemptobj->view_url(),
             $output->access_messages($messages));
@@ -120,7 +121,6 @@ $title = get_string('attempt', 'quiz', $attemptobj->get_attempt_number());
 $headtags = $attemptobj->get_html_head_contributions($page);
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
-$accessmanager->setup_attempt_page($PAGE);
 
 if ($attemptobj->is_last_page($page)) {
     $nextpage = -1;
diff --git a/mod/quiz/review.php b/mod/quiz/review.php
index c19afaa..eacc703 100644
--- a/mod/quiz/review.php
+++ b/mod/quiz/review.php
@@ -52,6 +52,8 @@ $attemptobj->check_review_capability();
 
 // Create an object to manage all the other (non-roles) access rules.
 $accessmanager = $attemptobj->get_access_manager(time());
+$accessmanager->setup_attempt_page($PAGE);
+
 $options = $attemptobj->get_display_options(true);
 
 // Check permissions.
@@ -103,7 +105,6 @@ if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
 $headtags = $attemptobj->get_html_head_contributions($page, $showall);
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
-$accessmanager->setup_attempt_page($PAGE);
 
 // Summary table start. ============================================================================
 
diff --git a/mod/quiz/summary.php b/mod/quiz/summary.php
index 303638f..822e307 100644
--- a/mod/quiz/summary.php
+++ b/mod/quiz/summary.php
@@ -52,8 +52,9 @@ if ($attemptobj->is_preview_user()) {
 
 // Check access.
 $accessmanager = $attemptobj->get_access_manager(time());
-$messages = $accessmanager->prevent_access();
+$accessmanager->setup_attempt_page($PAGE);
 $output = $PAGE->get_renderer('mod_quiz');
+$messages = $accessmanager->prevent_access();
 if (!$attemptobj->is_preview_user() && $messages) {
     print_error('attempterror', 'quiz', $attemptobj->view_url(),
             $output->access_messages($messages));
@@ -89,7 +90,6 @@ $PAGE->blocks->add_fake_block($navbc, reset($regions));
 $PAGE->navbar->add(get_string('summaryofattempt', 'quiz'));
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
-$accessmanager->setup_attempt_page($PAGE);
 
 // Display the page.
 echo $output->summary_page($attemptobj, $displayoptions);
-- 
1.7.9.5


From ad1a52e07cd3033ab02f51eafa683376169f4155 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 13 Sep 2012 19:12:45 +0100
Subject: [PATCH 712/903] MDL-35370 cloze qtype: distinguish wrong &
 unanswered subqs

This affects the subquestions that appear as an embedded text input box.

There are three cases:
1. Input for subq left blank
2. Input for subq was wrong, and matched by a * wildcard.
3. Input for subq was wrong, and did not match any answer.

2. and 3. should look identical, apart from any feedback in case 2.

1. is different. The state should be displayed as "Not answered" even
though the mark for this part is still shown as 0.

There are some new unit tests for these cases.

Also, we slighly improve handling of , for decimal point in multianswer,
although there are still issues.

While working on this, I made some minor clean-ups in shortanswer and
numerical qtypes.
---
 question/type/multianswer/renderer.php             |   30 +++++-
 question/type/multianswer/tests/helper.php         |   46 +++++++-
 .../type/multianswer/tests/walkthrough_test.php    |  114 +++++++++++++++++++-
 question/type/numerical/question.php               |   12 ++-
 question/type/numerical/tests/question_test.php    |    5 +
 question/type/shortanswer/question.php             |    6 +-
 question/type/shortanswer/questiontype.php         |    2 +-
 7 files changed, 203 insertions(+), 12 deletions(-)

diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php
index 547a370d..682e905 100644
--- a/question/type/multianswer/renderer.php
+++ b/question/type/multianswer/renderer.php
@@ -177,13 +177,18 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
         if ($subq->qtype->name() == 'shortanswer') {
             $matchinganswer = $subq->get_matching_answer(array('answer' => $response));
         } else if ($subq->qtype->name() == 'numerical') {
-            $matchinganswer = $subq->get_matching_answer($response, 1);
+            list($value, $unit, $multiplier) = $subq->ap->apply_units($response, '');
+            $matchinganswer = $subq->get_matching_answer($value, 1);
         } else {
             $matchinganswer = $subq->get_matching_answer($response);
         }
 
         if (!$matchinganswer) {
-            $matchinganswer = new question_answer(0, '', null, '', FORMAT_HTML);
+            if (is_null($response) || $response === '') {
+                $matchinganswer = new question_answer(0, '', null, '', FORMAT_HTML);
+            } else {
+                $matchinganswer = new question_answer(0, '', 0.0, '', FORMAT_HTML);
+            }
         }
 
         // Work out a good input field size.
@@ -281,6 +286,9 @@ class qtype_multianswer_multichoice_inline_renderer
         $order = $subq->get_order($qa);
         $correctresponses = $subq->get_correct_response();
         $rightanswer = $subq->answers[$order[reset($correctresponses)]];
+        if (!$matchinganswer) {
+            $matchinganswer = new question_answer(0, '', null, '', FORMAT_HTML);
+        }
         $feedbackpopup = $this->feedback_popup($subq, $matchinganswer->fraction,
                 $subq->format_text($matchinganswer->feedback, $matchinganswer->feedbackformat,
                         $qa, 'question', 'answerfeedback', $matchinganswer->id),
@@ -366,16 +374,30 @@ class qtype_multianswer_multichoice_vertical_renderer extends qtype_multianswer_
 
         $result .= $this->all_choices_wrapper_end();
 
+        $feedback = array();
         if ($options->feedback && $options->marks >= question_display_options::MARK_AND_MAX &&
                 $subq->maxmark > 0) {
             $a = new stdClass();
             $a->mark = format_float($fraction * $subq->maxmark, $options->markdp);
             $a->max =  format_float($subq->maxmark, $options->markdp);
 
-            $result .= html_writer::tag('div', get_string('markoutofmax', 'question', $a),
-                    array('class' => 'outcome'));
+            $feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a));
+        }
+
+        if ($options->rightanswer) {
+            foreach ($subq->answers as $ans) {
+                if (question_state::graded_state_for_fraction($ans->fraction) ==
+                        question_state::$gradedright) {
+                    $feedback[] = get_string('correctansweris', 'qtype_multichoice',
+                            $subq->format_text($ans->answer, $ans->answerformat,
+                                    $qa, 'question', 'answer', $ansid));
+                    break;
+                }
+            }
         }
 
+        $result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome'));
+
         return $result;
     }
 
diff --git a/question/type/multianswer/tests/helper.php b/question/type/multianswer/tests/helper.php
index 75a3d7d..3a77001 100644
--- a/question/type/multianswer/tests/helper.php
+++ b/question/type/multianswer/tests/helper.php
@@ -38,7 +38,7 @@ require_once($CFG->dirroot . '/question/type/multianswer/question.php');
  */
 class qtype_multianswer_test_helper extends question_test_helper {
     public function get_test_questions() {
-        return array('twosubq', 'fourmc');
+        return array('twosubq', 'fourmc', 'numericalzero');
     }
 
     /**
@@ -287,4 +287,48 @@ class qtype_multianswer_test_helper extends question_test_helper {
 
         return $q;
     }
+
+    /**
+     * Makes a multianswer question with one numerical subquestion, right answer 0.
+     * This is used for testing the MDL-35370 bug.
+     * @return qtype_multianswer_question
+     */
+    public function make_multianswer_question_numericalzero() {
+        question_bank::load_question_definition_classes('multianswer');
+        $q = new qtype_multianswer_question();
+        test_question_maker::initialise_a_question($q);
+        $q->name = 'Numerical zero';
+        $q->questiontext =
+                'Enter zero: {#1}.';
+        $q->generalfeedback = '';
+        $q->qtype = question_bank::get_qtype('multianswer');
+
+        $q->textfragments = array(
+            'Enter zero: ',
+            '.',
+        );
+        $q->places = array('1' => '1');
+
+        // Numerical subquestion.
+        question_bank::load_question_definition_classes('numerical');
+        $sub = new qtype_numerical_question();
+        test_question_maker::initialise_a_question($sub);
+        $sub->name = 'Numerical zero';
+        $sub->questiontext = '{1:NUMERICAL:=0:0}';
+        $sub->questiontextformat = FORMAT_HTML;
+        $sub->generalfeedback = '';
+        $sub->generalfeedbackformat = FORMAT_HTML;
+        $sub->answers = array(
+            13 => new qtype_numerical_answer(13, '0', 1.0, '', FORMAT_HTML, 0),
+        );
+        $sub->qtype = question_bank::get_qtype('numerical');
+        $sub->ap = new qtype_numerical_answer_processor(array());
+        $sub->maxmark = 1;
+
+        $q->subquestions = array(
+            1 => $sub,
+        );
+
+        return $q;
+    }
 }
diff --git a/question/type/multianswer/tests/walkthrough_test.php b/question/type/multianswer/tests/walkthrough_test.php
index 19af3c7..9c9d291 100644
--- a/question/type/multianswer/tests/walkthrough_test.php
+++ b/question/type/multianswer/tests/walkthrough_test.php
@@ -37,9 +37,15 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_base {
+
+    protected function get_contains_subq_status(question_state $state) {
+        return new question_pattern_expectation('~' .
+                preg_quote($state->default_string(true), '~') . '<br />~');
+    }
+
     public function test_deferred_feedback() {
 
-        // Create a gapselect question.
+        // Create a multianswer question.
         $q = test_question_maker::make_question('multianswer', 'fourmc');
         $this->start_attempt_at_question($q, 'deferredfeedback', 4);
 
@@ -86,4 +92,110 @@ class qtype_multianswer_walkthrough_test extends qbehaviour_walkthrough_test_bas
                 $this->get_contains_partcorrect_expectation(),
                 $this->get_does_not_contain_validation_error_expectation());
     }
+
+    public function test_deferred_feedback_numericalzero_not_answered() {
+        // Tests the situation found in MDL-35370.
+
+        // Create a multianswer question with one numerical subquestion, right answer zero.
+        $q = test_question_maker::make_question('multianswer', 'numericalzero');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                $this->get_does_not_contain_feedback_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
+
+        // Now submit all and finish.
+        $this->process_submission(array('-finish' => 1));
+
+        // Verify.
+        $this->check_current_state(question_state::$gaveup);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                new question_pattern_expectation('~<input[^>]* class="incorrect" [^>]*/>~'),
+                $this->get_contains_subq_status(question_state::$gaveup),
+                $this->get_does_not_contain_validation_error_expectation());
+    }
+
+    public function test_deferred_feedback_numericalzero_0_answer() {
+        // Tests the situation found in MDL-35370.
+
+        // Create a multianswer question with one numerical subquestion, right answer zero.
+        $q = test_question_maker::make_question('multianswer', 'numericalzero');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                $this->get_does_not_contain_feedback_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
+
+        // Save a the correct answer.
+        $this->process_submission(array('sub1_answer' => '0'));
+
+        // Verify.
+        $this->check_current_state(question_state::$complete);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                $this->get_does_not_contain_feedback_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
+
+        // Now submit all and finish.
+        $this->process_submission(array('-finish' => 1));
+
+        // Verify.
+        $this->check_current_state(question_state::$gradedright);
+        $this->check_current_mark(1);
+        $this->check_current_output(
+                $this->get_contains_mark_summary(1),
+                $this->get_contains_correct_expectation(),
+                $this->get_contains_subq_status(question_state::$gradedright),
+                $this->get_does_not_contain_validation_error_expectation());
+    }
+
+    public function test_deferred_feedback_numericalzero_0_wrong() {
+        // Tests the situation found in MDL-35370.
+
+        // Create a multianswer question with one numerical subquestion, right answer zero.
+        $q = test_question_maker::make_question('multianswer', 'numericalzero');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                $this->get_does_not_contain_feedback_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
+
+        // Save a the correct answer.
+        $this->process_submission(array('sub1_answer' => '42'));
+
+        // Verify.
+        $this->check_current_state(question_state::$complete);
+        $this->check_current_mark(null);
+        $this->check_current_output(
+                $this->get_contains_marked_out_of_summary(),
+                $this->get_does_not_contain_feedback_expectation(),
+                $this->get_does_not_contain_validation_error_expectation());
+
+        // Now submit all and finish.
+        $this->process_submission(array('-finish' => 1));
+
+        // Verify.
+        $this->check_current_state(question_state::$gradedwrong);
+        $this->check_current_mark(0);
+        $this->check_current_output(
+                $this->get_contains_mark_summary(0),
+                $this->get_contains_incorrect_expectation(),
+                $this->get_contains_subq_status(question_state::$gradedwrong),
+                $this->get_does_not_contain_validation_error_expectation());
+    }
 }
diff --git a/question/type/numerical/question.php b/question/type/numerical/question.php
index 110cfdc..0e48155 100644
--- a/question/type/numerical/question.php
+++ b/question/type/numerical/question.php
@@ -179,6 +179,10 @@ class qtype_numerical_question extends question_graded_automatically {
      * @return question_answer the matching answer.
      */
     public function get_matching_answer($value, $multiplier) {
+        if (is_null($value) || $value === '') {
+            return null;
+        }
+
         if (!is_null($multiplier)) {
             $scaledvalue = $value * $multiplier;
         } else {
@@ -193,6 +197,7 @@ class qtype_numerical_question extends question_graded_automatically {
                 return $answer;
             }
         }
+
         return null;
     }
 
@@ -273,18 +278,17 @@ class qtype_numerical_question extends question_graded_automatically {
     public function check_file_access($qa, $options, $component, $filearea, $args,
             $forcedownload) {
         if ($component == 'question' && $filearea == 'answerfeedback') {
-            $question = $qa->get_question();
             $currentanswer = $qa->get_last_qt_var('answer');
             if ($this->has_separate_unit_field()) {
                 $selectedunit = $qa->get_last_qt_var('unit');
             } else {
                 $selectedunit = null;
             }
-            list($value, $unit, $multiplier) = $question->ap->apply_units(
+            list($value, $unit, $multiplier) = $this->ap->apply_units(
                     $currentanswer, $selectedunit);
-            $answer = $question->get_matching_answer($value, $multiplier);
+            $answer = $this->get_matching_answer($value, $multiplier);
             $answerid = reset($args); // itemid is answer id.
-            return $options->feedback && $answerid == $answer->id;
+            return $options->feedback && $answer && $answerid == $answer->id;
 
         } else if ($component == 'question' && $filearea == 'hint') {
             return $this->check_hint_file_access($qa, $options, $args);
diff --git a/question/type/numerical/tests/question_test.php b/question/type/numerical/tests/question_test.php
index d4ba6f8..84fc7d0 100644
--- a/question/type/numerical/tests/question_test.php
+++ b/question/type/numerical/tests/question_test.php
@@ -181,6 +181,11 @@ class qtype_numerical_question_test extends advanced_testcase {
         $this->assertEquals('3.1', $num->summarise_response(array('answer' => '3.1')));
     }
 
+    public function test_summarise_response_zero() {
+        $num = test_question_maker::make_question('numerical');
+        $this->assertEquals('0', $num->summarise_response(array('answer' => '0')));
+    }
+
     public function test_summarise_response_unit() {
         $num = test_question_maker::make_question('numerical', 'unit');
         $this->assertEquals('3.1', $num->summarise_response(array('answer' => '3.1')));
diff --git a/question/type/shortanswer/question.php b/question/type/shortanswer/question.php
index a875c8c..72f0f4a 100644
--- a/question/type/shortanswer/question.php
+++ b/question/type/shortanswer/question.php
@@ -78,6 +78,10 @@ class qtype_shortanswer_question extends question_graded_by_strategy
     }
 
     public function compare_response_with_answer(array $response, question_answer $answer) {
+        if (!array_key_exists('answer', $response) || is_null($response['answer'])) {
+            return false;
+        }
+
         return self::compare_string_with_wildcard(
                 $response['answer'], $answer->answer, !$this->usecase);
     }
@@ -129,7 +133,7 @@ class qtype_shortanswer_question extends question_graded_by_strategy
             $currentanswer = $qa->get_last_qt_var('answer');
             $answer = $qa->get_question()->get_matching_answer(array('answer' => $currentanswer));
             $answerid = reset($args); // itemid is answer id.
-            return $options->feedback && $answerid == $answer->id;
+            return $options->feedback && $answer && $answerid == $answer->id;
 
         } else if ($component == 'question' && $filearea == 'hint') {
             return $this->check_hint_file_access($qa, $options, $args);
diff --git a/question/type/shortanswer/questiontype.php b/question/type/shortanswer/questiontype.php
index 31212ce..2cf77d7 100644
--- a/question/type/shortanswer/questiontype.php
+++ b/question/type/shortanswer/questiontype.php
@@ -117,7 +117,7 @@ class qtype_shortanswer extends question_type {
 
         $this->save_hints($question);
 
-        // Perform sanity checks on fractional grades
+        // Perform sanity checks on fractional grades.
         if ($maxfraction != 1) {
             $result->noticeyesno = get_string('fractionsnomax', 'question', $maxfraction * 100);
             return $result;
-- 
1.7.9.5


From f0f201431682d94e83fe4c5baf35e847e1fb9f30 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 25 Sep 2012 14:08:59 +0100
Subject: [PATCH 713/903] MDL-35620 question engine: should distinguish NULL
 and 0.

This only matters in an obscure edge case, but it is an edge case we hit
with one of the OU question types.

This load data code is processing the results of a LEFT JOIN, so is_null
is the correct logic.
---
 question/engine/questionattemptstep.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/question/engine/questionattemptstep.php b/question/engine/questionattemptstep.php
index 4cd813a..20a34da 100644
--- a/question/engine/questionattemptstep.php
+++ b/question/engine/questionattemptstep.php
@@ -386,7 +386,7 @@ class question_attempt_step {
         $record = $currentrec;
         $data = array();
         while ($currentrec && $currentrec->attemptstepid == $attemptstepid) {
-            if ($currentrec->name) {
+            if (!is_null($currentrec->name)) {
                 $data[$currentrec->name] = $currentrec->value;
             }
             $records->next();
-- 
1.7.9.5


From 022a3555d1f92d4a63bdf159743f604277669243 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 27 Sep 2012 14:13:24 +0100
Subject: [PATCH 714/903] MDL-30885 quiz: use formchangechecker during quiz
 attempts.

To avoid the possiblity of dataloss if a student tries to navigate away
having changed some answers.
---
 mod/quiz/locallib.php |    3 ++-
 mod/quiz/module.js    |    1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php
index f535e9b..fc59804 100644
--- a/mod/quiz/locallib.php
+++ b/mod/quiz/locallib.php
@@ -1456,13 +1456,14 @@ function quiz_get_js_module() {
         'name' => 'mod_quiz',
         'fullpath' => '/mod/quiz/module.js',
         'requires' => array('base', 'dom', 'event-delegate', 'event-key',
-                'core_question_engine'),
+                'core_question_engine', 'moodle-core-formchangechecker'),
         'strings' => array(
             array('cancel', 'moodle'),
             array('flagged', 'question'),
             array('functiondisabledbysecuremode', 'quiz'),
             array('startattempt', 'quiz'),
             array('timesup', 'quiz'),
+            array('changesmadereallygoaway', 'moodle'),
         ),
     );
 }
diff --git a/mod/quiz/module.js b/mod/quiz/module.js
index 89fa16a..ce0d359 100644
--- a/mod/quiz/module.js
+++ b/mod/quiz/module.js
@@ -27,6 +27,7 @@ M.mod_quiz = M.mod_quiz || {};
 M.mod_quiz.init_attempt_form = function(Y) {
     M.core_question_engine.init_form(Y, '#responseform');
     Y.on('submit', M.mod_quiz.timer.stop, '#responseform');
+    M.core_formchangechecker.init({formid: 'responseform'});
 };
 
 M.mod_quiz.init_review_form = function(Y) {
-- 
1.7.9.5


From 40d651bbbb20b4373b6b56e4e09c90b30ff86484 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 27 Sep 2012 18:57:51 +0100
Subject: [PATCH 715/903] MDL-34894 course ws unit tests: fix windows problem.

This fixes a weird windows-only failure, as explained in the tracker
issue.
---
 course/tests/externallib_test.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index 984b9ed..605c5d8 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -580,5 +580,6 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         // Check that the course has been duplicated.
         $this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
+        gc_collect_cycles();
     }
 }
-- 
1.7.9.5


From 28c93484058f9397efa337e1f47c4c1daeea59a1 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Thu, 27 Sep 2012 19:03:34 +0100
Subject: [PATCH 716/903] MDL-35680 user selector: more usable when queries
 are slow.

The problem is to do when you pause a bit, so a search starts, and then
type a bit more before the search finishes. It was behaving like this:

1. Type a bit, then pause.
2. First search request sent.
3. Type a bit more, then pause.
4. Second search request sent.
5. First search request completes.
6. You try to select one result.
7. Second search request comples, overwriting what you are selecting.

This fix works by cancelling the first request before sending the
second.
---
 user/selector/module.js |   24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/user/selector/module.js b/user/selector/module.js
index 68b743d..de2f500 100644
--- a/user/selector/module.js
+++ b/user/selector/module.js
@@ -43,6 +43,8 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
         listbox : Y.one('#'+name),
         /** Used to hold the timeout id of the timeout that waits before doing a search. */
         timeoutid : null,
+        /** Stores any in-progress remote requests. */
+        iotransactions : {},
         /** The last string that we searched for, so we can avoid unnecessary repeat searches. */
         lastsearch : lastsearch,
         /** Whether any options where selected last time we checked. Used by
@@ -140,7 +142,12 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
                 return;
             }
 
-            Y.io(M.cfg.wwwroot + '/user/selector/search.php', {
+            // Try to cancel existing transactions.
+            Y.Object.each(this.iotransactions, function(trans) {
+                trans.abort();
+            });
+
+            var iotrans = Y.io(M.cfg.wwwroot + '/user/selector/search.php', {
                 method: 'POST',
                 data: 'selectorid='+hash+'&sesskey='+M.cfg.sesskey+'&search='+value + '&userselector_searchanywhere=' + this.get_option('searchanywhere'),
                 on: {
@@ -149,6 +156,7 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
                 },
                 context:this
             });
+            this.iotransactions[iotrans.id] = iotrans;
 
             this.lastsearch = value;
             this.listbox.setStyle('background','url(' + M.util.image_url('i/loading', 'moodle') + ') no-repeat center center');
@@ -160,17 +168,27 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
          */
         handle_response : function(requestid, response) {
             try {
+                delete this.iotransactions[requestid];
+                if (!Y.Object.isEmpty(this.iotransactions)) {
+                    // More searches pending. Wait until they are all done.
+                    return;
+                }
                 this.listbox.setStyle('background','');
                 var data = Y.JSON.parse(response.responseText);
                 this.output_options(data);
             } catch (e) {
-                this.handle_failure();
+                this.handle_failure(requestid);
             }
         },
         /**
          * Handles what happens when the ajax request fails.
          */
-        handle_failure : function() {
+        handle_failure : function(requestid) {
+            delete this.iotransactions[requestid];
+            if (!Y.Object.isEmpty(this.iotransactions)) {
+                // More searches pending. Wait until they are all done.
+                return;
+            }
             this.listbox.setStyle('background','');
             this.searchfield.addClass('error');
 
-- 
1.7.9.5


From 860c7e82bd45d068a15827875c790bf7da2e0b89 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Tue, 18 Sep 2012 13:07:01 +1200
Subject: [PATCH 717/903] MDL-35227 SCORM: set completion in correct location.

---
 mod/scorm/lib.php |   56 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 19 deletions(-)

diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php
index c587b68..27b4722 100644
--- a/mod/scorm/lib.php
+++ b/mod/scorm/lib.php
@@ -150,7 +150,7 @@ function scorm_add_instance($scorm, $mform=null) {
 
     scorm_parse($record, true);
 
-    scorm_grade_item_update($record, null, false);
+    scorm_grade_item_update($record);
 
     return $record->id;
 }
@@ -591,18 +591,21 @@ function scorm_get_user_grades($scorm, $userid=0) {
  * @param bool $nullifnone
  */
 function scorm_update_grades($scorm, $userid=0, $nullifnone=true) {
-    global $CFG, $DB;
+    global $CFG;
     require_once($CFG->libdir.'/gradelib.php');
+    require_once($CFG->libdir.'/completionlib.php');
 
     if ($grades = scorm_get_user_grades($scorm, $userid)) {
         scorm_grade_item_update($scorm, $grades);
-
+        //set complete
+        scorm_set_completion($scorm, $userid, COMPLETION_COMPLETE, $grades);
     } else if ($userid and $nullifnone) {
         $grade = new stdClass();
         $grade->userid   = $userid;
         $grade->rawgrade = null;
         scorm_grade_item_update($scorm, $grade);
-
+        //set incomplete.
+        scorm_set_completion($scorm, $userid, COMPLETION_INCOMPLETE);
     } else {
         scorm_grade_item_update($scorm);
     }
@@ -646,10 +649,9 @@ function scorm_upgrade_grades() {
  * @uses GRADE_TYPE_NONE
  * @param object $scorm object with extra cmidnumber
  * @param mixed $grades optional array/object of grade(s); 'reset' means reset grades in gradebook
- * @param boolean $updatecompletion  set whether to update completion stuff
  * @return object grade_item
  */
-function scorm_grade_item_update($scorm, $grades=null, $updatecompletion=true) {
+function scorm_grade_item_update($scorm, $grades=null) {
     global $CFG, $DB;
     require_once($CFG->dirroot.'/mod/scorm/locallib.php');
     if (!function_exists('grade_update')) { //workaround for buggy PHP versions
@@ -680,19 +682,6 @@ function scorm_grade_item_update($scorm, $grades=null, $updatecompletion=true) {
         $grades = null;
     }
 
-    // Update activity completion if applicable
-    if ($updatecompletion) {
-        // Get course info
-        $course = new stdClass();
-        $course->id = $scorm->course;
-
-        $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id);
-        if (!empty($cm)) {
-            $completion = new completion_info($course);
-            $completion->update_state($cm, COMPLETION_COMPLETE);
-        }
-    }
-
     return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, $grades, $params);
 }
 
@@ -1329,3 +1318,32 @@ function scorm_dndupload_handle($uploadinfo) {
 
     return scorm_add_instance($scorm, null);
 }
+
+/**
+ * Sets activity completion state
+ *
+ * @param object $scorm object
+ * @param int $userid User ID
+ * @param int $completionstate Completion state
+ * @param array $grades grades array of users with grades - used when $userid = 0
+ */
+function scorm_set_completion($scorm, $userid, $completionstate = COMPLETION_COMPLETE, $grades = array()) {
+    if (!completion_info::is_enabled()) {
+        return;
+    }
+
+    $course = new stdClass();
+    $course->id = $scorm->course;
+
+    $cm = get_coursemodule_from_instance('scorm', $scorm->id, $scorm->course);
+    if (!empty($cm)) {
+        $completion = new completion_info($course);
+        if (empty($userid)) { //we need to get all the relevant users from $grades param.
+            foreach ($grades as $grade) {
+                $completion->update_state($cm, $completionstate, $grade->userid);
+            }
+        } else {
+            $completion->update_state($cm, $completionstate, $userid);
+        }
+    }
+}
-- 
1.7.9.5


From add494f1afb2ee00240235b086c0d89585621baa Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Fri, 21 Sep 2012 13:41:43 +1200
Subject: [PATCH 718/903] MDL-35557 enrol/database: use distinct call when
 getting list of courses that should be added.

---
 enrol/database/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/enrol/database/lib.php b/enrol/database/lib.php
index 1755a89..b5beeba 100644
--- a/enrol/database/lib.php
+++ b/enrol/database/lib.php
@@ -630,7 +630,7 @@ class enrol_database_plugin extends enrol_plugin {
         if ($idnumber) {
             $sqlfields[] = $idnumber;
         }
-        $sql = $this->db_get_sql($table, array(), $sqlfields);
+        $sql = $this->db_get_sql($table, array(), $sqlfields, true);
         $createcourses = array();
         if ($rs = $extdb->Execute($sql)) {
             if (!$rs->EOF) {
-- 
1.7.9.5


From 31fabbdbaa3922ef96ed33c71e053f23d4563183 Mon Sep 17 00:00:00 2001
From: Dan Marsden <dan@danmarsden.com>
Date: Fri, 21 Sep 2012 21:52:42 +1200
Subject: [PATCH 719/903] MDL-35562 enrol_database: enrolment_sync - don't
 halt sync on failed search for course.

---
 enrol/database/lib.php |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/enrol/database/lib.php b/enrol/database/lib.php
index 1755a89..0109866 100644
--- a/enrol/database/lib.php
+++ b/enrol/database/lib.php
@@ -481,9 +481,8 @@ class enrol_database_plugin extends enrol_plugin {
                 }
                 $rs->Close();
             } else {
-                mtrace('Error while communicating with external enrolment database');
-                $extdb->Close();
-                return;
+                mtrace("  error: skipping course '$course->mapping' - could not match with external database");
+                continue;
             }
             unset($user_mapping);
 
-- 
1.7.9.5


From 14a695f6077a2fc9fe6b36143eb6ecfae0ef230a Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 28 Sep 2012 02:18:48 +0100
Subject: [PATCH 720/903] MDL-35654 theme_anomaly: Added custom menu renderer
 to aid RTL styling of menu

---
 theme/anomaly/config.php                       |    2 +-
 theme/anomaly/pix/menu/nav-arrow-left.jpg      |  Bin 0 -> 461 bytes
 theme/anomaly/pix/menu/nav-arrow-right.jpg     |  Bin 0 -> 460 bytes
 theme/anomaly/pix/menu/nav-arrowover-left.jpg  |  Bin 0 -> 437 bytes
 theme/anomaly/pix/menu/nav-arrowover-right.jpg |  Bin 0 -> 440 bytes
 theme/anomaly/renderers.php                    |   85 +++++++++
 theme/anomaly/style/general.css                |  158 -----------------
 theme/anomaly/style/menu.css                   |  221 ++++++++++++++++++++++++
 8 files changed, 307 insertions(+), 159 deletions(-)
 create mode 100644 theme/anomaly/pix/menu/nav-arrow-left.jpg
 create mode 100644 theme/anomaly/pix/menu/nav-arrow-right.jpg
 create mode 100644 theme/anomaly/pix/menu/nav-arrowover-left.jpg
 create mode 100644 theme/anomaly/pix/menu/nav-arrowover-right.jpg
 create mode 100644 theme/anomaly/style/menu.css

diff --git a/theme/anomaly/config.php b/theme/anomaly/config.php
index 1f32394..d435a8d 100644
--- a/theme/anomaly/config.php
+++ b/theme/anomaly/config.php
@@ -7,7 +7,7 @@
 
 $THEME->name = 'anomaly';
 
-$THEME->sheets = array('base', 'general', 'browser','dock');
+$THEME->sheets = array('base', 'general', 'browser', 'dock', 'menu');
 /// This variable is an array containing the names of all the
 /// stylesheet files you want included in this theme, and in what order
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/theme/anomaly/pix/menu/nav-arrow-left.jpg b/theme/anomaly/pix/menu/nav-arrow-left.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..177f823a0a3a1e73e4846d183d14ec5b1dc5fc78
GIT binary patch
literal 461
zcmex=<NpH&0WUXCHwH#V21Xr59R`N~w;7xnSeaQ^SeRLX1S=~m8#@mNI}q@5b93?t
z@(T$G@(T(Ii^+%!i%5wI3Q8zSNXg2|%gYOkE2${SsmRF5%Yh7G1ZrhxW9Q@G;FA*(
z6p<qt{6D}T$iWc6Ajiz8#K0uT$SlbC{|JLP(5XPjA_F#NcA$ik00R>vGczkfj**Fh
zg;kK5ja^7s(J{~vs74G!FHi+gTtpC|3u^NJTMRtRj6i#t1sUua9&Z#hyfjgeQBXio
zkWtIxc1rB_vp=HOp1!sG^5M{{yPj%Z_-!BY;LG|w@&`DDJ}vIuzV~)=eCx40cW>4D
z=*B8<6I#f=_+y*Dch$+iEKO2HZ`<x~t7Lnev~}I0OF?Q)%L{+a?7VO}Evasr%8vt|
zA22qmJWbcTzxMa+33=wXqq9s^qcV)jg_ln0<uy%Jev#nb(=W#<VdTf8q@bh(CfNVq
F1OWTSaDo5;

literal 0
HcmV?d00001

diff --git a/theme/anomaly/pix/menu/nav-arrow-right.jpg b/theme/anomaly/pix/menu/nav-arrow-right.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e9a89f559fa6c282bd6a5e522e011591a041f703
GIT binary patch
literal 460
zcmex=<NpH&0WUXCHwH#V21Xr59R`N~w;7xnSeaQ^SeRLX1S=~m8#@mNI}q@5b93?t
z@(T$G@(T(Ii^+%!i%5wI3Q8zSNXg2|%gYOkE2${SsmRF5%Yh7G1ZrhxW9Q@G;FA*(
z6p<qt{6D}T$iWc6Ajiz8#K0uT$SlbC{|JLP(5XPjA_I07HlT!(00R>vGYb<lLW+@z
znT3^2P)LzoMA&H~P>mRdUIrFcpty)2s);}&{@-HYVP*u{%Ph!X&(PPvQ?dYTFr&wZ
z{|x<ax4vT!x)}O5XYTy9)>4=9n~Hu`I%U?T9<yD#>!#`c!s4Qd5C1bLL}%#mEnTys
z+S2-bl$c4%e747*KFzuH>-dx^|MFelc~6>~&nA76h*^6~TRS`G(zjbRT9;<M)Bm_^
zTjsi1nQJc_&NhzpY0K6woO<eR$nL#6=UZ(}`#t%Or|u;0C6l~UdJ@1c0uuHAZvp^z
CO>wsX

literal 0
HcmV?d00001

diff --git a/theme/anomaly/pix/menu/nav-arrowover-left.jpg b/theme/anomaly/pix/menu/nav-arrowover-left.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..596b6ff366dac22ec6974758b9c973c56865adb7
GIT binary patch
literal 437
zcmex=<NpH&0WUXCHwH#V21Xr59R`N~w;7xnSeaQ^SeRLX1S=~m8#@mNI}q@5b93?t
z@(T$G@(T(Ii^+%!i%5wI3Q8zSNXg2|%gYOkE2${SsmRF5%Yh7G1ZrhxW9Q@G;FA*(
z6p<qt{6D}T$iWc6Ajiz8#K0uT$SlbC{|JK^(5Z|JD1em-D6TBPz{JSR%)*S2Vq{`w
z5oBdkWET<+bWA)5(hSs#rkRBmC@vz1CJGFPTMRtRj6i#t1sUuaW-u5ELJVd-J9At9
zce_<<-dykNG1Ttv)Hyb#KKeQL^OtH@jGmpjbNzR6X!x}JlWrBgNB7KA4zuqqZvXgg
zwvXu*S*^=1cel@q?V7cHp_G^Hr!%ul7TnIiox4BgV-sif3ahotw(rh2^%ghJk29H5
Z{kT(YrK8F9EtlhVJXR5adCLC(O#tQ&WXS*k

literal 0
HcmV?d00001

diff --git a/theme/anomaly/pix/menu/nav-arrowover-right.jpg b/theme/anomaly/pix/menu/nav-arrowover-right.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..15f8cf177ebaead49fdbe98b18f34860a1a49f4a
GIT binary patch
literal 440
zcmex=<NpH&0WUXCHwH#V21Xr59R`N~w;7xnSeaQ^SeRLX1S=~m8#@mNI}q@5b93?t
z@(T$G@(T(Ii^+%!i%5wI3Q8zSNXg2|%gYOkE2${SsmRF5%Yh7G1ZrhxW9Q@G;FA*(
z6p<qt{6D}T$iWc6Ajiz8#K0uT$SlbC{|JLP(5XPjA_F!SR-lBk00R>vGcyY_LW+@@
ziA9lBP?(Kf$j~wHAW)GQhGqt^W>G;jGZ`2d|KDQZVP*u{%q+-Y&+v?a$Hf6`G-K-R
zbCcRvZCRUTs?Ym&J8#$~vp?lEvo8nzs@C}(tv+YDRAkxb)rl`-wWB7wo~<rE?7Jq{
zUiP}$*N}hHUd!EknXIcY^~##OFSmcL$zQOJdq&pBNmhH8|JoNEk*#qq<I4JVU$uX(
eU%z}^^~_bDCVB1M{$rm|gg3`In77#f-vj_*m}kWR

literal 0
HcmV?d00001

diff --git a/theme/anomaly/renderers.php b/theme/anomaly/renderers.php
index d5b8296..016f2fb 100644
--- a/theme/anomaly/renderers.php
+++ b/theme/anomaly/renderers.php
@@ -81,4 +81,89 @@ class theme_anomaly_core_renderer extends core_renderer {
         return $output;
     }
 
+    /**
+     * Renders a custom menu object (located in outputcomponents.php)
+     *
+     * The custom menu this method override the render_custom_menu function
+     * in outputrenderers.php
+     * @staticvar int $menucount
+     * @param custom_menu $menu
+     * @return string
+     */
+    protected function render_custom_menu(custom_menu $menu) {
+
+        // If the menu has no children return an empty string
+        if (!$menu->has_children()) {
+            return '';
+        }
+
+        // Add a login or logout link
+        if (isloggedin()) {
+            $branchlabel = get_string('logout');
+            $branchurl   = new moodle_url('/login/logout.php');
+        } else {
+            $branchlabel = get_string('login');
+            $branchurl   = new moodle_url('/login/index.php');
+        }
+        $branch = $menu->add($branchlabel, $branchurl, $branchlabel, -1);
+
+        // Initialise this custom menu
+        $content = html_writer::start_tag('ul', array('class'=>'dropdown dropdown-horizontal'));
+        // Render each child
+        foreach ($menu->get_children() as $item) {
+            $content .= $this->render_custom_menu_item($item);
+        }
+        // Close the open tags
+        $content .= html_writer::end_tag('ul');
+        // Return the custom menu
+        return $content;
+    }
+
+    /**
+     * Renders a custom menu node as part of a submenu
+     *
+     * The custom menu this method override the render_custom_menu_item function
+     * in outputrenderers.php
+     *
+     * @see render_custom_menu()
+     *
+     * @staticvar int $submenucount
+     * @param custom_menu_item $menunode
+     * @return string
+     */
+    protected function render_custom_menu_item(custom_menu_item $menunode) {
+        // Required to ensure we get unique trackable id's
+        static $submenucount = 0;
+        $content = html_writer::start_tag('li');
+        if ($menunode->has_children()) {
+            // If the child has menus render it as a sub menu
+            $submenucount++;
+            if ($menunode->get_url() !== null) {
+                $url = $menunode->get_url();
+            } else {
+                $url = '#cm_submenu_'.$submenucount;
+            }
+            $content .= html_writer::start_tag('span', array('class'=>'customitem'));
+            $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title()));
+            $content .= html_writer::end_tag('span');
+            $content .= html_writer::start_tag('ul');
+            foreach ($menunode->get_children() as $menunode) {
+                $content .= $this->render_custom_menu_item($menunode);
+            }
+            $content .= html_writer::end_tag('ul');
+        } else {
+            // The node doesn't have children so produce a final menuitem
+
+            if ($menunode->get_url() !== null) {
+                $url = $menunode->get_url();
+            } else {
+                $url = '#';
+            }
+            $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title()));
+        }
+        $content .= html_writer::end_tag('li');
+        // Return the sub menu
+        return $content;
+    }
+
 }
\ No newline at end of file
diff --git a/theme/anomaly/style/general.css b/theme/anomaly/style/general.css
index d695186..cfc2ecf 100644
--- a/theme/anomaly/style/general.css
+++ b/theme/anomaly/style/general.css
@@ -11,21 +11,17 @@ a:visited {
 a:hover {
     text-decoration: underline;
 }
-
 img.icon,
 img.iconhelp {
     vertical-align: middle;
 }
-
 html, body {
     background-color: #C8C9C7;
 }
-
 #page-content {
     background-color: #FFF;
     min-width: 0;
 }
-
 /** Header **/
 
 #page-header {
@@ -36,14 +32,12 @@ html, body {
     padding: 0;
     width: 100%;
 }
-
 h1.headermain {
     float: left;
     font-size: 2.3em;
     margin: 15px;
     line-height: 1;
 }
-
 #page-header .headermain span {
     color: #C8C9C7;
 }
@@ -54,7 +48,6 @@ h1.headermain {
     border-bottom-color: #3A4D28;
     border-bottom-width: 3px;
 }
-
 #page-header .navbar {
     background-color: #697F55;
     width: 100%;
@@ -96,7 +89,6 @@ h1.headermain {
     background-color: #E3E3E3;
     padding: 4px 5px;
 }
-
 .coursebox {
     width: 100%;
     margin: 10px 0;
@@ -120,55 +112,44 @@ h1.headermain {
 .course-content .headingblock.outline {
     margin-top: 0;
 }
-
 .course-content .section.main {
     border:1px solid #E3E3E3;
     margin-bottom: 10px;
 }
-
 .course-content .section.main .left.side {
     float:left;width:20px;padding:5px;
 }
-
 .course-content .section.main .right.side {
     float: right;
     width: 20px;
     padding: 5px;
 }
-
 .course-content .section.main .content {
     padding: 5px 5px 10px;
     background-color: #FFF;
 }
-
 .course-content .section.main .content .section_add_menus {
     text-align: right;
 }
-
 #page-report-outline-user .section {
     border: 1px solid #DDD;
     margin: 0 5% 1.5em 5%;
 }
-
 #page-report-outline-user .section h2,
 #page-report-outline-user .section .content {
     margin: 5px 1em;
 }
-
 #page-report-outline-user .section table td {
     border: 0;
 }
-
 .generaltable {
     border: 1px solid #DDD;
 }
-
 .generaltable .cell {
     background-color: #FFF;
     border:1px solid #EEE;
     border-collapse: collapse;
 }
-
 .generaltable .header {
     background-color: #EEE;
     border: 1px solid #EEE;
@@ -180,17 +161,14 @@ h1.headermain {
     margin-top: 15px;
     margin-bottom: 15px;
 }
-
 .loginbox .loginform {
     margin-top: 15px;
 }
-
 .loginbox .loginform .form-label {
     width: 44%;
     float: left;
     text-align: right;
 }
-
 .loginbox .loginform .form-input {
     width: 55%;
     float: right;
@@ -200,42 +178,34 @@ h1.headermain {
 .loginbox .loginform .form-input input {
     width: 6em;
 }
-
 .loginbox.twocolumns {
     border: 1px solid #DDD;
 }
-
 .loginbox.twocolumns .loginpanel {
     float: left;
     width: 49%;
     text-align: center;
 }
-
 .loginbox.twocolumns .signuppanel {
     float: left;
     width: 50%;
     border-left: 1px solid #DDD;
 }
-
 .loginbox.twocolumns .signuppanel h2 {
     text-align: center;
 }
-
 .loginbox.twocolumns .signuppanel div {
     margin: 1em;
 }
-
 .loginbox.twocolumns .signuppanel div li {
     font-size: 90%;
 }
-
 .loginbox .loginsub {
     margin-left: 10%;
     margin-right: 10%;
     padding: 10px;
     margin-bottom: 5px;
 }
-
 .loginbox .guestsub {
     margin-left: 10%;
     margin-right: 10%;
@@ -243,7 +213,6 @@ h1.headermain {
     margin-bottom: 5px;
     border-top: 1px solid #DDD;
 }
-
 .dir-rtl .loginbox .loginform .form-input {width:50%}
 
 /** Blocks **/
@@ -260,15 +229,12 @@ h1.headermain {
 .block h4 {
     margin: 0;
 }
-
 .block .header {
     margin: 10px 6px 3px 6px;
 }
-
 .block .content {
     margin: 10px 6px 3px 6px;
 }
-
 /** Admin **/
 .box.adminwarning {
     text-align: center;
@@ -282,62 +248,50 @@ h1.headermain {
     font-size: 90%;
     padding: 10px 10%;
 }
-
 #adminsettings fieldset {
     border: 1px solid #C8C9C7;
     background-color: #E3E3E3;
 }
-
 #adminsettings fieldset .generalbox {
     margin: 1em 0.5em;
     border-color: #C8C9C7;
 }
-
 #adminsettings .form-buttons {
     margin-left: 13em;
 }
-
 .form-item {
     width: 100%;
     margin: 1em 1em 2em 1em;
 }
-
 .form-item .form-label {
     width: 12.5em;
     text-align: right;
     float: left;
     margin-right: 0.5em;
 }
-
 .form-item .form-label .form-shortname {
     display: block;
     color: #666;
     font-size: 75%;
 }
-
 .form-item .form-setting {
     margin-left: 13em;
 }
-
 .form-item .form-setting .defaultsnext {
     display:inline;
 }
-
 .form-item .form-setting .form-defaultinfo {
     display: inline;
     margin-left: 0.5em;
     font-size: 90%;
     color: #666;
 }
-
 .form-item .form-description {
     margin: 0.5em 1em 0.5em 13em;
 }
-
 .form-item .form-textarea textarea {
     width: 495px;
 }
-
 #authmenu .informationbox {
     width: 80%;
     margin: 0 auto 10px;
@@ -347,13 +301,11 @@ h1.headermain {
 #authmenu table td {
     border-width: 0;
 }
-
 #categoryquestions {
     margin-left: auto;
     margin-right: auto;
     width: 100%;
 }
-
 #categoryquestions th,
 .user th,
 .user th.header,
@@ -365,7 +317,6 @@ h1.headermain {
     border: 2px solid #697F55;
     border-bottom-color: #111;
 }
-
 .user th a:link,
 #categoryquestions th a:link,
 .group  th a:link,
@@ -373,7 +324,6 @@ h1.headermain {
     color: #FFF;
     text-decoration: none;
 }
-
 .user th a:visited,
 #categoryquestions th a:visited,
 .group th a:visited,
@@ -381,7 +331,6 @@ h1.headermain {
     color: #FFF;
     text-decoration: underline;
 }
-
 .user tr td.cell,
 #categoryquestions tr td.cell,
 .group tr td.cell,
@@ -389,39 +338,32 @@ h1.headermain {
     border: 1px solid #C8C9C7;
     border-width: 0 1px;
 }
-
 .user .r1 .cell,
 #categoryquestions .r1 .cell,
 .group .r1 .cell,
 .admin table .r1 .cell {
     background-color: #EEE;
 }
-
 .singlebutton,
 .buttons {
     text-align: center;
     margin: 20px;
 }
-
 .buttons form {
     display: inline;
 }
-
 .buttons div {
     display: inline;
 }
-
 .buttons .singlebutton {
     display: inline;
     padding: 5px;
     margin: 0;
 }
-
 .admin .generalbox {
     background-color: #EEE;
     border-color: #C8C9C7;
 }
-
 #admin-mnet-index table td,
 #files-index .column-content table td {
     border-width: 0;
@@ -436,7 +378,6 @@ h1.headermain {
 .tag-management-form {
     text-align:center;
 }
-
 #tag-management-list {
     margin-top:1em;
 }
@@ -446,12 +387,10 @@ h1.headermain {
     border-width: 0;
     vertical-align: top;
 }
-
 .userinfobox .side {
     width: 120px;
     text-align: center;
 }
-
 .userinfobox .list .label {font-weight:bold;text-align:right;
 }
 
@@ -463,7 +402,6 @@ h1.headermain {
     border: 1px solid #DDD;
     border-collapse: separate;
 }
-
 .forumpost,
 .forumpost .left.picture {
     background-color: #EEE;
@@ -484,13 +422,11 @@ h1.headermain {
 .forumpost .topic .author {
     padding-left: 10px;
 }
-
 .forumpost .content,
 .forumpost .options {
     background-color: white;
     padding-top: 10px;
 }
-
 .forumpost .content .shortenedpost a {
     margin: 0 10px;
     padding: 0;
@@ -505,7 +441,6 @@ h1.headermain {
 .forumpost .options .link {
     padding-right: 10px;
 }
-
 .forumpost .content .shortenedpost a,
 .forumpost .content .shortenedpost span.post-word-count,
 .forumpost .commands,
@@ -517,13 +452,11 @@ h1.headermain {
 .forumpost .row .left {
     clear: left;
 }
-
 .forumpost .posting.shortenedpost {margin-left: 10px;}
 
 #page-mod-forum-discuss #page-header { /* fixes broken header in forum discuss */
     margin-top: 10px;
 }
-
 /** Calendar **/
 .block.block_calendar_month td,
 .block.block_calendar_month th {
@@ -533,12 +466,10 @@ h1.headermain {
     width: 14%;
     line-height: 18px;
 }
-
 #calendar abbr,
 .block.block_calendar_month abbr {
     border-bottom-width: 0;
 }
-
 #calendar .weekend,
 .block.block_calendar_month .weekend {
     color: #A00;
@@ -547,19 +478,16 @@ h1.headermain {
 .block.block_calendar_month .today {
     border: 1px solid #444;
 }
-
 #calendar .eventnone a,
 .block.block_calendar_month .eventnone a {
     color:#444;
 }
-
 #calendar {
     width: 98%;
     margin: 0 1%;
     border-spacing: 5px;
     border-collapse: separate;
 }
-
 #calendar td,
 #calendar th {
     border-width: 0;
@@ -569,43 +497,35 @@ h1.headermain {
     line-height: 18px;
     vertical-align: top;
 }
-
 #calendar .maincalendar {
     width: auto;
     border: 1px solid #DDD;
 }
-
 #calendar .maincalendar .heightcontainer {
     height: 100%;
     position: relative;
     margin: 1em;
 }
-
 #calendar .maincalendar .header {
     padding: 5px;
     font-weight: bold;
 }
-
 #calendar .maincalendar .header .buttons {
     float: right;
 }
-
 #calendar .maincalendar table {
     width: 100%;
 }
-
 #calendar .maincalendar .calendar-controls {
     width: 100%;
     overflow: hidden;
     font-size: 1.1em;
 }
-
 #calendar .maincalendar .calendar-controls .previous {
     display: block;
     float: left;
     width: 20%;
 }
-
 #calendar .maincalendar .calendar-controls .current {
     display: block;
     float: left;
@@ -613,43 +533,35 @@ h1.headermain {
     text-align: center;
     margin-top: 0;
 }
-
 #calendar .maincalendar .calendar-controls .next {
     display: block;
     float: left;
     width: 20%;
     text-align: right;
 }
-
 #calendar .sidecalendar {
     width: 200px;
 }
-
 #calendar .sidecalendar h2,
 #calendar .sidecalendar h3 {
     margin: 5px;
     font-size: 95%;
 }
-
 #calendar .sidecalendar .block {
     border: 1px solid #DDD;
     margin-bottom: 10px;
     text-align: center;
 }
-
 #calendar .sidecalendar .block table {
     margin: 0 auto 5px;
 }
-
 #calendar .sidecalendar .block .filters table {
     width: 95%;
     margin: 0 auto 1em;
 }
-
 #calendar .sidecalendar .block .minicalendarblock {
     border-top: 1px solid #DDD;
 }
-
 #calendar .filters table {
     padding: 2px;
     background-color: #EEE;
@@ -657,7 +569,6 @@ h1.headermain {
     border-spacing: 2px;
     border-collapse: separate;
 }
-
 #calendar .filters table td {
     font-size: 100%;
     width: auto;
@@ -667,91 +578,73 @@ h1.headermain {
     border: 1px solid #444;
     overflow: hidden;
 }
-
 #calendar .calendar_event_global {
     background-color: #D6F8CD;
 }
-
 #calendar .calendar_event_course {
     background-color: #FFD3BD;
 }
-
 #calendar .calendar_event_group {
     background-color: #FEE7AE;
 }
-
 #calendar .calendar_event_user {
     background-color: #DCE7EC;
 }
-
 #calendar .maincalendar .calendarmonth {
     border-collapse: separate;
 }
-
 #calendar .maincalendar .calendarmonth th {
     font-size: 0.9em;
     border-bottom: 2px solid #444;
 }
-
 #calendar .maincalendar .calendarmonth td {
     border: 1px solid #EEE;
     border-bottom-color: #CCC;
     border-right-color: #CCC;
     height: 6em;
 }
-
 #calendar .maincalendar .calendarmonth td div {margin:4px;font-size:0.9em;
 }
 
 #calendar .maincalendar .calendarmonth td .day {font-weight:bold;
 }
-
 #calendar .maincalendar .calendarmonth tr td:first-child {
     border-left-color: #CCC;
 }
-
 #calendar .maincalendar .event {
     border-spacing: 0;
     border: 1px solid #DDD;
     background-color: #EEE;
 }
-
 #calendar .maincalendar .event .picture {
     width: 32px;
     text-align: center;
 }
-
 #calendar .maincalendar .event .topic {
     width: auto;
     padding: 5px;
 }
-
 #calendar .maincalendar .event .side {
     width: 32px;
 }
-
 #calendar .maincalendar .event .description {
     width: auto;
     border-top: 1px solid #DDD;
     border-left:1px solid #DDD;
     padding: 5px;
 }
-
 #calendar .maincalendar .bottom {
     text-align: center;
 }
-
 #calendar .calendarmonth ul {
     margin: 0;
     padding: 0;
 }
-
 #calendar .calendarmonth ul li {
     list-style: none;
     margin: 0;
     padding: 2px;
 }
-
 /** User **/
 
 .user .rolesform,
@@ -760,14 +653,11 @@ h1.headermain {
 .user #participantsform {
     text-align:center;
 }
-
 .user #participantsform table {
     margin-top:1em;
 }
-
 .user #participantsform td {text-align:left;
 }
-
 .user table.controls {
     margin: 5px auto;
     border: 1px solid #DDD;
@@ -777,7 +667,6 @@ h1.headermain {
 .user table.controls td {
     border-width:0px;
 }
-
 /** Overide for RTL layout **/
 
 .dir-rtl #page-header .navbar .breadcrumb {
@@ -787,53 +676,6 @@ h1.headermain {
     float:left;
 }
 
-/** Custom menu **/
-
-#custommenu {
-    margin-bottom: 0;
-}
-
-#custommenu .yui3-menu-horizontal .yui3-menu-content,
-#custommenu .yui3-menu-horizontal.javascript-disabled .yui3-menu-content,
-#custommenu .yui3-menu-horizontal .yui3-menu-content ul,
-#custommenu .yui3-menu-horizontal.javascript-disabled .yui3-menu-content ul,
-#custommenu .yui3-menu-horizontal.javascript-disabled .yui3-menu-content li li:hover > a,
-#custommenu .yui3-menu-horizontal .yui3-menu-label,
-#custommenu .yui3-menuitem,
-#custommenu .yui3-menuitem .yui3-menuitem-content {
-    border-width: 0;
-}
-
-#custommenu .yui3-menu .yui3-menu-label,
-#custommenu .yui3-menu .yui3-menuitem-content {
-    color: #FFF;
-    font-weight: bold;
-    line-height: 30px;
-    padding: 0 14px;
-}
-
-#custommenu .custom_menu_submenu .yui3-menu-content{
-    background-color: #3A4D28;
-}
-
-#custommenu .yui3-menuitem-active .yui3-menuitem-content {
-    background-image: none;
-}
-
-#custommenu .custom_menu_submenu .yui3-menu-label,
-#custommenu .custom_menu_submenu .yui3-menuitem-content {
-    line-height: 25px;
-    padding: 0 20px;
-}
-
-#custommenu .yui3-menu-label-active,
-#custommenu .yui3-menu-label-menuvisible,
-#custommenu .yui3-menuitem-active .yui3-menuitem-content,
-#custommenu .yui3-menu .yui3-menu .yui3-menuitem-active .yui3-menuitem-content,
-#custommenu .yui3-menu-horizontal.javascript-disabled li a:hover {
-    background-color: #697F55;
-}
-
 /* Add Block
 -------------------------*/
 .block .content .singleselect form#add_block .select.menubui_addblock { width: 160px;}
diff --git a/theme/anomaly/style/menu.css b/theme/anomaly/style/menu.css
new file mode 100644
index 0000000..09a8c14
--- /dev/null
+++ b/theme/anomaly/style/menu.css
@@ -0,0 +1,221 @@
+/* Custom menu, in LTR mode
+--------------------------*/
+#custommenu {
+    width: 100%;
+    margin: 0;
+    padding: 0;
+    clear: both;
+    height: 30px;
+    background: #222;
+    margin:0;
+}
+/*
+Dropdown Menu - CSS from DeCaf Theme by Lei Zhang
+-------------------------------------------------*/
+ul.dropdown span.customitem {
+    padding: 0;
+    border: 0;
+    width: 100%;
+}
+ul.dropdown span.customitem {
+    padding: 0;
+    width: 100%;
+}
+ul.dropdown li a,
+ul.dropdown span.customitem a {
+    padding: 6px 20px;
+}
+ul.dropdown span.customitem a:hover {
+    border: 0;
+}
+#custommenu ul.dropdown ul {
+    padding:0;
+    width: auto;
+}
+#custommenu ul.dropdown ul a {
+    padding: 4px 18px;
+}
+#custommenu ul.dropdown > li span a {
+    height: 16px;
+}
+ul.dropdown,
+ul.dropdown li,
+ul.dropdown ul {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+ul.dropdown {
+    position:relative;
+    top: 0;
+    z-index: 597;
+    float:left;
+    font-size: 13px;
+}
+ul.dropdown li {
+    float: left;
+    line-height: 1.3em;
+    vertical-align: middle;
+    background-color: transparent;
+    color: #FFF;
+    zoom: 1;
+}
+ul.dropdown li.hover,
+ul.dropdown li:hover {
+    position: relative;
+    z-index: 599;
+    cursor: default;
+}
+ul.dropdown ul {
+    visibility: hidden;
+    position: absolute;
+    top: 100%;
+    z-index: 598;
+    left: 0;
+    right: auto;
+    margin-top: -1px; /** this setting is important do not change **/
+    font-size: 100%;
+}
+ul.dropdown ul li {
+    float:none;
+    background-color: #3A4D28;
+    border-width: 1px;
+    border-style: solid;
+    border-color: #3A4D28 #697F55 #5A6D49; /** menu item border **/
+    padding: 0;
+}
+ul.dropdown ul ul {
+    top: 0;
+    right: auto;
+    left: 100%;
+    margin-top: 0;
+    border-top: none;
+    border-left: none;
+    font-weight: 400;
+}
+ul.dropdown li:hover > ul {
+    visibility: visible;
+}
+ul.dropdown span,
+ul.dropdown span a,
+ul.dropdown li.clickable-with-children > a {
+    width: auto;
+    padding: 2px 6px 4px 20px;
+    color: #FFF;
+}
+ul.dropdown ul span,
+ul.dropdown ul span a,
+ul.dropdown ul li.clickable-with-children > a {
+    background-color: #3A4D28;
+    background-image: url([[pix:theme|menu/nav-arrow-right]]);
+    background-position: 100% 50%;
+    background-repeat: no-repeat;
+    color: #FFF;
+}
+ul.dropdown ul ul span,
+ul.dropdown ul ul span a,
+ul.dropdown ul ul li.clickable-with-children > a {
+    background-color: #3A4D28;
+    background-image: url([[pix:theme|menu/nav-arrow-right]]);
+    background-position: 100% 50%;
+    background-repeat: no-repeat;
+    color: #FFF;
+}
+ul.dropdown a:link,
+ul.dropdown a:visited {
+    color: white;
+    text-decoration: none;
+}
+ul.dropdown a:hover {
+    border: 0 none;
+    background-color: #697F55;
+    color: #FFF;
+}
+ul.dropdown ul ul li {
+    background-color: #3A4D28;
+}
+ul.dropdown ul ul ul li {
+    background-color: #3A4D28;
+}
+ul.dropdown li a,
+ul.dropdown span,
+ul.dropdown span a {
+    border: 0 none;
+}
+ul.dropdown ul li a,
+ul.dropdown ul span,
+ul.dropdown ul span a {
+    border: 0;
+}
+ul.dropdown ul ul li a,
+ul.dropdown ul ul span,
+ul.dropdown ul ul span a {
+    border: 0 none;
+}
+ul.dropdown ul ul ul li a,
+ul.dropdown ul ul ul span,
+ul.dropdown ul ul ul span a {
+    border: 0 none;
+}
+ul.dropdown a,
+ul.dropdown span {
+    display: block;
+}
+ul.dropdown ul a {
+    width: 166px;
+    padding: 2px 0 4px 5px;
+}
+ul.dropdown ul a.open:hover {
+   background-color: #697F55;
+    color: #FFF;
+}
+ul.dropdown ul li:hover > span,
+ul.dropdown ul li:hover > span a {
+    background-color: #697F55;
+    background-image:url([[pix:theme|menu/nav-arrowover-right]]);
+    color:  #FFF;
+}
+ul.dropdown li.clickable-with-children:hover > a {
+    background-image:url([[pix:theme|menu/nav-arrowover-right]]);
+}
+ul.dropdown *.open,
+ul.dropdown li:hover > span,
+ul.dropdown li:hover > span a {
+    background-color: #697F55;
+    color: #FFF;
+}
+ul.dropdown ul ul *.open,
+ul.dropdown ul ul li:hover > span,
+ul.dropdown ul ul li:hover > span a {
+    background-color: #697F55;
+    background-image: url([[pix:theme|menu/nav-arrowover-right]]);
+    color: #FFF;
+}
+
+/* Custom menu, in RTL mode
+---------------------------*/
+.dir-rtl #custommenu ul.dropdown {
+    float: right;
+}
+.dir-rtl #custommenu ul.dropdown ul{
+    right: 0;
+    left: auto;
+}
+.dir-rtl #custommenu ul.dropdown ul ul {
+    right: 203px;
+    left: auto;
+}
+.dir-rtl #custommenu ul.dropdown ul span,
+.dir-rtl #custommenu ul.dropdown ul span a,
+.dir-rtl #custommenu ul.dropdown ul li.clickable-with-children > a {
+    background-image: url([[pix:theme|menu/nav-arrow-left]]);
+    background-position: 0 50%;
+    background-repeat: no-repeat;
+}
+.dir-rtl #custommenu ul.dropdown ul li:hover > span,
+.dir-rtl #custommenu ul.dropdown ul li:hover > span a {
+    background-image: url([[pix:theme|menu/nav-arrowover-left]]);
+}
+.dir-rtl #custommenu ul.dropdown li.clickable-with-children:hover > a {
+    background-image: url([[pix:theme|menu/nav-arrowover-left]]);
+}
-- 
1.7.9.5


From 7765e94f5edb3e305c7e9aedad54ca43e9cc3a9f Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 18 Sep 2012 13:41:11 +0800
Subject: [PATCH 721/903] MDL-34931 core_grade: Fixed grades hidden when
 activity is hidden

---
 grade/report/user/lib.php |   24 +++++++++++++-----------
 lib/modinfolib.php        |   20 +++++++++++++++++---
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php
index 915aefd..cd2e951 100644
--- a/grade/report/user/lib.php
+++ b/grade/report/user/lib.php
@@ -341,23 +341,25 @@ class grade_report_user extends grade_report {
                 $hidden = ' hidden';
             }
 
+            $hide = false;
             // If this is a hidden grade item, hide it completely from the user.
             if ($grade_grade->is_hidden() && !$this->canviewhidden && (
                     $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN ||
                     ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) {
-                // return false;
-            } else {
-                // The grade object can be marked visible but still be hidden
-                // if "enablegroupmembersonly" is on and its an activity assigned to a grouping the user is not in
-                if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
-                    $instances = $this->gtree->modinfo->get_instances();
-                    if (!empty($instances[$grade_object->itemmodule][$grade_object->iteminstance])) {
-                        $cm = $instances[$grade_object->itemmodule][$grade_object->iteminstance];
-                        if (!$cm->uservisible) {
-                            return false;
-                        }
+                $hide = true;
+            } else if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
+                // The grade object can be marked visible but still be hidden if "enablegroupmembersonly"
+                // is on and it's an activity assigned to a grouping the user is not in.
+                $instances = $this->gtree->modinfo->get_instances_of($grade_object->itemmodule);
+                if (!empty($instances[$grade_object->iteminstance])) {
+                    $cm = $instances[$grade_object->iteminstance];
+                    if ($cm->is_user_access_restricted_by_group()) {
+                        $hide = true;
                     }
                 }
+            }
+
+            if (!$hide) {
                 /// Excluded Item
                 if ($grade_grade->is_excluded()) {
                     $fullname .= ' ['.get_string('excluded', 'grades').']';
diff --git a/lib/modinfolib.php b/lib/modinfolib.php
index 0739f76..c787896 100644
--- a/lib/modinfolib.php
+++ b/lib/modinfolib.php
@@ -1095,17 +1095,31 @@ class cm_info extends stdClass {
         }
         // Check group membership. The grouping option makes the activity
         // completely invisible as it does not apply to the user at all.
+        if ($this->is_user_access_restricted_by_group()) {
+            $this->uservisible = false;
+            // Ensure activity is completely hidden from user.
+            $this->showavailability = 0;
+        }
+    }
+
+    /**
+     * Checks whether the module group settings restrict the user access.
+     * @return bool true if the user access is restricted
+     */
+    public function is_user_access_restricted_by_group() {
+        global $CFG;
+        $modcontext = context_module::instance($this->id);
+        $userid = $this->modinfo->get_user_id();
         if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
                 and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
             // If the activity has 'group members only' and you don't have accessallgroups...
             $groups = $this->modinfo->get_groups($this->groupingid);
             if (empty($groups)) {
                 // ...and you don't belong to a group, then set it so you can't see/access it
-                $this->uservisible = false;
-                // Ensure activity is completely hidden from user.
-                $this->showavailability = 0;
+                return true;
             }
         }
+        return false;
     }
 
     /**
-- 
1.7.9.5


From daa3c5ff1b8dfafb494d41c7b8357a5aeea1a650 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 31 Jul 2012 17:40:06 +0800
Subject: [PATCH 722/903] MDL-34570 accessibility compliance for question:
 edit string label

---
 question/behaviour/rendererbase.php                |    3 ++-
 question/format/xhtml/format.php                   |    9 ++++++---
 question/format/xhtml/lang/en/qformat_xhtml.php    |    1 +
 .../type/calculated/lang/en/qtype_calculated.php   |    2 ++
 question/type/calculated/questiontype.php          |    6 ++++--
 question/type/essay/lang/en/qtype_essay.php        |    1 +
 question/type/essay/renderer.php                   |    3 ++-
 question/type/match/lang/en/qtype_match.php        |    1 +
 question/type/match/renderer.php                   |    1 +
 question/type/multianswer/renderer.php             |    6 +++---
 question/type/numerical/renderer.php               |    7 +++++--
 question/type/shortanswer/renderer.php             |    4 ++--
 12 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/question/behaviour/rendererbase.php b/question/behaviour/rendererbase.php
index adf9363..78de4db 100644
--- a/question/behaviour/rendererbase.php
+++ b/question/behaviour/rendererbase.php
@@ -88,12 +88,13 @@ abstract class qbehaviour_renderer extends plugin_renderer_base {
                 array('id' => $id, 'name' => $inputname, 'rows' => 10, 'cols' => 60)));
 
         $commenteditor .= html_writer::start_tag('div');
-        if (count($formats == 1)) {
+        if (count($formats) == 1) {
             reset($formats);
             $commenteditor .= html_writer::empty_tag('input', array('type' => 'hidden',
                     'name' => $inputname . 'format', 'value' => key($formats)));
 
         } else {
+            $commenteditor .= html_writer::label(get_string('formattexttype'), 'menu' . $inputname . 'format', false, array('class' => 'accesshide'));
             $commenteditor .= html_writer::select(
                     $formats, $inputname . 'format', $commentformat, '');
         }
diff --git a/question/format/xhtml/format.php b/question/format/xhtml/format.php
index 0b70c45..a289ae6 100644
--- a/question/format/xhtml/format.php
+++ b/question/format/xhtml/format.php
@@ -95,12 +95,14 @@ class qformat_xhtml extends qformat_default {
             break;
         case SHORTANSWER:
             $expout .= "<ul class=\"shortanswer\">\n";
-            $expout .= "  <li><input name=\"quest_$id\" type=\"text\" /></li>\n";
+            $expout .= "  <li>" . html_writer::label(get_string('answer'), 'quest_'.$id, false, array('class' => 'accesshide'));
+            $expout .= "    <input id=\"quest_$id\" name=\"quest_$id\" type=\"text\" /></li>\n";
             $expout .= "</ul>\n";
             break;
         case NUMERICAL:
             $expout .= "<ul class=\"numerical\">\n";
-            $expout .= "  <li><input name=\"quest_$id\" type=\"text\" /></li>\n";
+            $expout .= "  <li>" . html_writer::label(get_string('answer'), 'quest_'.$id, false, array('class' => 'accesshide'));
+            $expout .= "    <input id=\"quest_$id\" name=\"quest_$id\" type=\"text\" /></li>\n";
             $expout .= "</ul>\n";
             break;
         case MATCH:
@@ -114,7 +116,8 @@ class qformat_xhtml extends qformat_default {
             shuffle( $ans_list ); // random display order
 
             // build drop down for answers
-            $dropdown = "<select name=\"quest_$id\">\n";
+            $dropdown = html_writer::label(get_string('selectansweroption'), 'quest_'.$id, false, array('class' => 'accesshide'));
+            $dropdown .= "<select id=\"quest_$id\" name=\"quest_$id\">\n";
             foreach($ans_list as $ans) {
                 $dropdown .= "<option value=\"" . s($ans) . "\">" . s($ans) . "</option>\n";
             }
diff --git a/question/format/xhtml/lang/en/qformat_xhtml.php b/question/format/xhtml/lang/en/qformat_xhtml.php
index e5492eb..ddbadfc 100644
--- a/question/format/xhtml/lang/en/qformat_xhtml.php
+++ b/question/format/xhtml/lang/en/qformat_xhtml.php
@@ -26,3 +26,4 @@
 $string['pluginname'] = 'XHTML format';
 $string['pluginname_help'] = 'XHTML format enables all questions in the category to be exported to a single page of strict XHTML for possible use in another application.';
 $string['pluginname_link'] = 'qformat/xhtml';
+$string['selectansweroption'] = 'Select answer option';
diff --git a/question/type/calculated/lang/en/qtype_calculated.php b/question/type/calculated/lang/en/qtype_calculated.php
index 36e2d1d..a27d9be 100644
--- a/question/type/calculated/lang/en/qtype_calculated.php
+++ b/question/type/calculated/lang/en/qtype_calculated.php
@@ -49,6 +49,7 @@ $string['datasetrole']= ' The wild cards <strong>{x..}</strong> will be substitu
 $string['decimals'] = 'with {$a}';
 $string['deleteitem'] = 'Delete item';
 $string['deletelastitem'] = 'Delete last item';
+$string['distributionoption'] = 'Select distribution option';
 $string['editdatasets'] = 'Edit the wildcards datasets';
 $string['editdatasets_help'] = 'Wildcard values may be created by entering a number in each wild card field then clicking the add button. To automatically generate 10 or more values, select the number of values required before clicking the add button. A uniform distribution means any value between the limits is equally likely to be generated; a loguniform distribution means that values towards the lower limit are more likely.';
 $string['editdatasets_link'] = 'question/type/calculated';
@@ -79,6 +80,7 @@ $string['keptlocal1'] = 'will use the same existing private dataset as before';
 $string['keptlocal2'] = 'a file from the same question private set of files as before';
 $string['keptlocal3'] = 'a link from the same question private set of links as before';
 $string['lastitem(s)'] = 'last items(s)';
+$string['lengthoption'] = 'Select length option';
 $string['loguniform'] = 'Loguniform';
 $string['loguniformbit'] = 'digits, from a loguniform distribution';
 $string['makecopynextpage'] = 'Next page (new question)';
diff --git a/question/type/calculated/questiontype.php b/question/type/calculated/questiontype.php
index a4655a4..c0ab753 100644
--- a/question/type/calculated/questiontype.php
+++ b/question/type/calculated/questiontype.php
@@ -751,11 +751,13 @@ class qtype_calculated extends question_type {
                     ? 'decimals'
                     : 'significantfigures'), 'qtype_calculated', $i);
             }
-            $menu1 = html_writer::select($lengthoptions, 'calclength[]', $regs[4], null);
+            $menu1 = html_writer::label(get_string('lengthoption', 'qtype_calculated'), 'menucalclength', false, array('class' => 'accesshide'));
+            $menu1 .= html_writer::select($lengthoptions, 'calclength[]', $regs[4], null);
 
             $options = array('uniform' => get_string('uniformbit', 'qtype_calculated'),
                     'loguniform' => get_string('loguniformbit', 'qtype_calculated'));
-            $menu2 = html_writer::select($options, 'calcdistribution[]', $regs[1], null);
+            $menu2 = html_writer::label(get_string('distributionoption', 'qtype_calculated'), 'menucalcdistribution', false, array('class' => 'accesshide'));
+            $menu2 .= html_writer::select($options, 'calcdistribution[]', $regs[1], null);
             return '<input type="submit" onclick="'
                 . "getElementById('addform').regenerateddefid.value='$defid'; return true;"
                 .'" value="'. get_string('generatevalue', 'qtype_calculated') . '"/><br/>'
diff --git a/question/type/essay/lang/en/qtype_essay.php b/question/type/essay/lang/en/qtype_essay.php
index 2e8d524..735a968 100644
--- a/question/type/essay/lang/en/qtype_essay.php
+++ b/question/type/essay/lang/en/qtype_essay.php
@@ -38,3 +38,4 @@ $string['pluginnameediting'] = 'Editing an Essay question';
 $string['pluginnamesummary'] = 'Allows a response of a few sentences or paragraphs. This must then be graded manually.';
 $string['responsefieldlines'] = 'Input box size';
 $string['responseformat'] = 'Response format';
+$string['selectanswerformat'] = 'Select answer format';
diff --git a/question/type/essay/renderer.php b/question/type/essay/renderer.php
index ac2bac9..a189b24 100644
--- a/question/type/essay/renderer.php
+++ b/question/type/essay/renderer.php
@@ -219,12 +219,13 @@ class qtype_essay_format_editor_renderer extends plugin_renderer_base {
                 array('id' => $id, 'name' => $inputname, 'rows' => $lines, 'cols' => 60)));
 
         $output .= html_writer::start_tag('div');
-        if (count($formats == 1)) {
+        if (count($formats) == 1) {
             reset($formats);
             $output .= html_writer::empty_tag('input', array('type' => 'hidden',
                     'name' => $inputname . 'format', 'value' => key($formats)));
 
         } else {
+            $output .= html_writer::label(get_string('selectanswerformat'), 'menu' . $inputname . 'format', false, array("class" => 'accesshide'));
             $output .= html_writer::select($formats, $inputname . 'format', $responseformat, '');
         }
         $output .= html_writer::end_tag('div');
diff --git a/question/type/match/lang/en/qtype_match.php b/question/type/match/lang/en/qtype_match.php
index a096607..4b7bc71 100644
--- a/question/type/match/lang/en/qtype_match.php
+++ b/question/type/match/lang/en/qtype_match.php
@@ -40,3 +40,4 @@ $string['pluginname_link'] = 'question/type/match';
 $string['pluginnameadding'] = 'Adding a Matching question';
 $string['pluginnameediting'] = 'Editing a Matching question';
 $string['pluginnamesummary'] = 'The answer to each of a number of sub-question must be selected from a list of possibilities.';
+$string['selectananswer'] = 'Select an answer';
diff --git a/question/type/match/renderer.php b/question/type/match/renderer.php
index 8a3372c..0a464ef 100644
--- a/question/type/match/renderer.php
+++ b/question/type/match/renderer.php
@@ -80,6 +80,7 @@ class qtype_match_renderer extends qtype_with_combined_feedback_renderer {
             }
 
             $result .= html_writer::tag('td',
+                    html_writer::label(get_string('selectananswer', 'qtype_match'), 'menu' . $qa->get_qt_field_name('sub' . $key), false, array('class' => 'accesshide')) .
                     html_writer::select($choices, $qa->get_qt_field_name('sub' . $key), $selected,
                             array('0' => 'choose'), array('disabled' => $options->readonly)) .
                     ' ' . $feedbackimage, array('class' => $classes));
diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php
index 547a370d..b4c0650 100644
--- a/question/type/multianswer/renderer.php
+++ b/question/type/multianswer/renderer.php
@@ -223,7 +223,7 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
                 s($correctanswer->answer), $options);
 
         $output = '';
-        $output .= html_writer::start_tag('label', array('class' => 'subq'));
+        $output .= html_writer::start_tag('label', array('class' => 'subq', 'for' => $inputattributes['id']));
         $output .= html_writer::empty_tag('input', $inputattributes);
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
@@ -274,8 +274,8 @@ class qtype_multianswer_multichoice_inline_renderer
             $inputattributes['class'] = $this->feedback_class($matchinganswer->fraction);
             $feedbackimg = $this->feedback_image($matchinganswer->fraction);
         }
-
-        $select = html_writer::select($choices, $qa->get_qt_field_name($fieldname),
+        $select = html_writer::label($response, $inputattributes['id'], false, array('class' => 'accesshide'));
+        $select .= html_writer::select($choices, $qa->get_qt_field_name($fieldname),
                 $response, array('' => ''), $inputattributes);
 
         $order = $subq->get_order($qa);
diff --git a/question/type/numerical/renderer.php b/question/type/numerical/renderer.php
index 7689a2c..2486740 100644
--- a/question/type/numerical/renderer.php
+++ b/question/type/numerical/renderer.php
@@ -76,7 +76,8 @@ class qtype_numerical_renderer extends qtype_renderer {
             $inputattributes['size'] = round(strlen($placeholder) * 1.1);
         }
 
-        $input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
+        $input = html_writer::label($inputattributes['name'], $inputattributes['id'], false, array('class' => 'accesshide'));
+        $input .= html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
 
         if ($question->has_separate_unit_field()) {
             if ($question->unitdisplay == qtype_numerical::UNITRADIO) {
@@ -98,7 +99,9 @@ class qtype_numerical_renderer extends qtype_renderer {
                         array('class' => 'unitchoices'));
 
             } else if ($question->unitdisplay == qtype_numerical::UNITSELECT) {
-                $unitchoice = html_writer::select($question->ap->get_unit_options(),
+                $unitchoice = html_writer::label(get_string('selectunits', 'qtype_numerical'),
+                        'menu' . $qa->get_qt_field_name('unit'), false, array('class' => 'accesshide'));
+                $unitchoice .= html_writer::select($question->ap->get_unit_options(),
                         $qa->get_qt_field_name('unit'), $selectedunit, array(''=>'choosedots'),
                         array('disabled' => $options->readonly));
             }
diff --git a/question/type/shortanswer/renderer.php b/question/type/shortanswer/renderer.php
index e7879bf..0595b57 100644
--- a/question/type/shortanswer/renderer.php
+++ b/question/type/shortanswer/renderer.php
@@ -71,8 +71,8 @@ class qtype_shortanswer_renderer extends qtype_renderer {
             $placeholder = $matches[0];
             $inputattributes['size'] = round(strlen($placeholder) * 1.1);
         }
-
-        $input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
+        $input = html_writer::label($inputattributes['name'], $inputattributes['id'], false, array('class' => 'accesshide'));
+        $input .= html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
 
         if ($placeholder) {
             $questiontext = substr_replace($questiontext, $input,
-- 
1.7.9.5


From d3187c299a14659bd5ec5ccc3e4a243ba3659583 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 23 Aug 2012 15:54:39 +0800
Subject: [PATCH 723/903] MDL-34570 Accessibility: Adding labels on text
 inputs and selects to questions

---
 question/behaviour/rendererbase.php                |   20 ++++++++++++-------
 question/format/xhtml/format.php                   |   21 +++++++++++---------
 question/format/xhtml/lang/en/qformat_xhtml.php    |    1 -
 question/type/essay/lang/en/qtype_essay.php        |    1 -
 question/type/essay/renderer.php                   |    3 ++-
 question/type/match/lang/en/qtype_match.php        |    2 +-
 question/type/match/renderer.php                   |    4 +++-
 question/type/multianswer/renderer.php             |   11 +++++-----
 .../type/numerical/lang/en/qtype_numerical.php     |    1 +
 question/type/numerical/renderer.php               |   14 +++++++------
 question/type/shortanswer/renderer.php             |   13 +++++++-----
 11 files changed, 53 insertions(+), 38 deletions(-)

diff --git a/question/behaviour/rendererbase.php b/question/behaviour/rendererbase.php
index 78de4db..e04a638 100644
--- a/question/behaviour/rendererbase.php
+++ b/question/behaviour/rendererbase.php
@@ -86,25 +86,30 @@ abstract class qbehaviour_renderer extends plugin_renderer_base {
 
         $commenteditor = html_writer::tag('div', html_writer::tag('textarea', s($commenttext),
                 array('id' => $id, 'name' => $inputname, 'rows' => 10, 'cols' => 60)));
+        $commenteditor .= html_writer::end_tag('div');
 
-        $commenteditor .= html_writer::start_tag('div');
+        $editorformat = '';
         if (count($formats) == 1) {
             reset($formats);
-            $commenteditor .= html_writer::empty_tag('input', array('type' => 'hidden',
+            $editorformat .= html_writer::empty_tag('input', array('type' => 'hidden',
                     'name' => $inputname . 'format', 'value' => key($formats)));
-
         } else {
-            $commenteditor .= html_writer::label(get_string('formattexttype'), 'menu' . $inputname . 'format', false, array('class' => 'accesshide'));
-            $commenteditor .= html_writer::select(
-                    $formats, $inputname . 'format', $commentformat, '');
+            $editorformat = html_writer::start_tag('div', array('class' => 'fitem'));
+            $editorformat .= html_writer::start_tag('div', array('class' => 'fitemtitle'));
+            $editorformat .= html_writer::tag('label', get_string('format'), array('for'=>'menu'.$inputname.'format'));
+            $editorformat .= html_writer::end_tag('div');
+            $editorformat .= html_writer::start_tag('div', array('class' => 'felement fhtmleditor'));
+            $editorformat .= html_writer::select($formats, $inputname.'format', $commentformat, '');
+            $editorformat .= html_writer::end_tag('div');
+            $editorformat .= html_writer::end_tag('div');
         }
-        $commenteditor .= html_writer::end_tag('div');
 
         $comment = html_writer::tag('div', html_writer::tag('div',
                 html_writer::tag('label', get_string('comment', 'question'),
                 array('for' => $id)), array('class' => 'fitemtitle')) .
                 html_writer::tag('div', $commenteditor, array('class' => 'felement fhtmleditor')),
                 array('class' => 'fitem'));
+        $comment .= $editorformat;
 
         $mark = '';
         if ($qa->get_max_mark()) {
@@ -118,6 +123,7 @@ abstract class qbehaviour_renderer extends plugin_renderer_base {
                 'type' => 'text',
                 'size' => $fieldsize,
                 'name' => $markfield,
+                'id'=> $markfield
             );
             if (!is_null($currentmark)) {
                 $attributes['value'] = $qa->format_fraction_as_mark(
diff --git a/question/format/xhtml/format.php b/question/format/xhtml/format.php
index a289ae6..7c929d6 100644
--- a/question/format/xhtml/format.php
+++ b/question/format/xhtml/format.php
@@ -115,19 +115,22 @@ class qformat_xhtml extends qformat_default {
             }
             shuffle( $ans_list ); // random display order
 
-            // build drop down for answers
-            $dropdown = html_writer::label(get_string('selectansweroption'), 'quest_'.$id, false, array('class' => 'accesshide'));
-            $dropdown .= "<select id=\"quest_$id\" name=\"quest_$id\">\n";
+            // Build select options.
+            $selectoptions = '';
             foreach($ans_list as $ans) {
-                $dropdown .= "<option value=\"" . s($ans) . "\">" . s($ans) . "</option>\n";
+                $selectoptions .= "<option value=\"" . s($ans) . "\">" . s($ans) . "</option>\n";
             }
-            $dropdown .= "</select>\n";
 
-            // finally display
+            // display
+            $option = 0;
             foreach($question->options->subquestions as $subquestion) {
-              $quest_text = $this->repchar( $subquestion->questiontext );
-              $expout .= "  <li>$quest_text</li>\n";
-              $expout .= $dropdown;
+                // build drop down for answers
+                $quest_text = $this->repchar( $subquestion->questiontext );
+                $dropdown = html_writer::label(get_string('answer', 'qtype_match', $option+1), 'quest_'.$id.'_'.$option, false, array('class' => 'accesshide'));
+                $dropdown .= "<select id=\"quest_{$id}_{$option}\" name=\"quest_{$id}_{$option}\">\n".$selectoptions."</select>\n";
+                $expout .= "  <li>$quest_text</li>\n";
+                $expout .= $dropdown;
+                $option++;
             }
             $expout .= "</ul>\n";
             break;
diff --git a/question/format/xhtml/lang/en/qformat_xhtml.php b/question/format/xhtml/lang/en/qformat_xhtml.php
index ddbadfc..e5492eb 100644
--- a/question/format/xhtml/lang/en/qformat_xhtml.php
+++ b/question/format/xhtml/lang/en/qformat_xhtml.php
@@ -26,4 +26,3 @@
 $string['pluginname'] = 'XHTML format';
 $string['pluginname_help'] = 'XHTML format enables all questions in the category to be exported to a single page of strict XHTML for possible use in another application.';
 $string['pluginname_link'] = 'qformat/xhtml';
-$string['selectansweroption'] = 'Select answer option';
diff --git a/question/type/essay/lang/en/qtype_essay.php b/question/type/essay/lang/en/qtype_essay.php
index 735a968..2e8d524 100644
--- a/question/type/essay/lang/en/qtype_essay.php
+++ b/question/type/essay/lang/en/qtype_essay.php
@@ -38,4 +38,3 @@ $string['pluginnameediting'] = 'Editing an Essay question';
 $string['pluginnamesummary'] = 'Allows a response of a few sentences or paragraphs. This must then be graded manually.';
 $string['responsefieldlines'] = 'Input box size';
 $string['responseformat'] = 'Response format';
-$string['selectanswerformat'] = 'Select answer format';
diff --git a/question/type/essay/renderer.php b/question/type/essay/renderer.php
index a189b24..1905e2e 100644
--- a/question/type/essay/renderer.php
+++ b/question/type/essay/renderer.php
@@ -225,7 +225,8 @@ class qtype_essay_format_editor_renderer extends plugin_renderer_base {
                     'name' => $inputname . 'format', 'value' => key($formats)));
 
         } else {
-            $output .= html_writer::label(get_string('selectanswerformat'), 'menu' . $inputname . 'format', false, array("class" => 'accesshide'));
+            $output .= html_writer::label(get_string('format'), 'menu' . $inputname . 'format', false);
+            $output .= ' ';
             $output .= html_writer::select($formats, $inputname . 'format', $responseformat, '');
         }
         $output .= html_writer::end_tag('div');
diff --git a/question/type/match/lang/en/qtype_match.php b/question/type/match/lang/en/qtype_match.php
index 4b7bc71..5dd3c4a 100644
--- a/question/type/match/lang/en/qtype_match.php
+++ b/question/type/match/lang/en/qtype_match.php
@@ -24,6 +24,7 @@
  */
 
 $string['addmoreqblanks'] = '{no} More Sets of Blanks';
+$string['answer'] = 'Answer {$a}';
 $string['availablechoices'] = 'Available choices';
 $string['correctansweris'] = 'The correct answer is: {$a}';
 $string['filloutthreeqsandtwoas'] = 'You must provide at least two questions and three answers. You can provide extra wrong answers by giving an answer with a blank question. Entries where both the question and the answer are blank will be ignored.';
@@ -40,4 +41,3 @@ $string['pluginname_link'] = 'question/type/match';
 $string['pluginnameadding'] = 'Adding a Matching question';
 $string['pluginnameediting'] = 'Editing a Matching question';
 $string['pluginnamesummary'] = 'The answer to each of a number of sub-question must be selected from a list of possibilities.';
-$string['selectananswer'] = 'Select an answer';
diff --git a/question/type/match/renderer.php b/question/type/match/renderer.php
index 0a464ef..2cadb7e 100644
--- a/question/type/match/renderer.php
+++ b/question/type/match/renderer.php
@@ -53,6 +53,7 @@ class qtype_match_renderer extends qtype_with_combined_feedback_renderer {
         $result .= html_writer::start_tag('tbody');
 
         $parity = 0;
+        $i = 1;
         foreach ($stemorder as $key => $stemid) {
 
             $result .= html_writer::start_tag('tr', array('class' => 'r' . $parity));
@@ -80,13 +81,14 @@ class qtype_match_renderer extends qtype_with_combined_feedback_renderer {
             }
 
             $result .= html_writer::tag('td',
-                    html_writer::label(get_string('selectananswer', 'qtype_match'), 'menu' . $qa->get_qt_field_name('sub' . $key), false, array('class' => 'accesshide')) .
+                    html_writer::label(get_string('answer', 'qtype_match', $i), 'menu' . $qa->get_qt_field_name('sub' . $key), false, array('class' => 'accesshide')) .
                     html_writer::select($choices, $qa->get_qt_field_name('sub' . $key), $selected,
                             array('0' => 'choose'), array('disabled' => $options->readonly)) .
                     ' ' . $feedbackimage, array('class' => $classes));
 
             $result .= html_writer::end_tag('tr');
             $parity = 1 - $parity;
+            $i++;
         }
         $result .= html_writer::end_tag('tbody');
         $result .= html_writer::end_tag('table');
diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php
index b4c0650..86d5646 100644
--- a/question/type/multianswer/renderer.php
+++ b/question/type/multianswer/renderer.php
@@ -223,11 +223,11 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
                 s($correctanswer->answer), $options);
 
         $output = '';
-        $output .= html_writer::start_tag('label', array('class' => 'subq', 'for' => $inputattributes['id']));
+        $output .= html_writer::tag('label', get_string('answer'),
+                array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= html_writer::empty_tag('input', $inputattributes);
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
-        $output .= html_writer::end_tag('label');
 
         return $output;
     }
@@ -274,8 +274,7 @@ class qtype_multianswer_multichoice_inline_renderer
             $inputattributes['class'] = $this->feedback_class($matchinganswer->fraction);
             $feedbackimg = $this->feedback_image($matchinganswer->fraction);
         }
-        $select = html_writer::label($response, $inputattributes['id'], false, array('class' => 'accesshide'));
-        $select .= html_writer::select($choices, $qa->get_qt_field_name($fieldname),
+        $select = html_writer::select($choices, $qa->get_qt_field_name($fieldname),
                 $response, array('' => ''), $inputattributes);
 
         $order = $subq->get_order($qa);
@@ -288,11 +287,11 @@ class qtype_multianswer_multichoice_inline_renderer
                         $qa, 'question', 'answer', $rightanswer->id), $options);
 
         $output = '';
-        $output .= html_writer::start_tag('label', array('class' => 'subq'));
+        $output .= html_writer::tag('label', get_string('answer'),
+                array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= $select;
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
-        $output .= html_writer::end_tag('label');
 
         return $output;
     }
diff --git a/question/type/numerical/lang/en/qtype_numerical.php b/question/type/numerical/lang/en/qtype_numerical.php
index 75dc457..fb4784b 100644
--- a/question/type/numerical/lang/en/qtype_numerical.php
+++ b/question/type/numerical/lang/en/qtype_numerical.php
@@ -26,6 +26,7 @@
 $string['acceptederror'] = 'Accepted error';
 $string['addmoreanswerblanks'] = 'Blanks for {no} More Answers';
 $string['addmoreunitblanks'] = 'Blanks for {no} More Units';
+$string['answercolon'] = 'Answer:';
 $string['answermustbenumberorstar'] = 'The answer must be a number, for example -1.234 or 3e8, or \'*\'.';
 $string['answerno'] = 'Answer {$a}';
 $string['decfractionofquestiongrade'] = 'as a fraction (0-1) of the question grade';
diff --git a/question/type/numerical/renderer.php b/question/type/numerical/renderer.php
index 2486740..d1b7c0a 100644
--- a/question/type/numerical/renderer.php
+++ b/question/type/numerical/renderer.php
@@ -76,8 +76,7 @@ class qtype_numerical_renderer extends qtype_renderer {
             $inputattributes['size'] = round(strlen($placeholder) * 1.1);
         }
 
-        $input = html_writer::label($inputattributes['name'], $inputattributes['id'], false, array('class' => 'accesshide'));
-        $input .= html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
+        $input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
 
         if ($question->has_separate_unit_field()) {
             if ($question->unitdisplay == qtype_numerical::UNITRADIO) {
@@ -99,7 +98,7 @@ class qtype_numerical_renderer extends qtype_renderer {
                         array('class' => 'unitchoices'));
 
             } else if ($question->unitdisplay == qtype_numerical::UNITSELECT) {
-                $unitchoice = html_writer::label(get_string('selectunits', 'qtype_numerical'),
+                $unitchoice = html_writer::label(get_string('selectunit', 'qtype_numerical'),
                         'menu' . $qa->get_qt_field_name('unit'), false, array('class' => 'accesshide'));
                 $unitchoice .= html_writer::select($question->ap->get_unit_options(),
                         $qa->get_qt_field_name('unit'), $selectedunit, array(''=>'choosedots'),
@@ -114,7 +113,10 @@ class qtype_numerical_renderer extends qtype_renderer {
         }
 
         if ($placeholder) {
-            $questiontext = substr_replace($questiontext, $input,
+            $inputinplace = html_writer::tag('label', get_string('answer'),
+                    array('for' => $inputattributes['id'], 'class' => 'accesshide'));
+            $inputinplace .= $input;
+            $questiontext = substr_replace($questiontext, $inputinplace,
                     strpos($questiontext, $placeholder), strlen($placeholder));
         }
 
@@ -122,8 +124,8 @@ class qtype_numerical_renderer extends qtype_renderer {
 
         if (!$placeholder) {
             $result .= html_writer::start_tag('div', array('class' => 'ablock'));
-            $result .= get_string('answer', 'qtype_shortanswer',
-                    html_writer::tag('div', $input, array('class' => 'answer')));
+            $result .= html_writer::tag('label', get_string('answercolon', 'qtype_numerical'), array('for' => $inputattributes['id']));
+            $result .= html_writer::tag('span', $input, array('class' => 'answer'));
             $result .= html_writer::end_tag('div');
         }
 
diff --git a/question/type/shortanswer/renderer.php b/question/type/shortanswer/renderer.php
index 0595b57..cfdca17 100644
--- a/question/type/shortanswer/renderer.php
+++ b/question/type/shortanswer/renderer.php
@@ -71,11 +71,13 @@ class qtype_shortanswer_renderer extends qtype_renderer {
             $placeholder = $matches[0];
             $inputattributes['size'] = round(strlen($placeholder) * 1.1);
         }
-        $input = html_writer::label($inputattributes['name'], $inputattributes['id'], false, array('class' => 'accesshide'));
-        $input .= html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
+        $input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
 
         if ($placeholder) {
-            $questiontext = substr_replace($questiontext, $input,
+            $inputinplace = html_writer::tag('label', get_string('answer'),
+                    array('for' => $inputattributes['id'], 'class' => 'accesshide'));
+            $inputinplace .= $input;
+            $questiontext = substr_replace($questiontext, $inputinplace,
                     strpos($questiontext, $placeholder), strlen($placeholder));
         }
 
@@ -83,8 +85,9 @@ class qtype_shortanswer_renderer extends qtype_renderer {
 
         if (!$placeholder) {
             $result .= html_writer::start_tag('div', array('class' => 'ablock'));
-            $result .= get_string('answer', 'qtype_shortanswer',
-                    html_writer::tag('div', $input, array('class' => 'answer')));
+            $result .= html_writer::tag('label', get_string('answer', 'qtype_shortanswer',
+                    html_writer::tag('span', $input, array('class' => 'answer'))),
+                    array('for' => $inputattributes['id']));
             $result .= html_writer::end_tag('div');
         }
 
-- 
1.7.9.5


From 60b6b6280b8d9b3f7fdab93dc9dde9a2ca4a24e5 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 14 Aug 2012 20:24:33 +0800
Subject: [PATCH 724/903] MDL-33117 grade: added some smarts to the user
 report method inject_rowspans() to deal with
 activity conditional availability

---
 grade/report/user/lib.php |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php
index 915aefd..5b92b1c 100644
--- a/grade/report/user/lib.php
+++ b/grade/report/user/lib.php
@@ -228,6 +228,26 @@ class grade_report_user extends grade_report {
         }
         $count = 1;
         foreach ($element['children'] as $key=>$child) {
+
+            $grade_object = $child['object'];
+            // If grade object isn't hidden
+            if ($grade_object->hidden != 1) {
+
+                // If grade object is an module instance
+                if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
+
+                    $instances = $this->gtree->modinfo->get_instances();
+                    // If we can find the module instance
+                    if (!empty($instances[$grade_object->itemmodule][$grade_object->iteminstance])) {
+
+                        $cm = $instances[$grade_object->itemmodule][$grade_object->iteminstance];
+                        // Skip generating rowspans if the user cannot see the module instance
+                        if (!$cm->uservisible) {
+                            continue;
+                        }
+                    }
+                }
+            }
             $count += $this->inject_rowspans($element['children'][$key]);
         }
         $element['rowspan'] = $count;
-- 
1.7.9.5


From b865c07b69a85d6d4720dc66b8745cf8936bcdbb Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Wed, 12 Sep 2012 16:33:54 +0800
Subject: [PATCH 725/903] MDL-35665: Cherry-pick MDL-35389 : Fix an error when
 changing locked state of a assignment is changed

---
 mod/assign/lib.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index 070dc50..74cfd3b 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -757,7 +757,9 @@ function assign_get_user_grades($assign, $userid=0) {
     global $CFG;
     require_once($CFG->dirroot . '/mod/assign/locallib.php');
 
-    $assignment = new assign(null, null, null);
+    $cm = get_coursemodule_from_instance('assign', $assign->id, 0, false, MUST_EXIST);
+    $context = context_module::instance($cm->id);
+    $assignment = new assign($context, null, null);
     $assignment->set_instance($assign);
     return $assignment->get_user_grades_for_gradebook($userid);
 }
-- 
1.7.9.5


From 10839ace75f9b5c2849f1a7fc051a9ddc1c9f92a Mon Sep 17 00:00:00 2001
From: Raymond Wijaya <raymond.wijaya@netspot.com.au>
Date: Tue, 21 Aug 2012 15:50:56 +0800
Subject: [PATCH 726/903] MDL-34794_M23: Add reset course feature in 
 mod_assign (new assignment)

---
 mod/assign/lang/en/assign.php |    1 +
 mod/assign/lib.php            |   66 +++++++++++++++++++++++++++++++++++
 mod/assign/locallib.php       |   76 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)

diff --git a/mod/assign/lang/en/assign.php b/mod/assign/lang/en/assign.php
index 96c1c22..f362421 100644
--- a/mod/assign/lang/en/assign.php
+++ b/mod/assign/lang/en/assign.php
@@ -78,6 +78,7 @@ $string['couldnotfindassignmenttoupgrade'] = 'Could not find old assignment inst
 $string['currentgrade'] = 'Current grade in gradebook';
 $string['defaultplugins'] = 'Default assignment settings';
 $string['defaultplugins_help'] = 'These settings define the defaults for all new assignments.';
+$string['deleteallsubmissions'] = 'Delete all submissions';
 $string['deletepluginareyousure'] = 'Delete assignment plugin {$a}: are you sure?';
 $string['deletepluginareyousuremessage'] = 'You are about to completely delete the assignment plugin {$a}. This will completely delete everything in the database associated with this assignment plugin. Are you SURE you want to continue?';
 $string['deletingplugin'] = 'Deleting plugin {$a}.';
diff --git a/mod/assign/lib.php b/mod/assign/lib.php
index 070dc50..e370467 100644
--- a/mod/assign/lib.php
+++ b/mod/assign/lib.php
@@ -55,6 +55,72 @@ function assign_delete_instance($id) {
 }
 
 /**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * This function will remove all assignment submissions and feedbacks in the database
+ * and clean up any related data.
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function assign_reset_userdata($data) {
+    global $CFG, $DB;
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+    $status = array();
+    $params = array('courseid'=>$data->courseid);
+    $sql = "SELECT a.id FROM {assign} a WHERE a.course=:courseid";
+    $course = $DB->get_record('course', array('id'=> $data->courseid), '*', MUST_EXIST);
+    if ($assigns = $DB->get_records_sql($sql,$params)) {
+        foreach ($assigns as $assign) {
+            $cm = get_coursemodule_from_instance('assign', $assign->id, $data->courseid, false, MUST_EXIST);
+            $context = context_module::instance($cm->id);
+            $assignment = new assign($context, $cm, $course);
+            $status = array_merge($status, $assignment->reset_userdata($data));
+        }
+    }
+    return $status;
+}
+
+/**
+ * Removes all grades from gradebook
+ *
+ * @param int $courseid The ID of the course to reset
+ * @param string $type Optional type of assignment to limit the reset to a particular assignment type
+ */
+function assign_reset_gradebook($courseid, $type='') {
+    global $CFG, $DB;
+
+    $params = array('moduletype'=>'assign','courseid'=>$courseid);
+    $sql = 'SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
+            FROM {assign} a, {course_modules} cm, {modules} m
+            WHERE m.name=:moduletype AND m.id=cm.module AND cm.instance=a.id AND a.course=:courseid';
+
+    if ($assignments = $DB->get_records_sql($sql,$params)) {
+        foreach ($assignments as $assignment) {
+            assign_grade_item_update($assignment, 'reset');
+        }
+    }
+}
+
+/**
+ * Implementation of the function for printing the form elements that control
+ * whether the course reset functionality affects the assignment.
+ * @param $mform form passed by reference
+ */
+function assign_reset_course_form_definition(&$mform) {
+    $mform->addElement('header', 'assignheader', get_string('modulenameplural', 'assign'));
+    $mform->addElement('advcheckbox', 'reset_assign_submissions', get_string('deleteallsubmissions','assign'));
+}
+
+/**
+ * Course reset form defaults.
+ * @param  object $course
+ * @return array
+ */
+function assign_reset_course_form_defaults($course) {
+    return array('reset_assign_submissions'=>1);
+}
+
+/**
  * Update an assignment instance
  *
  * This is done by calling the update_instance() method of the assignment type class
diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 8ba72d4..7238b70 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -506,6 +506,82 @@ class assign {
     }
 
     /**
+    * Actual implementation of the reset course functionality, delete all the
+    * assignment submissions for course $data->courseid.
+    *
+    * @param $data the data submitted from the reset course.
+    * @return array status array
+    */
+    public function reset_userdata($data) {
+        global $CFG,$DB;
+
+        $componentstr = get_string('modulenameplural', 'assign');
+        $status = array();
+
+        $fs = get_file_storage();
+        if (!empty($data->reset_assign_submissions)) {
+            // Delete files associated with this assignment.
+            foreach ($this->submissionplugins as $plugin) {
+                $fileareas = array();
+                $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+                $fileareas = $plugin->get_file_areas();
+                foreach ($fileareas as $filearea) {
+                    $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+                }
+
+                if (!$plugin->delete_instance()) {
+                    $status[] = array('component'=>$componentstr,
+                                      'item'=>get_string('deleteallsubmissions','assign'),
+                                      'error'=>$plugin->get_error());
+                }
+            }
+
+            foreach ($this->feedbackplugins as $plugin) {
+                $fileareas = array();
+                $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+                $fileareas = $plugin->get_file_areas();
+                foreach ($fileareas as $filearea) {
+                    $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+                }
+
+                if (!$plugin->delete_instance()) {
+                    $status[] = array('component'=>$componentstr,
+                                      'item'=>get_string('deleteallsubmissions','assign'),
+                                      'error'=>$plugin->get_error());
+                }
+            }
+
+            $assignssql = "SELECT a.id
+                             FROM {assign} a
+                           WHERE a.course=:course";
+            $params = array ("course" => $data->courseid);
+
+            $DB->delete_records_select('assign_submission', "assignment IN ($assignssql)", $params);
+            $status[] = array('component'=>$componentstr,
+                              'item'=>get_string('deleteallsubmissions','assign'),
+                              'error'=>false);
+
+            if (empty($data->reset_gradebook_grades)) {
+                // Remove all grades from gradebook.
+                require_once($CFG->dirroot.'/mod/assign/lib.php');
+                assign_reset_gradebook($data->courseid);
+            }
+        }
+        // Updating dates - shift may be negative too.
+        if ($data->timeshift) {
+            shift_course_mod_dates('assign',
+                                    array('duedate', 'allowsubmissionsfromdate'),
+                                    $data->timeshift,
+                                    $data->courseid);
+            $status[] = array('component'=>$componentstr,
+                              'item'=>get_string('datechanged'),
+                              'error'=>false);
+        }
+
+        return $status;
+    }
+
+    /**
      * Update the settings for a single plugin
      *
      * @param assign_plugin $plugin The plugin to update
-- 
1.7.9.5


From 0222cd954510a4bcfe47c3f05622e37294d51551 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 28 Sep 2012 15:28:27 +0100
Subject: [PATCH 727/903] MDL-35693 question engine: set id when saving a new
 question_attempt

---
 question/engine/datalib.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/question/engine/datalib.php b/question/engine/datalib.php
index 6fbccbf..86d58f3 100644
--- a/question/engine/datalib.php
+++ b/question/engine/datalib.php
@@ -117,6 +117,7 @@ class question_engine_data_mapper {
         $record->responsesummary = $qa->get_response_summary();
         $record->timemodified = time();
         $record->id = $this->db->insert_record('question_attempts', $record);
+        $qa->set_database_id($record->id);
 
         foreach ($qa->get_step_iterator() as $seq => $step) {
             $this->insert_question_attempt_step($step, $record->id, $seq, $context);
-- 
1.7.9.5


From 6b7cd710cdf724b1b06da252685f914047a5c011 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 29 Sep 2012 00:34:18 +0000
Subject: [PATCH 728/903] Automatically generated installer lang files

---
 install/lang/es_mx/install.php |    2 +-
 install/lang/fi/install.php    |    4 +---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/install/lang/es_mx/install.php b/install/lang/es_mx/install.php
index 91a4a09..7de314e 100644
--- a/install/lang/es_mx/install.php
+++ b/install/lang/es_mx/install.php
@@ -85,7 +85,7 @@ $string['phpversionhelp'] = '<p>Moodle requiere al menos una versión de PHP 4.3
 (En caso de 5.0.x podría también revertir a la versión 4.4.x)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['welcomep20'] = 'Si está viendo esta página es porque ha podido ejecutar el paquete <strong>{$a->packname} {$a->packversion}</strong> en su computadora. !Enhorabuena!';
-$string['welcomep30'] = 'Esta versión de <strong>{$a->installername}</strong> incluye las aplicaciones necesarias para que <strong>Moodle</strong> funcione en su computadora principalmente:';
+$string['welcomep30'] = 'Esta versión de <strong>{$a->installername}</strong> incluye las aplicaciones necesarias para que <strong>Moodle</strong> funcione en su computadora,  principalmente:';
 $string['welcomep40'] = 'El paquete también incluye <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
 $string['welcomep50'] = 'El uso de todas las aplicaciones del paquete está gobernado por sus respectivas
     licencias. El programa <strong>{$a->installername}</strong> es
diff --git a/install/lang/fi/install.php b/install/lang/fi/install.php
index cffb9b0..57673d4 100644
--- a/install/lang/fi/install.php
+++ b/install/lang/fi/install.php
@@ -82,9 +82,7 @@ $string['pathsunsecuredataroot'] = 'Dataroot-sijainti on turvallinen';
 $string['pathswrongadmindir'] = 'Admin-hakemistoa ei ole';
 $string['phpextension'] = '{$a} PHP-lisäosa';
 $string['phpversion'] = 'PHP versio';
-$string['phpversionhelp'] = '<p>Moodle vaatii vähintään PHP version 4.1.0.</p>
-<p>Käytät parhaillaan versiota {$a}</p>
-<p>Sinun täytyy päivittää PHP tai siirtää isäntä uudemman PHP version kanssa!</p>';
+$string['phpversionhelp'] = '<p>Moodle vaatii vähintään PHP-version 4.3.0 tai 5.1.0 (5.0.x sisältää monia tunnettuja ongelmia).</p> <p>Käytössäsi on versio {$a}</p> <p>Sinun pitää päivittää PHP tai siirtää palvelimelle jossa on uudempi PHP.<br /> (Jos käytössäsi on 5.0.x voit myös päivittää alaspäin 4.4.x -versioon)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['welcomep20'] = 'Näet tämän sivun koska olet onnistuneesti asentanut ja käynnistänyt <strong>{$a->packname} {$a->packversion}</strong> paketin tietokoneellasi.
 Onnittelut!';
-- 
1.7.9.5


From 2d04a1fe31f7c199d52f8f03e8247236c54ae5e2 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Sat, 29 Sep 2012 09:34:29 +0100
Subject: [PATCH 729/903] MDL-35698 quiz cron: group overrides not computed
 correctly

Thanks to Matt Petro for finding the bug in this monster SQL statement.
---
 mod/quiz/cronlib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/quiz/cronlib.php b/mod/quiz/cronlib.php
index 7913b63..9e4e6a4 100644
--- a/mod/quiz/cronlib.php
+++ b/mod/quiz/cronlib.php
@@ -117,8 +117,8 @@ class mod_quiz_overdue_attempt_updater {
            FROM {quiz_attempts} iquiza
            JOIN {quiz} quiz ON quiz.id = iquiza.quiz
       LEFT JOIN {quiz_overrides} quo ON quo.quiz = quiz.id AND quo.userid = iquiza.userid
-      LEFT JOIN {quiz_overrides} qgo ON qgo.quiz = quiz.id
-      LEFT JOIN {groups_members} gm ON gm.userid = iquiza.userid AND gm.groupid = qgo.groupid
+      LEFT JOIN {groups_members} gm ON gm.userid = iquiza.userid
+      LEFT JOIN {quiz_overrides} qgo ON qgo.quiz = quiz.id AND qgo.groupid = gm.groupid
 
           WHERE iquiza.state IN ('inprogress', 'overdue')
             AND iquiza.timemodified >= :processfrom
-- 
1.7.9.5


From d69578571023104b8e46eac9f82d66b24ff263a3 Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Thu, 5 Jul 2012 13:43:33 +0800
Subject: [PATCH 730/903] MDL-33829 - Glossary - Adding Rich Portfolio Export
 support

---
 mod/glossary/locallib.php |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/mod/glossary/locallib.php b/mod/glossary/locallib.php
index 2f0b448..c569b18 100644
--- a/mod/glossary/locallib.php
+++ b/mod/glossary/locallib.php
@@ -266,6 +266,12 @@ class glossary_entry_portfolio_caller extends portfolio_module_caller_base {
             $fs->get_area_files($context->id, 'mod_glossary', 'attachment', $this->entry->id, "timemodified", false),
             $fs->get_area_files($context->id, 'mod_glossary', 'entry', $this->entry->id, "timemodified", false)
         );
+
+        if (!empty($this->multifiles)) {
+            $this->add_format(PORTFOLIO_FORMAT_RICHHTML);
+        } else {
+            $this->add_format(PORTFOLIO_FORMAT_PLAINHTML);
+        }
     }
 
     /**
-- 
1.7.9.5


From 88852071b53d33b3a2b868a3e908bb19c74d6788 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Mon, 24 Sep 2012 17:52:52 +0800
Subject: [PATCH 731/903] MDL-33829 mod_glossary: added some smarts so
 glossary entries with an image in their description
 are classed as richhtml instead of plainhtml

---
 mod/glossary/lib.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mod/glossary/lib.php b/mod/glossary/lib.php
index 2a307bd..35e7197 100644
--- a/mod/glossary/lib.php
+++ b/mod/glossary/lib.php
@@ -1282,7 +1282,9 @@ function glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode='',$h
             }
         }
         $fs = get_file_storage();
-        if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)) {
+        if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)
+         || $files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'entry', $entry->id, "timemodified", false)) {
+
             $button->set_formats(PORTFOLIO_FORMAT_RICHHTML);
         } else {
             $button->set_formats(PORTFOLIO_FORMAT_PLAINHTML);
-- 
1.7.9.5


From 24d9d1811f8b91c43a5c604c1eb07eea7c499804 Mon Sep 17 00:00:00 2001
From: Tomasz Muras <nexor1984@gmail.com>
Date: Thu, 20 Sep 2012 17:48:14 +0200
Subject: [PATCH 732/903] MDL-35547 Detect question category pointing to
 itself as a parent.

---
 lib/questionlib.php |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index c8aeacd..5f2cfc1 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -1184,6 +1184,10 @@ function question_categorylist($categoryid) {
 
     $categorylist = array($categoryid);
     foreach ($subcategories as $subcategory) {
+        if($subcategory->id == $categoryid)
+            //prevent infinite loop
+            throw new coding_exception("Question category $categoryid points to itself as a parent.");
+        }
         $categorylist = array_merge($categorylist, question_categorylist($subcategory->id));
     }
 
-- 
1.7.9.5


From 2ade1b52f9f44ca80aff60da5ec8b325b2f8fc6f Mon Sep 17 00:00:00 2001
From: Tomasz Muras <nexor1984@gmail.com>
Date: Fri, 21 Sep 2012 22:01:06 +0200
Subject: [PATCH 733/903] MDL-35547 Detect loops in question categories.

---
 lib/questionlib.php |   26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index 5f2cfc1..c18a763 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -1179,16 +1179,24 @@ function question_add_tops($categories, $pcontexts) {
 function question_categorylist($categoryid) {
     global $DB;
 
-    $subcategories = $DB->get_records('question_categories',
-            array('parent' => $categoryid), 'sortorder ASC', 'id, 1');
-
-    $categorylist = array($categoryid);
-    foreach ($subcategories as $subcategory) {
-        if($subcategory->id == $categoryid)
-            //prevent infinite loop
-            throw new coding_exception("Question category $categoryid points to itself as a parent.");
+    //final list of category IDs
+    $categorylist = array();
+
+    //a list of category IDs to check for any sub-categories
+    $templist = array($categoryid);
+
+    while ($current = array_shift($templist)) {
+        if (isset($categorylist[$current])) {
+            throw new coding_exception("Category id=$current is already on the list - loop of categories detected.");
         }
-        $categorylist = array_merge($categorylist, question_categorylist($subcategory->id));
+
+        $subcategories = $DB->get_records('question_categories',
+                array('parent' => $current), 'sortorder ASC', 'id, 1');
+        foreach ($subcategories as $subcategory) {
+            $templist[] = $subcategory->id;
+        }
+
+        $categorylist[$current] = $current;
     }
 
     return $categorylist;
-- 
1.7.9.5


From d0bb10027b3c2c40c95387fbca5e952d6b976de6 Mon Sep 17 00:00:00 2001
From: Tomasz Muras <nexor1984@gmail.com>
Date: Sun, 23 Sep 2012 19:25:30 +0200
Subject: [PATCH 734/903] MDL-35547 Fetch more sub-categories with one SQL
 query.

---
 lib/questionlib.php |   25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/lib/questionlib.php b/lib/questionlib.php
index c18a763..311629d 100644
--- a/lib/questionlib.php
+++ b/lib/questionlib.php
@@ -1179,24 +1179,25 @@ function question_add_tops($categories, $pcontexts) {
 function question_categorylist($categoryid) {
     global $DB;
 
-    //final list of category IDs
+    // final list of category IDs
     $categorylist = array();
 
-    //a list of category IDs to check for any sub-categories
-    $templist = array($categoryid);
+    // a list of category IDs to check for any sub-categories
+    $subcategories = array($categoryid);
 
-    while ($current = array_shift($templist)) {
-        if (isset($categorylist[$current])) {
-            throw new coding_exception("Category id=$current is already on the list - loop of categories detected.");
-        }
-
-        $subcategories = $DB->get_records('question_categories',
-                array('parent' => $current), 'sortorder ASC', 'id, 1');
+    while ($subcategories) {
         foreach ($subcategories as $subcategory) {
-            $templist[] = $subcategory->id;
+            // if anything from the temporary list was added already, then we have a loop
+            if (isset($categorylist[$subcategory])) {
+                throw new coding_exception("Category id=$subcategory is already on the list - loop of categories detected.");
+            }
+            $categorylist[$subcategory] = $subcategory;
         }
 
-        $categorylist[$current] = $current;
+        list ($in, $params) = $DB->get_in_or_equal($subcategories);
+
+        $subcategories = $DB->get_records_select_menu('question_categories',
+                "parent $in", $params, NULL, 'id,id AS id2');
     }
 
     return $categorylist;
-- 
1.7.9.5


From 194e79536e576c0574568454046a1b807f6a9dab Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 6 Aug 2012 09:29:41 +1200
Subject: [PATCH 735/903] MDL-34234 course: Fixed notice causing issues in JS
 when upgrade settings for 2.3+ not run

---
 mod/resource/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/resource/lib.php b/mod/resource/lib.php
index b500784..cac3069 100644
--- a/mod/resource/lib.php
+++ b/mod/resource/lib.php
@@ -512,8 +512,8 @@ function resource_dndupload_handle($uploadinfo) {
     $data->popupwidth = $config->popupwidth;
     $data->printheading = $config->printheading;
     $data->printintro = $config->printintro;
-    $data->showsize = $config->showsize;
-    $data->showtype = $config->showtype;
+    $data->showsize = (isset($config->showsize)) ? $config->showsize : 0;
+    $data->showtype = (isset($config->showtype)) ? $config->showtype : 0;
     $data->filterfiles = $config->filterfiles;
 
     return resource_add_instance($data, null);
-- 
1.7.9.5


From af277cc994d6458bea86860846accfdccdf7847a Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sun, 30 Sep 2012 23:53:01 +0200
Subject: [PATCH 736/903] MDL-35708 - Right align user's information in quiz
 attempt review page , when in RTL mode
 (theme/standard & base)

---
 mod/quiz/styles.css |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index d07442b..3ab0f5a 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -11,6 +11,8 @@
 
 #page-mod-quiz-attempt .submitbtns,
 #page-mod-quiz-review .submitbtns {clear: left; text-align: left; padding-top: 1.5em;}
+#page-mod-quiz-attempt.dir-rtl .submitbtns,
+#page-mod-quiz-review.dir-rtl .submitbtns {text-align: right;}
 
 body.jsenabled .questionflagcheckbox {display: none;}
 
@@ -27,6 +29,7 @@ body.jsenabled .questionflagcheckbox {display: none;}
 .path-mod-quiz #user-picture img {width: auto;height: auto;float: left;}
 
 .path-mod-quiz .qnbutton {display: block; position: relative; float: left; width: 1.5em; height: 1.5em; overflow: hidden; margin: 0.3em 0.3em 0.3em 0; padding: 0; border: 1px solid #bbb; background: #ddd; text-align: center; vertical-align: middle;line-height: 1.5em !important; font-weight: bold; text-decoration: none;}
+.path-mod-quiz.dir-rtl  .qnbutton {float: right;}
 
 .path-mod-quiz .qnbutton .trafficlight,
 .path-mod-quiz .qnbutton .thispageholder {display: block; position: absolute; top: 0; bottom: 0; left: 0; right: 0;}
@@ -135,6 +138,7 @@ table.quizattemptsummary .noreviewmessage {color: gray;}
 table.quizreviewsummary {width: 100%;}
 table.quizreviewsummary th.cell {padding: 1px 0.5em 1px 1em;font-weight: bold;text-align: right;width: 10em;background: #f0f0f0;}
 table.quizreviewsummary td.cell {padding: 1px 1em 1px 0.5em;text-align: left;background: #fafafa;}
+.dir-rtl table.quizreviewsummary td.cell {text-align: right;}
 
 /** Mod quiz make comment or override grade popup. **/
 #page-mod-quiz-comment .mform {width: 100%;}
-- 
1.7.9.5


From 410d0dc2435c4bc4e6ede3b3de4b5924c7dd1a44 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Thu, 27 Sep 2012 14:29:26 +0800
Subject: [PATCH 737/903] MDL-31782 core_grade: fixed a potential infinite
 loop

---
 lib/grade/grade_category.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/grade/grade_category.php b/lib/grade/grade_category.php
index 95b99f8..3fa19ec 100644
--- a/lib/grade/grade_category.php
+++ b/lib/grade/grade_category.php
@@ -911,7 +911,10 @@ class grade_category extends grade_object {
 
                 $i = 1;
                 while ($originalindex+$i < count($grade_keys)) {
+
                     $possibleitemid = $grade_keys[$originalindex+$i];
+                    $i++;
+
                     if ($grade_values[$founditemid] != $grade_values[$possibleitemid]) {
                         // The next grade item has a different grade. Stop looking.
                         break;
@@ -928,8 +931,6 @@ class grade_category extends grade_object {
                         $founditemid = $possibleitemid;
                         // Continue searching to see if there is an even higher grademax...
                     }
-
-                    $i++;
                 }
 
                 // Now drop whatever grade item we have found
-- 
1.7.9.5


From 7ad8f468489a40bf68e472144e0e69b3bf97f58b Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Mon, 1 Oct 2012 12:53:26 +0800
Subject: [PATCH 738/903] MDL-35667 core_grade: added a new test for
 grade_category::apply_limit_rules()

---
 lib/grade/tests/grade_category_test.php |   15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/lib/grade/tests/grade_category_test.php b/lib/grade/tests/grade_category_test.php
index 727e698..e4281a0 100644
--- a/lib/grade/tests/grade_category_test.php
+++ b/lib/grade/tests/grade_category_test.php
@@ -516,6 +516,21 @@ class grade_category_testcase extends grade_base_testcase {
         $this->assertEquals(count($grades), 1);
         $this->assertEquals($grades[$this->grade_items[2]->id], 6);
 
+        // MDL-35667 - There was an infinite loop if several items had the same grade and at least one was extra credit
+        $category = new grade_category();
+        $category->droplow     = 1;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $items[$this->grade_items[1]->id]->aggregationcoef = 1; // Mark grade item 1 as "extra credit"
+        $grades = array($this->grade_items[0]->id=>1, // 1 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>1, // 1 out of 100. Extra credit. Should be retained.
+                        $this->grade_items[2]->id=>1, // 1 out of 6. Should be retained.
+                        $this->grade_items[4]->id=>1);// 1 out of 100. Should be retained.
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 3);
+        $this->assertEquals($grades[$this->grade_items[1]->id], 1);
+        $this->assertEquals($grades[$this->grade_items[2]->id], 1);
+        $this->assertEquals($grades[$this->grade_items[4]->id], 1);
+
     }
 
     /**
-- 
1.7.9.5


From 50675bf5492af688df51311f3cae118e878aadf9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Mon, 1 Oct 2012 09:51:12 +0200
Subject: [PATCH 739/903] MDL-35619 fix invalid avatars on other users page

---
 enrol/locallib.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/enrol/locallib.php b/enrol/locallib.php
index 41b7337..e923c2e 100644
--- a/enrol/locallib.php
+++ b/enrol/locallib.php
@@ -766,13 +766,15 @@ class course_enrolment_manager {
 
         $users = array();
         foreach ($userroles as $userrole) {
+            $contextid = $userrole->contextid;
+            unset($userrole->contextid); // This would collide with user avatar.
             if (!array_key_exists($userrole->id, $users)) {
                 $users[$userrole->id] = $this->prepare_user_for_display($userrole, $extrafields, $now);
             }
             $a = new stdClass;
             $a->role = $roles[$userrole->roleid]->localname;
             $changeable = ($userrole->component == '');
-            if ($userrole->contextid == $this->context->id) {
+            if ($contextid == $this->context->id) {
                 $roletext = get_string('rolefromthiscourse', 'enrol', $a);
             } else {
                 $changeable = false;
-- 
1.7.9.5


From b843f7aee2462fceeca96314a2009267303673f3 Mon Sep 17 00:00:00 2001
From: Jerome Mouneyrac <jerome@moodle.com>
Date: Wed, 26 Sep 2012 14:16:19 +0800
Subject: [PATCH 740/903] MDL-34971 PHPunit test: user/externallib.php

---
 user/tests/externallib_test.php |  347 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 347 insertions(+)
 create mode 100644 user/tests/externallib_test.php

diff --git a/user/tests/externallib_test.php b/user/tests/externallib_test.php
new file mode 100644
index 0000000..53670e98
--- /dev/null
+++ b/user/tests/externallib_test.php
@@ -0,0 +1,347 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * User external PHPunit tests
+ *
+ * @package    core_user
+ * @category   external
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 2.4
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/user/externallib.php');
+
+class core_user_external_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Test get_course_user_profiles
+     */
+    public function test_get_course_user_profiles() {
+        global $USER, $CFG;
+
+        $this->resetAfterTest(true);
+
+        $course = self::getDataGenerator()->create_course();
+        $user1 = array(
+            'username' => 'usernametest1',
+            'idnumber' => 'idnumbertest1',
+            'firstname' => 'First Name User Test 1',
+            'lastname' => 'Last Name User Test 1',
+            'email' => 'usertest1@email.com',
+            'address' => '2 Test Street Perth 6000 WA',
+            'phone1' => '01010101010',
+            'phone2' => '02020203',
+            'icq' => 'testuser1',
+            'skype' => 'testuser1',
+            'yahoo' => 'testuser1',
+            'aim' => 'testuser1',
+            'msn' => 'testuser1',
+            'department' => 'Department of user 1',
+            'institution' => 'Institution of user 1',
+            'description' => 'This is a description for user 1',
+            'descriptionformat' => FORMAT_MOODLE,
+            'city' => 'Perth',
+            'url' => 'http://moodle.org',
+            'country' => 'au'
+            );
+        $user1 = self::getDataGenerator()->create_user($user1);
+        if (!empty($CFG->usetags)) {
+            require_once($CFG->dirroot . '/user/editlib.php');
+            require_once($CFG->dirroot . '/tag/lib.php');
+            $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
+            useredit_update_interests($user1, $user1->interests);
+        }
+        $user2 = self::getDataGenerator()->create_user();
+
+        $context = context_course::instance($course->id);
+        $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id);
+
+        // Enrol the users in the course.
+        // We use the manual plugin.
+        $enrol = enrol_get_plugin('manual');
+        $enrolinstances = enrol_get_instances($course->id, true);
+        foreach ($enrolinstances as $courseenrolinstance) {
+            if ($courseenrolinstance->enrol == "manual") {
+                $instance = $courseenrolinstance;
+                break;
+            }
+        }
+        $enrol->enrol_user($instance, $user1->id, $roleid);
+        $enrol->enrol_user($instance, $user2->id, $roleid);
+        $enrol->enrol_user($instance, $USER->id, $roleid);
+
+        // Call the external function.
+        $enrolledusers = core_user_external::get_course_user_profiles(array(
+                    array('userid' => $USER->id, 'courseid' => $course->id),
+                    array('userid' => $user1->id, 'courseid' => $course->id),
+                    array('userid' => $user2->id, 'courseid' => $course->id)));
+
+        // Check we retrieve the good total number of enrolled users + no error on capability.
+        $this->assertEquals(3, count($enrolledusers));
+
+        // Do the same call as admin to receive all possible fields.
+        $this->setAdminUser();
+        $USER->email = "admin@fakeemail.com";
+
+        // Call the external function.
+        $enrolledusers = core_user_external::get_course_user_profiles(array(
+                    array('userid' => $USER->id, 'courseid' => $course->id),
+                    array('userid' => $user1->id, 'courseid' => $course->id),
+                    array('userid' => $user2->id, 'courseid' => $course->id)));
+
+        foreach($enrolledusers as $enrolleduser) {
+            if ($enrolleduser['username'] == $user1->username) {
+                $this->assertEquals($user1->idnumber, $enrolleduser['idnumber']);
+                $this->assertEquals($user1->firstname, $enrolleduser['firstname']);
+                $this->assertEquals($user1->lastname, $enrolleduser['lastname']);
+                $this->assertEquals($user1->email, $enrolleduser['email']);
+                $this->assertEquals($user1->address, $enrolleduser['address']);
+                $this->assertEquals($user1->phone1, $enrolleduser['phone1']);
+                $this->assertEquals($user1->phone2, $enrolleduser['phone2']);
+                $this->assertEquals($user1->icq, $enrolleduser['icq']);
+                $this->assertEquals($user1->skype, $enrolleduser['skype']);
+                $this->assertEquals($user1->yahoo, $enrolleduser['yahoo']);
+                $this->assertEquals($user1->aim, $enrolleduser['aim']);
+                $this->assertEquals($user1->msn, $enrolleduser['msn']);
+                $this->assertEquals($user1->department, $enrolleduser['department']);
+                $this->assertEquals($user1->institution, $enrolleduser['institution']);
+                $this->assertEquals($user1->description, $enrolleduser['description']);
+                $this->assertEquals(FORMAT_HTML, $enrolleduser['descriptionformat']);
+                $this->assertEquals($user1->city, $enrolleduser['city']);
+                $this->assertEquals($user1->country, $enrolleduser['country']);
+                $this->assertEquals($user1->url, $enrolleduser['url']);
+                if (!empty($CFG->usetags)) {
+                    $this->assertEquals(implode(', ', $user1->interests), $enrolleduser['interests']);
+                }
+            }
+        }
+    }
+
+    /**
+     * Test create_users
+     */
+    public function test_create_users() {
+         global $USER, $CFG, $DB;
+
+        $this->resetAfterTest(true);
+
+        $user1 = array(
+            'username' => 'usernametest1',
+            'password' => 'Moodle2012!',
+            'idnumber' => 'idnumbertest1',
+            'firstname' => 'First Name User Test 1',
+            'lastname' => 'Last Name User Test 1',
+            'email' => 'usertest1@email.com',
+            'description' => 'This is a description for user 1',
+            'city' => 'Perth',
+            'country' => 'au'
+            );
+
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/user:create', $context->id);
+
+        // Call the external function.
+        $createdusers = core_user_external::create_users(array($user1));
+
+        // Check we retrieve the good total number of created users + no error on capability.
+        $this->assertEquals(1, count($createdusers));
+
+        foreach($createdusers as $createduser) {
+            $dbuser = $DB->get_record('user', array('id' => $createduser['id']));
+            $this->assertEquals($dbuser->username, $user1['username']);
+            $this->assertEquals($dbuser->idnumber, $user1['idnumber']);
+            $this->assertEquals($dbuser->firstname, $user1['firstname']);
+            $this->assertEquals($dbuser->lastname, $user1['lastname']);
+            $this->assertEquals($dbuser->email, $user1['email']);
+            $this->assertEquals($dbuser->description, $user1['description']);
+            $this->assertEquals($dbuser->city, $user1['city']);
+            $this->assertEquals($dbuser->country, $user1['country']);
+        }
+
+        // Call without required capability
+        $this->unassignUserCapability('moodle/user:create', $context->id, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        $createdusers = core_user_external::create_users(array($user1));
+    }
+
+    /**
+     * Test delete_users
+     */
+    public function test_delete_users() {
+        global $USER, $CFG, $DB;
+
+        $this->resetAfterTest(true);
+
+        $user1 = self::getDataGenerator()->create_user();
+        $user2 = self::getDataGenerator()->create_user();
+
+        // Check the users were correctly created.
+        $this->assertEquals(2, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)',
+                array('userid1' => $user1->id, 'userid2' => $user2->id)));
+
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/user:delete', $context->id);
+
+        // Call the external function.
+        core_user_external::delete_users(array($user1->id, $user2->id));
+
+        // Check we retrieve no users + no error on capability.
+        $this->assertEquals(0, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)',
+                array('userid1' => $user1->id, 'userid2' => $user2->id)));
+
+        // Call without required capability.
+        $this->unassignUserCapability('moodle/user:delete', $context->id, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        core_user_external::delete_users(array($user1->id, $user2->id));
+    }
+
+    /**
+     * Test get_users_by_id
+     */
+    public function test_get_users_by_id() {
+        global $USER, $CFG;
+
+        $this->resetAfterTest(true);
+
+        $user1 = array(
+            'username' => 'usernametest1',
+            'idnumber' => 'idnumbertest1',
+            'firstname' => 'First Name User Test 1',
+            'lastname' => 'Last Name User Test 1',
+            'email' => 'usertest1@email.com',
+            'address' => '2 Test Street Perth 6000 WA',
+            'phone1' => '01010101010',
+            'phone2' => '02020203',
+            'icq' => 'testuser1',
+            'skype' => 'testuser1',
+            'yahoo' => 'testuser1',
+            'aim' => 'testuser1',
+            'msn' => 'testuser1',
+            'department' => 'Department of user 1',
+            'institution' => 'Institution of user 1',
+            'description' => 'This is a description for user 1',
+            'descriptionformat' => FORMAT_MOODLE,
+            'city' => 'Perth',
+            'url' => 'http://moodle.org',
+            'country' => 'au'
+            );
+        $user1 = self::getDataGenerator()->create_user($user1);
+        if (!empty($CFG->usetags)) {
+            require_once($CFG->dirroot . '/user/editlib.php');
+            require_once($CFG->dirroot . '/tag/lib.php');
+            $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
+            useredit_update_interests($user1, $user1->interests);
+        }
+        $user2 = self::getDataGenerator()->create_user();
+
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id);
+
+        // Call the external function.
+        $returnedusers = core_user_external::get_users_by_id(array(
+                    $USER->id, $user1->id, $user2->id));
+
+        // Check we retrieve the good total number of enrolled users + no error on capability.
+        $this->assertEquals(3, count($returnedusers));
+
+        // Do the same call as admin to receive all possible fields.
+        $this->setAdminUser();
+        $USER->email = "admin@fakeemail.com";
+
+        // Call the external function.
+        $returnedusers = core_user_external::get_users_by_id(array(
+                    $USER->id, $user1->id, $user2->id));
+
+        foreach($returnedusers as $enrolleduser) {
+            if ($enrolleduser['username'] == $user1->username) {
+                $this->assertEquals($user1->idnumber, $enrolleduser['idnumber']);
+                $this->assertEquals($user1->firstname, $enrolleduser['firstname']);
+                $this->assertEquals($user1->lastname, $enrolleduser['lastname']);
+                $this->assertEquals($user1->email, $enrolleduser['email']);
+                $this->assertEquals($user1->address, $enrolleduser['address']);
+                $this->assertEquals($user1->phone1, $enrolleduser['phone1']);
+                $this->assertEquals($user1->phone2, $enrolleduser['phone2']);
+                $this->assertEquals($user1->icq, $enrolleduser['icq']);
+                $this->assertEquals($user1->skype, $enrolleduser['skype']);
+                $this->assertEquals($user1->yahoo, $enrolleduser['yahoo']);
+                $this->assertEquals($user1->aim, $enrolleduser['aim']);
+                $this->assertEquals($user1->msn, $enrolleduser['msn']);
+                $this->assertEquals($user1->department, $enrolleduser['department']);
+                $this->assertEquals($user1->institution, $enrolleduser['institution']);
+                $this->assertEquals($user1->description, $enrolleduser['description']);
+                $this->assertEquals(FORMAT_HTML, $enrolleduser['descriptionformat']);
+                $this->assertEquals($user1->city, $enrolleduser['city']);
+                $this->assertEquals($user1->country, $enrolleduser['country']);
+                $this->assertEquals($user1->url, $enrolleduser['url']);
+                if (!empty($CFG->usetags)) {
+                    $this->assertEquals(implode(', ', $user1->interests), $enrolleduser['interests']);
+                }
+            }
+        }
+    }
+
+    /**
+     * Test update_users
+     */
+    public function test_update_users() {
+        global $USER, $CFG, $DB;
+
+        $this->resetAfterTest(true);
+
+        $user1 = self::getDataGenerator()->create_user();
+
+        $user1 = array(
+            'id' => $user1->id,
+            'username' => 'usernametest1',
+            'password' => 'Moodle2012!',
+            'idnumber' => 'idnumbertest1',
+            'firstname' => 'First Name User Test 1',
+            'lastname' => 'Last Name User Test 1',
+            'email' => 'usertest1@email.com',
+            'description' => 'This is a description for user 1',
+            'city' => 'Perth',
+            'country' => 'au'
+            );
+
+        $context = context_system::instance();
+        $roleid = $this->assignUserCapability('moodle/user:update', $context->id);
+
+        // Call the external function.
+        core_user_external::update_users(array($user1));
+
+        $dbuser = $DB->get_record('user', array('id' => $user1['id']));
+        $this->assertEquals($dbuser->username, $user1['username']);
+        $this->assertEquals($dbuser->idnumber, $user1['idnumber']);
+        $this->assertEquals($dbuser->firstname, $user1['firstname']);
+        $this->assertEquals($dbuser->lastname, $user1['lastname']);
+        $this->assertEquals($dbuser->email, $user1['email']);
+        $this->assertEquals($dbuser->description, $user1['description']);
+        $this->assertEquals($dbuser->city, $user1['city']);
+        $this->assertEquals($dbuser->country, $user1['country']);
+
+        // Call without required capability.
+        $this->unassignUserCapability('moodle/user:update', $context->id, $roleid);
+        $this->setExpectedException('required_capability_exception');
+        core_user_external::update_users(array($user1));
+    }
+}
\ No newline at end of file
-- 
1.7.9.5


From 30c9794aec9bed5f754b62905adf0fb62dcfaffc Mon Sep 17 00:00:00 2001
From: Michael Aherne <Michael Aherne>
Date: Fri, 28 Sep 2012 12:31:36 +0100
Subject: [PATCH 741/903] MDL-35669 gravatar Provide default image URL to
 Gravatar

---
 admin/settings/users.php |    1 +
 lang/en/admin.php        |    2 ++
 lib/outputcomponents.php |   17 +++++++++++++++--
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/admin/settings/users.php b/admin/settings/users.php
index f317102..232745d 100644
--- a/admin/settings/users.php
+++ b/admin/settings/users.php
@@ -150,6 +150,7 @@ if ($hassiteconfig
                     'institution' => new lang_string('institution'),
                 )));
         $temp->add(new admin_setting_configcheckbox('enablegravatar', new lang_string('enablegravatar', 'admin'), new lang_string('enablegravatar_help', 'admin'), 0));
+        $temp->add(new admin_setting_configtext('gravatardefaulturl', new lang_string('gravatardefaulturl', 'admin'), new lang_string('gravatardefaulturl_help', 'admin'), 'mm'));
     }
 
     $ADMIN->add('roles', $temp);
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 5d26680..8a6a935 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -551,6 +551,8 @@ $string['googlemapkey3_help'] = 'You need to enter a special key to use Google M
 $string['gotofirst'] = 'Go to first missing string';
 $string['gradebook'] = 'Gradebook';
 $string['gradebookroles'] = 'Graded roles';
+$string['gravatardefaulturl'] = 'Gravatar default image URL';
+$string['gravatardefaulturl_help'] = 'Gravatar needs a default image to display if it is unable to find a picture for a given user. Provide a full URL for an image. If you leave this setting empty, Moodle will attempt to use the most appropriate default image for the page you are viewing. Note also that Gravatar has a number of codes which can be used to <a href="https://en.gravatar.com/site/implement/images/#default-image">generate default images</a>.';
 $string['gradeexport'] = 'Primary grade export methods';
 $string['guestroleid'] = 'Role for guest';
 $string['guestroleid_help'] = 'This role is automatically assigned to the guest user. It is also temporarily assigned to not enrolled users that enter the course via guest enrolment plugin.';
diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index a20bd7c..c29ccc2 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -384,12 +384,25 @@ class user_picture implements renderable {
             // Hash the users email address
             $md5 = md5(strtolower(trim($this->user->email)));
             // Build a gravatar URL with what we know.
+
+            // Find the best default image URL we can (MDL-35669)
+            if (empty($CFG->gravatardefaulturl)) {
+                $absoluteimagepath = $page->theme->resolve_image_location('u/'.$filename, 'core');
+                if (strpos($absoluteimagepath, $CFG->dirroot) === 0) {
+                    $gravatardefault = $CFG->wwwroot . substr($absoluteimagepath, strlen($CFG->dirroot));
+                } else {
+                    $gravatardefault = $CFG->wwwroot . '/pix/u/' . $filename . '.png';
+                }
+            } else {
+                $gravatardefault = $CFG->gravatardefaulturl;
+            }
+
             // If the currently requested page is https then we'll return an
             // https gravatar page.
             if (strpos($CFG->httpswwwroot, 'https:') === 0) {
-                return new moodle_url("https://secure.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $defaulturl->out(false)));
+                return new moodle_url("https://secure.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault));
             } else {
-                return new moodle_url("http://www.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $defaulturl->out(false)));
+                return new moodle_url("http://www.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault));
             }
         }
 
-- 
1.7.9.5


From ba804c9ea9067ade84b88a8c408f68e9b96c73b9 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 2 Oct 2012 01:19:33 +0200
Subject: [PATCH 742/903] MDL-35669 gravatar Fix secure image urls.

---
 lib/outputcomponents.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index c29ccc2..5e1cf96 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -400,6 +400,7 @@ class user_picture implements renderable {
             // If the currently requested page is https then we'll return an
             // https gravatar page.
             if (strpos($CFG->httpswwwroot, 'https:') === 0) {
+                $gravatardefault = str_replace($CFG->wwwroot, $CFG->httpswwwroot, $gravatardefault); // Replace by secure url.
                 return new moodle_url("https://secure.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault));
             } else {
                 return new moodle_url("http://www.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $gravatardefault));
-- 
1.7.9.5


From 54dd6ee7504b8bc3b3fbfdc14aa2fc4e6c415975 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 2 Oct 2012 01:33:59 +0200
Subject: [PATCH 743/903] MDL-35669 gravatar amend and complete gravatar
 tests.

---
 lib/tests/outputcomponents_test.php |   42 +++++++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 9 deletions(-)

diff --git a/lib/tests/outputcomponents_test.php b/lib/tests/outputcomponents_test.php
index c515888..d5d50bf 100644
--- a/lib/tests/outputcomponents_test.php
+++ b/lib/tests/outputcomponents_test.php
@@ -126,6 +126,7 @@ class user_picture_testcase extends advanced_testcase {
         $this->assertEquals('http://www.example.com/moodle', $CFG->wwwroot);
         $this->assertEquals($CFG->wwwroot, $CFG->httpswwwroot);
         $this->assertEquals(0, $CFG->enablegravatar);
+        $this->assertEquals('mm', $CFG->gravatardefaulturl);
 
         // create some users
         $page = new moodle_page();
@@ -197,21 +198,25 @@ class user_picture_testcase extends advanced_testcase {
         // test gravatar
         set_config('enablegravatar', 1);
 
-        $up2 = new user_picture($user2);
-        $this->assertEquals('http://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=http%3A%2F%2Fwww.example.com%2Fmoodle%2Ftheme%2Fimage.php%2Fstandard%2Fcore%2F1%2Fu%2Ff2', $up2->get_url($page, $renderer)->out(false));
-
-        // uploaded image takes precedence before gravatar
-        $up1 = new user_picture($user1);
-        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
-
         // deleted user can not have gravatar
         $user3->email = 'deleted';
         $user3->picture = 0;
         $up3 = new user_picture($user3);
         $this->assertEquals($CFG->wwwroot.'/theme/image.php/standard/core/1/u/f2', $up3->get_url($page, $renderer)->out(false));
 
+        // verify defaults to misteryman (mm)
+        $up2 = new user_picture($user2);
+        $this->assertEquals('http://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=mm', $up2->get_url($page, $renderer)->out(false));
+
+        // without gravatardefaulturl, verify we pick own file
+        set_config('gravatardefaulturl', '');
+        $up2 = new user_picture($user2);
+        $this->assertEquals('http://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=http%3A%2F%2Fwww.example.com%2Fmoodle%2Fpix%2Fu%2Ff2.png', $up2->get_url($page, $renderer)->out(false));
+        // uploaded image takes precedence before gravatar
+        $up1 = new user_picture($user1);
+        $this->assertEquals($CFG->wwwroot.'/pluginfile.php/15/user/icon/standard/f2?rev=11', $up1->get_url($page, $renderer)->out(false));
 
-        // https versions
+        // https version
         $CFG->httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
 
         $up1 = new user_picture($user1);
@@ -221,7 +226,26 @@ class user_picture_testcase extends advanced_testcase {
         $this->assertEquals($CFG->httpswwwroot.'/theme/image.php/standard/core/1/u/f2', $up3->get_url($page, $renderer)->out(false));
 
         $up2 = new user_picture($user2);
-        $this->assertEquals('https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=https%3A%2F%2Fwww.example.com%2Fmoodle%2Ftheme%2Fimage.php%2Fstandard%2Fcore%2F1%2Fu%2Ff2', $up2->get_url($page, $renderer)->out(false));
+        $this->assertEquals('https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=https%3A%2F%2Fwww.example.com%2Fmoodle%2Fpix%2Fu%2Ff2.png', $up2->get_url($page, $renderer)->out(false));
+
+        // now test gravatar with one theme having own images (afterburner)
+        $CFG->httpswwwroot = $CFG->wwwroot;
+        $this->assertTrue(file_exists("$CFG->dirroot/theme/afterburner/config.php"));
+        set_config('theme', 'afterburner');
+        $page = new moodle_page();
+        $page->set_url('/user/profile.php');
+        $page->set_context(context_system::instance());
+        $renderer = $page->get_renderer('core');
+
+        $up2 = new user_picture($user2);
+        $this->assertEquals('http://www.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=http%3A%2F%2Fwww.example.com%2Fmoodle%2Ftheme%2Fafterburner%2Fpix_core%2Fu%2Ff2.png', $up2->get_url($page, $renderer)->out(false));
+
+        // https version
+        $CFG->httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot);
+
+        $up2 = new user_picture($user2);
+        $this->assertEquals('https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?s=35&d=https%3A%2F%2Fwww.example.com%2Fmoodle%2Ftheme%2Fafterburner%2Fpix_core%2Fu%2Ff2.png', $up2->get_url($page, $renderer)->out(false));
+        // end of gravatar tests
 
         // test themed images
         set_config('enablegravatar', 0);
-- 
1.7.9.5


From bda487868e7489475151f43c77c5e3b968256696 Mon Sep 17 00:00:00 2001
From: Jody Steele <steelej@queensu.ca>
Date: Wed, 12 Sep 2012 08:06:08 -0700
Subject: [PATCH 744/903] MDL-33933 mod_forum: fix incorrect capability check

---
 mod/forum/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 9c3e801..7cfb638 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -5322,7 +5322,7 @@ function forum_user_can_see_post($forum, $discussion, $post, $user=NULL, $cm=NUL
 
         return (($userfirstpost !== false && (time() - $userfirstpost >= $CFG->maxeditingtime)) ||
                 $firstpost->id == $post->id || $post->userid == $user->id || $firstpost->userid == $user->id ||
-                has_capability('mod/forum:viewqandawithoutposting', $modcontext, $user->id, false));
+                has_capability('mod/forum:viewqandawithoutposting', $modcontext, $user->id));
     }
     return true;
 }
-- 
1.7.9.5


From 8c4fcc0e1a8eedbbed9accfcae4a9b19289469e2 Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Wed, 21 Mar 2012 10:00:16 +1030
Subject: [PATCH 745/903] enrol_manual: Set context correctly in manual
 enrolment user selector

---
 enrol/manual/manage.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/enrol/manual/manage.php b/enrol/manual/manage.php
index f7ea7e2..f458a91 100644
--- a/enrol/manual/manage.php
+++ b/enrol/manual/manage.php
@@ -64,7 +64,7 @@ $PAGE->set_heading($course->fullname);
 navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id)));
 
 // Create the user selector objects.
-$options = array('enrolid' => $enrolid);
+$options = array('enrolid' => $enrolid, 'accesscontext' => $context);
 
 $potentialuserselector = new enrol_manual_potential_participant('addselect', $options);
 $currentuserselector = new enrol_manual_current_participant('removeselect', $options);
-- 
1.7.9.5


From 5735b5a2ac8881f1bfe23c8510c5c928d295fa2c Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 2 Oct 2012 13:40:53 +0800
Subject: [PATCH 746/903] MDL-35397 Administration: changed link for 'many
 other contributors'

Previously 'many other contributors' was pointing to http://docs.moodle.org/dev/Credits
now, it will point to http://moodle.org/dev.
---
 admin/renderer.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/admin/renderer.php b/admin/renderer.php
index 3a3c2bd..56c9056 100644
--- a/admin/renderer.php
+++ b/admin/renderer.php
@@ -470,7 +470,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
                          '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
                          'Copyright &copy; 1999 onwards, Martin Dougiamas<br />'.
-                         'and <a href="http://docs.moodle.org/dev/Credits">many other contributors</a>.<br />'.
+                         'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
                          '<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
         //////////////////////////////////////////////////////////////////////////////////////////////////
 
-- 
1.7.9.5


From 08363c5c8078bd2f5fa863722acb1471293fe8a0 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 2 Oct 2012 14:19:09 +0800
Subject: [PATCH 747/903] MDL-35047 tool_xmldb: Added missing strings for
 xmldb

---
 admin/tool/xmldb/lang/en/tool_xmldb.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/admin/tool/xmldb/lang/en/tool_xmldb.php b/admin/tool/xmldb/lang/en/tool_xmldb.php
index 7b384b2..c1475be 100644
--- a/admin/tool/xmldb/lang/en/tool_xmldb.php
+++ b/admin/tool/xmldb/lang/en/tool_xmldb.php
@@ -111,10 +111,13 @@ $string['checkindexes'] = 'Check indexes';
 $string['check_indexes'] = 'Look for missing DB indexes';
 $string['checkoraclesemantics'] = 'Check semantics';
 $string['check_oracle_semantics'] = 'Look for incorrect length semantics';
+$string['duplicateindexname'] = 'Duplicate index name';
 $string['incorrectfieldname'] = 'Incorrect name';
 $string['index'] = 'Index';
 $string['indexes'] = 'Indexes';
+$string['indexnameempty'] = 'Index name is empty';
 $string['integerincorrectlength'] = 'Incorrect length for integer field';
+$string['incorrectindexname'] = 'Incorrect index name';
 $string['incorrectkeyname'] = 'Incorrect key name';
 $string['incorrecttablename'] = 'Incorrect table name';
 $string['key'] = 'Key';
-- 
1.7.9.5


From bbb553e077501dbb2ecddb676c1e285def796c31 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 2 Oct 2012 14:28:55 +0800
Subject: [PATCH 748/903] MDL-28235 form: Help button popup close
 accessibility improved

AMOS BEGIN
 CPY [close,editor],[close,form]
AMOS END
---
 lang/en/form.php          |    1 +
 lib/javascript-static.js  |    8 ++++++--
 lib/outputrenderers.php   |    2 ++
 theme/base/style/core.css |    2 ++
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/lang/en/form.php b/lang/en/form.php
index d55667d..d926cd2 100644
--- a/lang/en/form.php
+++ b/lang/en/form.php
@@ -25,6 +25,7 @@
 
 $string['addfields'] = 'Add {$a} fields to form';
 $string['advancedelement'] = 'Advanced element';
+$string['close'] = 'Close';
 $string['day'] = 'Day';
 $string['display'] = 'Display';
 $string['err_alphanumeric'] = 'You must enter only letters or numbers here.';
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 24ac3fa..cf155e7 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1385,16 +1385,19 @@ M.util.help_icon = {
         event.preventDefault();
         if (M.util.help_icon.instance === null) {
             var Y = M.util.help_icon.Y;
-            Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', function(Y) {
+            Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', 'escape', function(Y) {
                 var help_content_overlay = {
                     helplink : null,
                     overlay : null,
                     init : function() {
 
-                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img  src="'+M.util.image_url('t/delete', 'moodle')+'" /></a>');
+                        var strclose = Y.Escape.html(M.str.form.close);
+                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img src="'+M.util.image_url('t/delete', 'moodle')+'" alt="'+strclose+'" /></a>');
+                        var footerbtn = Y.Node.create('<button class="closebtn">'+strclose+'</button>');
                         // Create an overlay from markup
                         this.overlay = new Y.Overlay({
                             headerContent: closebtn,
+                            footerContent: footerbtn,
                             bodyContent: '',
                             id: 'helppopupbox',
                             width:'400px',
@@ -1404,6 +1407,7 @@ M.util.help_icon = {
                         this.overlay.render(Y.one(document.body));
 
                         closebtn.on('click', this.overlay.hide, this.overlay);
+                        footerbtn.on('click', this.overlay.hide, this.overlay);
 
                         var boundingBox = this.overlay.get("boundingBox");
 
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index dd03dc8..b49c69b 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1733,6 +1733,7 @@ class core_renderer extends renderer_base {
         $output = html_writer::tag('a', $output, $attributes);
 
         $this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+        $this->page->requires->string_for_js('close', 'form');
 
         // and finally span
         return html_writer::tag('span', $output, array('class' => 'helplink'));
@@ -1798,6 +1799,7 @@ class core_renderer extends renderer_base {
         $output = html_writer::tag('a', $output, $attributes);
 
         $this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+        $this->page->requires->string_for_js('close', 'form');
 
         // and finally span
         return html_writer::tag('span', $output, array('class' => 'helplink'));
diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 3aec3d8..33946cf 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -477,6 +477,8 @@ body.tag .managelink {padding: 5px;}
 #helppopupbox {background-color: #eee; border: 1px solid #848484;z-index: 10000 !important;}
 #helppopupbox .yui3-widget-hd {float:right;margin:3px 3px 0 0;}
 #helppopupbox .yui3-widget-bd {margin:0 1em 1em 1em;border-top:1px solid #eee;}
+#helppopupbox .yui3-widget-ft {text-align: center;}
+#helppopupbox .yui3-widget-ft .closebtn {margin:0 1em 1em 1em;}
 #helppopupbox .helpheading {font-size: 1em;}
 #helppopupbox .spinner {margin:1em;}
 
-- 
1.7.9.5


From 80f497ea40ee184ca40bfc97579fc0c9c7e4ba12 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 2 Oct 2012 14:34:15 +0800
Subject: [PATCH 749/903] MDL-28235 form: Removed close icon of help icon
 popups

---
 lib/javascript-static.js |    6 ------
 1 file changed, 6 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index cf155e7..653557b 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1392,11 +1392,9 @@ M.util.help_icon = {
                     init : function() {
 
                         var strclose = Y.Escape.html(M.str.form.close);
-                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img src="'+M.util.image_url('t/delete', 'moodle')+'" alt="'+strclose+'" /></a>');
                         var footerbtn = Y.Node.create('<button class="closebtn">'+strclose+'</button>');
                         // Create an overlay from markup
                         this.overlay = new Y.Overlay({
-                            headerContent: closebtn,
                             footerContent: footerbtn,
                             bodyContent: '',
                             id: 'helppopupbox',
@@ -1406,7 +1404,6 @@ M.util.help_icon = {
                         });
                         this.overlay.render(Y.one(document.body));
 
-                        closebtn.on('click', this.overlay.hide, this.overlay);
                         footerbtn.on('click', this.overlay.hide, this.overlay);
 
                         var boundingBox = this.overlay.get("boundingBox");
@@ -1423,9 +1420,6 @@ M.util.help_icon = {
                                 this.overlay.hide();
                             }
                         }, this);
-
-                        Y.on("key", this.close, closebtn , "down:13", this);
-                        closebtn.on('click', this.close, this);
                     },
 
                     close : function(e) {
-- 
1.7.9.5


From 1a2b3452324ff8ce29aaf46f0c0d769bd01ab39a Mon Sep 17 00:00:00 2001
From: Ruslan Kabalin <r.kabalin@lancaster.ac.uk>
Date: Tue, 2 Oct 2012 14:35:28 +0100
Subject: [PATCH 750/903] MDL-35715 course dragdrop Fix the ability to drag
 back to the empty section

---
 course/yui/dragdrop/dragdrop.js |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/course/yui/dragdrop/dragdrop.js b/course/yui/dragdrop/dragdrop.js
index f52497e..bd35bd9 100644
--- a/course/yui/dragdrop/dragdrop.js
+++ b/course/yui/dragdrop/dragdrop.js
@@ -294,13 +294,13 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                     var resources = Y.Node.create('<ul></ul>');
                     resources.addClass(CSS.SECTION);
                     sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
-                    // Define empty ul as droptarget, so that item could be moved to empty list
-                    var tar = new Y.DD.Drop({
-                        node: resources,
-                        groups: this.groups,
-                        padding: '20 0 20 0'
-                    });
                 }
+                // Define empty ul as droptarget, so that item could be moved to empty list
+                var tar = new Y.DD.Drop({
+                    node: resources,
+                    groups: this.groups,
+                    padding: '20 0 20 0'
+                });
 
                 // Initialise each resource/activity in this section
                 this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY);
-- 
1.7.9.5


From db1052ce5cbbab3e35eca8b6d01ff2d6eecb11e3 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Tue, 2 Oct 2012 15:51:45 +0100
Subject: [PATCH 751/903] MDL-35744 quiz: fix review options for Never
 submitted attempts

---
 mod/quiz/locallib.php            |    2 +-
 mod/quiz/tests/locallib_test.php |   88 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php
index fc59804..f55f590 100644
--- a/mod/quiz/locallib.php
+++ b/mod/quiz/locallib.php
@@ -987,7 +987,7 @@ function quiz_get_flag_option($attempt, $context) {
  *      IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants.
  */
 function quiz_attempt_state($quiz, $attempt) {
-    if ($attempt->state != quiz_attempt::FINISHED) {
+    if ($attempt->state == quiz_attempt::IN_PROGRESS) {
         return mod_quiz_display_options::DURING;
     } else if (time() < $attempt->timefinish + 120) {
         return mod_quiz_display_options::IMMEDIATELY_AFTER;
diff --git a/mod/quiz/tests/locallib_test.php b/mod/quiz/tests/locallib_test.php
index d058b3c..177947c 100644
--- a/mod/quiz/tests/locallib_test.php
+++ b/mod/quiz/tests/locallib_test.php
@@ -151,4 +151,92 @@ class mod_quiz_locallib_testcase extends basic_testcase {
         $this->assertEquals(1, quiz_get_slot_for_question($quiz, 1));
         $this->assertEquals(3, quiz_get_slot_for_question($quiz, 7));
     }
+
+    public function test_quiz_attempt_state_in_progress() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::IN_PROGRESS;
+        $attempt->timefinish = 0;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = 0;
+
+        $this->assertEquals(mod_quiz_display_options::DURING, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_recently_submitted() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::FINISHED;
+        $attempt->timefinish = time() - 10;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = 0;
+
+        $this->assertEquals(mod_quiz_display_options::IMMEDIATELY_AFTER, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_sumitted_quiz_never_closes() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::FINISHED;
+        $attempt->timefinish = time() - 7200;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = 0;
+
+        $this->assertEquals(mod_quiz_display_options::LATER_WHILE_OPEN, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_sumitted_quiz_closes_later() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::FINISHED;
+        $attempt->timefinish = time() - 7200;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = time() + 3600;
+
+        $this->assertEquals(mod_quiz_display_options::LATER_WHILE_OPEN, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_sumitted_quiz_closed() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::FINISHED;
+        $attempt->timefinish = time() - 7200;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = time() - 3600;
+
+        $this->assertEquals(mod_quiz_display_options::AFTER_CLOSE, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_never_sumitted_quiz_never_closes() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::ABANDONED;
+        $attempt->timefinish = 1000; // A very long time ago!
+
+        $quiz = new stdClass();
+        $quiz->timeclose = 0;
+
+        $this->assertEquals(mod_quiz_display_options::LATER_WHILE_OPEN, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_never_sumitted_quiz_closes_later() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::ABANDONED;
+        $attempt->timefinish = time() - 7200;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = time() + 3600;
+
+        $this->assertEquals(mod_quiz_display_options::LATER_WHILE_OPEN, quiz_attempt_state($quiz, $attempt));
+    }
+
+    public function test_quiz_attempt_state_never_sumitted_quiz_closed() {
+        $attempt = new stdClass();
+        $attempt->state = quiz_attempt::ABANDONED;
+        $attempt->timefinish = time() - 7200;
+
+        $quiz = new stdClass();
+        $quiz->timeclose = time() - 3600;
+
+        $this->assertEquals(mod_quiz_display_options::AFTER_CLOSE, quiz_attempt_state($quiz, $attempt));
+    }
 }
-- 
1.7.9.5


From 1c1455f29a47a6c7547e74dc8cae08694a1c07e2 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Mon, 1 Oct 2012 22:46:50 +0200
Subject: [PATCH 752/903] MDL-35723 - Align to center the "Quiz Feedback"
 label,when in RTL mode

---
 mod/quiz/styles.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index d07442b..2f8a5b4 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -113,6 +113,7 @@ table.quizattemptsummary .noreviewmessage {color: gray;}
 #page-mod-quiz-view .generalbox#feedback {width:70%;margin-left:auto;margin-right:auto;padding-bottom:15px;}
 #page-mod-quiz-view .generalbox#feedback h2 {margin: 0;}
 #page-mod-quiz-view .generalbox#feedback h3 {text-align: left;}
+#page-mod-quiz-view.dir-rtl .generalbox#feedback h3 {text-align: center;}
 #page-mod-quiz-view .generalbox#feedback .overriddennotice {text-align: center;font-size: 0.7em;}
 .quizstartbuttondiv.quizsecuremoderequired input { display: none; }
 .jsenabled .quizstartbuttondiv.quizsecuremoderequired input { display: inline; }
-- 
1.7.9.5


From 1e5b1d6dad43919b93606682ebf429f64130de1a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 3 Oct 2012 09:49:01 +0800
Subject: [PATCH 753/903] MDL-35754 libraries: openpopup() does not fail when
 window name is not set

---
 lib/javascript-static.js |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 24ac3fa..4189c37 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1190,9 +1190,12 @@ function openpopup(event, args) {
         }
     }
 
-    // Cleans window name because IE does not support funky ones.
+    // Make sure the name argument is set and valid.
     var nameregex = /[^a-z0-9_]/i;
-    if (args.name.match(nameregex)) {
+    if (typeof args.name !== 'string') {
+        args.name = '_blank';
+    } else if (args.name.match(nameregex)) {
+        // Cleans window name because IE does not support funky ones.
         args.name = args.name.replace(nameregex, '_');
         if (M.cfg.developerdebug) {
             alert('DEVELOPER NOTICE: Invalid \'name\' passed to openpopup()');
-- 
1.7.9.5


From 36c7b8665f4a141b9b0fcb251f58300b7ec8249b Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Wed, 3 Oct 2012 11:52:50 +0800
Subject: [PATCH 754/903] MDL-35763: Add ignoredirty class to drop down lists
 in assignment grading options form.

---
 mod/assign/gradingoptionsform.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mod/assign/gradingoptionsform.php b/mod/assign/gradingoptionsform.php
index 3e6e54b..b24f4fa 100644
--- a/mod/assign/gradingoptionsform.php
+++ b/mod/assign/gradingoptionsform.php
@@ -44,16 +44,17 @@ class mod_assign_grading_options_form extends moodleform {
     function definition() {
         $mform = $this->_form;
         $instance = $this->_customdata;
+        $dirtyclass = array('class'=>'ignoredirty');
 
         $mform->addElement('header', 'general', get_string('gradingoptions', 'assign'));
         // visible elements
         $options = array(-1=>get_string('all'),10=>'10', 20=>'20', 50=>'50', 100=>'100');
-        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
+        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options, $dirtyclass);
         $options = array('' => get_string('filternone', 'assign'),
                          ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'),
                          ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign'));
         if ($instance['submissionsenabled']) {
-            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options, $dirtyclass);
         }
 
         // quickgrading
-- 
1.7.9.5


From 113f51d7c9e52ed8e8921660724cda60342e4c85 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Mon, 1 Oct 2012 10:05:22 +0800
Subject: [PATCH 755/903] MDL-35519 mod_book: fixed the cancel import redirect
 URL

---
 mod/book/tool/importhtml/index.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/book/tool/importhtml/index.php b/mod/book/tool/importhtml/index.php
index eaae261..25ee6f7 100644
--- a/mod/book/tool/importhtml/index.php
+++ b/mod/book/tool/importhtml/index.php
@@ -60,9 +60,9 @@ $mform = new booktool_importhtml_form(null, array('id'=>$id, 'chapterid'=>$chapt
 // If data submitted, then process and store.
 if ($mform->is_cancelled()) {
     if (empty($chapter->id)) {
-        redirect("/mod/book/view.php?id=$cm->id");
+        redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id");
     } else {
-        redirect("/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
+        redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
     }
 
 } else if ($data = $mform->get_data()) {
-- 
1.7.9.5


From 1c409bfe80069dbce99cfaeb08efe7f75c4e0869 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 3 Oct 2012 17:03:35 +0800
Subject: [PATCH 756/903] MDL-35634 course: Restored alt attribute on module
 icons

---
 course/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/lib.php b/course/lib.php
index 955b58c..8081986 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1572,7 +1572,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     // Display link itself
                     echo '<a ' . $linkcss . $mod->extra . $onclick .
                             ' href="' . $url . '"><img src="' . $mod->get_icon_url() .
-                            '" class="activityicon" alt="" /> ' .
+                            '" class="activityicon" alt="' . $modulename . '" /> ' .
                             $accesstext . '<span class="instancename">' .
                             $instancename . $altname . '</span></a>';
 
-- 
1.7.9.5


From ea29e3141ad81256c847a4da70f554784f6640f7 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 3 Oct 2012 18:46:07 +0100
Subject: [PATCH 757/903] MDL-35776 user ajax: fix sort order in chrome.

It seems that Chrome orders fields of objects in order of array key.
Therefore we must stop using user.id in the PHP arrays, and instead
ensure that we use sequential numbers.

This commit fixes the user selector.

Conflicts:
	user/selector/module.js
	user/selector/search.php
---
 user/selector/module.js  |   14 ++++++++------
 user/selector/search.php |   13 ++++++++-----
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/user/selector/module.js b/user/selector/module.js
index de2f500..120fb78 100644
--- a/user/selector/module.js
+++ b/user/selector/module.js
@@ -221,8 +221,9 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
 
             // Output each optgroup.
             var count = 0;
-            for (var groupname in data.results) {
-                this.output_group(groupname, data.results[groupname], selectedusers, true);
+            for (var key in data.results) {
+                var groupdata = data.results[key];
+                this.output_group(groupdata.name, groupdata.users, selectedusers, true);
                 count++;
             }
             if (!count) {
@@ -248,13 +249,14 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
         output_group : function(groupname, users, selectedusers, processsingle) {
             var optgroup = Y.Node.create('<optgroup></optgroup>');
             var count = 0;
-            for (var userid in users) {
-                var user = users[userid];
-                var option = Y.Node.create('<option value="'+userid+'">'+user.name+'</option>');
+            for (var key in users) {
+                var user = users[key];
+                var option = Y.Node.create('<option value="'+user.id+'">'+user.name+'</option>');
                 if (user.disabled) {
                     option.set('disabled', true);
-                } else if (selectedusers===true || selectedusers[userid]) {
+                } else if (selectedusers===true || selectedusers[user.id]) {
                     option.set('selected', true);
+                    delete selectedusers[user.id];
                 } else {
                     option.set('selected', false);
                 }
diff --git a/user/selector/search.php b/user/selector/search.php
index fcaf74e..ab28274 100644
--- a/user/selector/search.php
+++ b/user/selector/search.php
@@ -78,17 +78,20 @@ if (isset($options['file'])) {
 $userselector = new $classname($name, $options);
 
 // Do the search and output the results.
-$users = $userselector->find_users($search);
-foreach ($users as &$group) {
-    foreach ($group as $user) {
+$results = $userselector->find_users($search);
+$json = array();
+foreach ($results as $groupname => $users) {
+    $groupdata = array('name' => $groupname, 'users' => array());
+    foreach ($users as $user) {
         $output = new stdClass;
         $output->id = $user->id;
         $output->name = $userselector->output_user($user);
         if (!empty($user->disabled)) {
             $output->disabled = true;
         }
-        $group[$user->id] = $output;
+        $groupdata['users'][] = $output;
     }
+    $json[] = $groupdata;
 }
 
-echo json_encode(array('results' => $users));
+echo json_encode(array('results' => $json));
-- 
1.7.9.5


From 13815377b59d692a311b86f10bf1a7ae5d199016 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 3 Oct 2012 18:46:07 +0100
Subject: [PATCH 758/903] MDL-35776 user ajax: fix sort order in chrome.

It seems that Chrome orders fields of objects in order of array key.
Therefore we must stop using user.id in the PHP arrays, and instead
ensure that we use sequential numbers.

This commit fixes the enrol UI.
---
 enrol/ajax.php        |    8 ++++++--
 enrol/manual/ajax.php |   10 +++++++---
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/enrol/ajax.php b/enrol/ajax.php
index 8a0bdfc..48b3fca 100644
--- a/enrol/ajax.php
+++ b/enrol/ajax.php
@@ -54,9 +54,9 @@ echo $OUTPUT->header(); // send headers
 
 $manager = new course_enrolment_manager($PAGE, $course);
 
-$outcome = new stdClass;
+$outcome = new stdClass();
 $outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
 $outcome->error = '';
 
 switch ($action) {
@@ -99,6 +99,10 @@ switch ($action) {
             $user->fullname = fullname($user);
             unset($user->id);
         }
+        // Chrome will display users in the order of the array keys, so we need
+        // to ensure that the results ordered array keys. Fortunately, the JavaScript
+        // does not care what the array keys are. It uses user.id where necessary.
+        $outcome->response['users'] = array_values($outcome->response['users']);
         $outcome->success = true;
         break;
     default:
diff --git a/enrol/manual/ajax.php b/enrol/manual/ajax.php
index a9d5bb7..b599b95 100644
--- a/enrol/manual/ajax.php
+++ b/enrol/manual/ajax.php
@@ -53,9 +53,9 @@ echo $OUTPUT->header(); // send headers
 
 $manager = new course_enrolment_manager($PAGE, $course);
 
-$outcome = new stdClass;
+$outcome = new stdClass();
 $outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
 $outcome->error = '';
 
 switch ($action) {
@@ -79,6 +79,10 @@ switch ($action) {
             }
             $user->extrafields = implode(', ', $fieldvalues);
         }
+        // Chrome will display users in the order of the array keys, so we need
+        // to ensure that the results ordered array keys. Fortunately, the JavaScript
+        // does not care what the array keys are. It uses user.id where necessary.
+        $outcome->response['users'] = array_values($outcome->response['users']);
         $outcome->success = true;
         break;
     case 'enrol':
@@ -135,4 +139,4 @@ switch ($action) {
         throw new enrol_ajax_exception('unknowajaxaction');
 }
 
-echo json_encode($outcome);
\ No newline at end of file
+echo json_encode($outcome);
-- 
1.7.9.5


From 0a1c7a188a6a92b5562dce3306b5f0addfb5f8e8 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 4 Oct 2012 00:35:00 +0000
Subject: [PATCH 759/903] Automatically generated installer lang files

---
 install/lang/uk/install.php |   34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 install/lang/uk/install.php

diff --git a/install/lang/uk/install.php b/install/lang/uk/install.php
new file mode 100644
index 0000000..c132e32
--- /dev/null
+++ b/install/lang/uk/install.php
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['databasehost'] = 'Сервер бази даних';
+$string['databasename'] = 'Ім’я бази даних';
-- 
1.7.9.5


From 90c6925bdbd0e401798ee52d4ba16e4847e72c08 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Thu, 4 Oct 2012 15:17:42 +0800
Subject: [PATCH 760/903] MDL-27309 Blocks: command node is taken from
 dockitem during restore

---
 blocks/dock.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/dock.js b/blocks/dock.js
index 4eff68c..3c8a31b 100644
--- a/blocks/dock.js
+++ b/blocks/dock.js
@@ -958,7 +958,7 @@ M.core_dock.genericblock.prototype = {
         placeholder.replace(this.Y.Node.getDOMNode(this.cachedcontentnode));
         this.cachedcontentnode = this.Y.one('#'+this.cachedcontentnode.get('id'));
 
-        var commands = this.cachedcontentnode.one('.title .commands');
+        var commands = dockitem.commands;
         if (commands) {
             commands.all('.hidepanelicon').remove();
             commands.all('.moveto').remove();
-- 
1.7.9.5


From e6b958d4db4ff8c938f5b867b50073f1128a8bb7 Mon Sep 17 00:00:00 2001
From: Ruslan Kabalin <r.kabalin@lancaster.ac.uk>
Date: Wed, 3 Oct 2012 13:42:10 +0100
Subject: [PATCH 761/903] MDL-35767 Fix missing target event group check

Prevent interfering between items from different groups (and no groups)
---
 lib/yui/dragdrop/dragdrop.js |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/yui/dragdrop/dragdrop.js b/lib/yui/dragdrop/dragdrop.js
index f8b664d..0772f18 100644
--- a/lib/yui/dragdrop/dragdrop.js
+++ b/lib/yui/dragdrop/dragdrop.js
@@ -167,6 +167,10 @@ YUI.add('moodle-core-dragdrop', function(Y) {
             // this.lastdroptarget (ghost node we use for indicating where to drop)
             e.drag = e.target;
             e.drop = this.lastdroptarget;
+            // Check that drag object belongs to correct group
+            if (!this.in_group(e.drag)) {
+                return;
+            }
             // Check that drop object belong to correct group
             if (!e.drop || !e.drop.inGroup(this.groups)) {
                 return;
-- 
1.7.9.5


From d1085311c91b95f49e4b0f6f6732febc91677ce1 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Thu, 4 Oct 2012 17:25:45 +0800
Subject: [PATCH 762/903] MDL-32218 Blocks: allowblockstodock is also checked
 for region dock status

---
 lib/blocklib.php |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/blocklib.php b/lib/blocklib.php
index 47885c9..9413201 100644
--- a/lib/blocklib.php
+++ b/lib/blocklib.php
@@ -454,7 +454,9 @@ class block_manager {
      * @return bool True if all of the blocks within that region are docked
      */
     public function region_completely_docked($region, $output) {
-        if (!$this->page->theme->enable_dock) {
+        global $CFG;
+        // If theme doesn't allow docking or allowblockstodock is not set, then return.
+        if (!$this->page->theme->enable_dock || empty($CFG->allowblockstodock)) {
             return false;
         }
 
-- 
1.7.9.5


From 5c3cb55b5dd144d5df093c7f9ef7cce79930cdc4 Mon Sep 17 00:00:00 2001
From: sam marshall <s.marshall@open.ac.uk>
Date: Wed, 29 Aug 2012 16:31:55 +0100
Subject: [PATCH 763/903] MDL-34228 Completion: Add capability that controls
 if a user is shown in reports

---
 lang/en/role.php      |    1 +
 lib/completionlib.php |    3 ++-
 lib/db/access.php     |    8 ++++++++
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lang/en/role.php b/lang/en/role.php
index ffbdec3..f9ab6a9 100644
--- a/lang/en/role.php
+++ b/lang/en/role.php
@@ -121,6 +121,7 @@ $string['course:changesummary'] = 'Change course summary';
 $string['course:enrolconfig'] = 'Configure enrol instances in courses';
 $string['course:enrolreview'] = 'Review course enrolments';
 $string['course:ignorefilesizelimits'] = 'Use files larger than any file size restrictions';
+$string['course:isincompletionreports'] = 'Be shown on completion reports';
 $string['course:manageactivities'] = 'Manage activities';
 $string['course:managefiles'] = 'Manage files';
 $string['course:managegrades'] = 'Manage grades';
diff --git a/lib/completionlib.php b/lib/completionlib.php
index fcd5910..fcc6f58 100644
--- a/lib/completionlib.php
+++ b/lib/completionlib.php
@@ -1069,7 +1069,8 @@ class completion_info {
         global $DB;
 
         list($enrolledsql, $params) = get_enrolled_sql(
-                context_course::instance($this->course->id), '', $groupid, true);
+                context_course::instance($this->course->id),
+                'moodle/course:isincompletionreports', $groupid, true);
 
         $sql = 'SELECT u.id, u.firstname, u.lastname, u.idnumber';
         if ($extracontext) {
diff --git a/lib/db/access.php b/lib/db/access.php
index 121750c..f2027df 100644
--- a/lib/db/access.php
+++ b/lib/db/access.php
@@ -979,6 +979,14 @@ $capabilities = array(
         )
     ),
 
+    'moodle/course:isincompletionreports' => array(
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_COURSE,
+        'archetypes' => array(
+            'student' => CAP_ALLOW,
+        ),
+    ),
+
     'moodle/course:viewscales' => array(
 
         'captype' => 'read',
-- 
1.7.9.5


From 5747c6bccd134e9982f15e4e1e5d0fa11f02ba06 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 4 Oct 2012 13:04:27 +0800
Subject: [PATCH 764/903] MDL-33646 book: Adding a notice instead of error
 when there is no content in the book

---
 mod/book/lang/en/book.php |    1 +
 mod/book/view.php         |   15 +++++++++------
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/mod/book/lang/en/book.php b/mod/book/lang/en/book.php
index 470e18e..e15de10 100644
--- a/mod/book/lang/en/book.php
+++ b/mod/book/lang/en/book.php
@@ -47,6 +47,7 @@ $string['editingchapter'] = 'Editing chapter';
 $string['chaptertitle'] = 'Chapter title';
 $string['content'] = 'Content';
 $string['subchapter'] = 'Subchapter';
+$string['nocontent'] = 'No content has been added to this book yet.';
 $string['numbering'] = 'Chapter formatting';
 $string['numbering_help'] = '* None - Chapter and subchapter titles have no formatting
 * Numbers - Chapters and subchapter titles are numbered 1, 1.1, 1.2, 2, ...
diff --git a/mod/book/view.php b/mod/book/view.php
index 91b83b8..6b9365d 100644
--- a/mod/book/view.php
+++ b/mod/book/view.php
@@ -87,13 +87,16 @@ if ($chapterid == '0') { // Go to first chapter if no given.
     }
 }
 
-if (!$chapterid or !$chapter = $DB->get_record('book_chapters', array('id'=>$chapterid, 'bookid'=>$book->id))) {
-    print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
-}
+$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
 
-// chapter is hidden for students
-if ($chapter->hidden and !$viewhidden) {
-    print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
+// No content in the book.
+if (!$chapterid) {
+    $PAGE->set_url('/mod/book/view.php', array('id' => $id));
+    notice(get_string('nocontent', 'mod_book'), $courseurl->out(false));
+}
+// Chapter doesnt exist or it is hidden for students
+if ((!$chapter = $DB->get_record('book_chapters', array('id' => $chapterid, 'bookid' => $book->id))) or ($chapter->hidden and !$viewhidden)) {
+    print_error('errorchapter', 'mod_book', $courseurl);
 }
 
 $PAGE->set_url('/mod/book/view.php', array('id'=>$id, 'chapterid'=>$chapterid));
-- 
1.7.9.5


From 8cfc92afddefd66d01e5efff2579303b1dc52cda Mon Sep 17 00:00:00 2001
From: Jason Fowler <phalacee@gmail.com>
Date: Thu, 13 Sep 2012 12:30:32 +0800
Subject: [PATCH 765/903] MDL-32184 - Course - Fixing incorrect redirect when
 toggling course edit while inside an activity --
 Patch provided by Kanika Goyal

---
 course/view.php       |    5 +++++
 lib/navigationlib.php |    2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/course/view.php b/course/view.php
index cb978d8..18f0313 100644
--- a/course/view.php
+++ b/course/view.php
@@ -20,6 +20,7 @@
     $marker      = optional_param('marker',-1 , PARAM_INT);
     $switchrole  = optional_param('switchrole',-1, PARAM_INT);
     $modchooser  = optional_param('modchooser', -1, PARAM_BOOL);
+    $return      = optional_param('return', 0, PARAM_LOCALURL);
 
     $params = array();
     if (!empty($name)) {
@@ -139,6 +140,8 @@
             // Redirect to site root if Editing is toggled on frontpage
             if ($course->id == SITEID) {
                 redirect($CFG->wwwroot .'/?redirect=0');
+            } else if (!empty($return)) {
+                redirect($CFG->wwwroot . $return);
             } else {
                 $url = new moodle_url($PAGE->url, array('notifyeditingon' => 1));
                 redirect($url);
@@ -152,6 +155,8 @@
             // Redirect to site root if Editing is toggled on frontpage
             if ($course->id == SITEID) {
                 redirect($CFG->wwwroot .'/?redirect=0');
+            } else if (!empty($return)) {
+                redirect($CFG->wwwroot . $return);
             } else {
                 redirect($PAGE->url);
             }
diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index b24c112..dcf466a 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -3561,7 +3561,7 @@ class settings_navigation extends navigation_node {
                 $baseurl->param('sesskey', sesskey());
             } else {
                 // Edit on the main course page.
-                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'sesskey'=>sesskey()));
+                $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'return'=>$this->page->url->out_as_local_url(false), 'sesskey'=>sesskey()));
             }
 
             $editurl = clone($baseurl);
-- 
1.7.9.5


From 077fde5dc5ccaef92170979a2024f31813ad3295 Mon Sep 17 00:00:00 2001
From: Jenny Gray <j.m.gray@open.ac.uk>
Date: Wed, 3 Oct 2012 09:27:36 +0100
Subject: [PATCH 766/903] MDL-35694 logs: extend course log report downloads
 with action url

---
 course/lib.php |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index ac7a957..460817c 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -531,7 +531,7 @@ function print_mnet_log($hostid, $course, $user=0, $date=0, $order="l.time ASC",
 
 function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
                         $modid, $modaction, $groupid) {
-    global $DB;
+    global $DB, $CFG;
 
     $text = get_string('course')."\t".get_string('time')."\t".get_string('ip_address')."\t".
             get_string('fullnameuser')."\t".get_string('action')."\t".get_string('info');
@@ -600,6 +600,8 @@ function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
         $firstField = format_string($courses[$log->course], true, array('context' => $coursecontext));
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info);
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+        $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action.' ('.$actionurl.')', $log->info);
         $text = implode("\t", $row);
         echo $text." \n";
     }
@@ -710,7 +712,8 @@ function print_log_xls($course, $user, $date, $order='l.time DESC', $modname,
         $myxls->write($row, 2, $log->ip, '');
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $myxls->write($row, 3, $fullname, '');
-        $myxls->write($row, 4, $log->module.' '.$log->action, '');
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+        $myxls->write($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')', '');
         $myxls->write($row, 5, $log->info, '');
 
         $row++;
@@ -823,7 +826,8 @@ function print_log_ods($course, $user, $date, $order='l.time DESC', $modname,
         $myxls->write_string($row, 2, $log->ip);
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $myxls->write_string($row, 3, $fullname);
-        $myxls->write_string($row, 4, $log->module.' '.$log->action);
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+        $myxls->write_string($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')');
         $myxls->write_string($row, 5, $log->info);
 
         $row++;
-- 
1.7.9.5


From db8e84ae1a81508dc55e705cc82489e41e495141 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 5 Oct 2012 16:20:52 +0800
Subject: [PATCH 767/903] Revert "MDL-33117 grade: added some smarts to the
 user report method inject_rowspans() to deal with
 activity conditional availability"

This reverts commit 60b6b6280b8d9b3f7fdab93dc9dde9a2ca4a24e5.
---
 grade/report/user/lib.php |   20 --------------------
 1 file changed, 20 deletions(-)

diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php
index a952b33..cd2e951 100644
--- a/grade/report/user/lib.php
+++ b/grade/report/user/lib.php
@@ -228,26 +228,6 @@ class grade_report_user extends grade_report {
         }
         $count = 1;
         foreach ($element['children'] as $key=>$child) {
-
-            $grade_object = $child['object'];
-            // If grade object isn't hidden
-            if ($grade_object->hidden != 1) {
-
-                // If grade object is an module instance
-                if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
-
-                    $instances = $this->gtree->modinfo->get_instances();
-                    // If we can find the module instance
-                    if (!empty($instances[$grade_object->itemmodule][$grade_object->iteminstance])) {
-
-                        $cm = $instances[$grade_object->itemmodule][$grade_object->iteminstance];
-                        // Skip generating rowspans if the user cannot see the module instance
-                        if (!$cm->uservisible) {
-                            continue;
-                        }
-                    }
-                }
-            }
             $count += $this->inject_rowspans($element['children'][$key]);
         }
         $element['rowspan'] = $count;
-- 
1.7.9.5


From 4abc5a1a2c2755d9f7ea60e7ae53d2f2007e33c5 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 5 Oct 2012 13:10:06 +0200
Subject: [PATCH 768/903] Revert "MDL-34257 quiz 'secure' mode: PAGE
 initialisation order issues."

This reverts commit d205afe662ba306833a525d87714d1994467dba7.
---
 mod/quiz/attempt.php |    4 ++--
 mod/quiz/review.php  |    3 +--
 mod/quiz/summary.php |    4 ++--
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php
index 1cbda08..135ae14 100644
--- a/mod/quiz/attempt.php
+++ b/mod/quiz/attempt.php
@@ -76,9 +76,8 @@ if ($attemptobj->is_finished()) {
 
 // Check the access rules.
 $accessmanager = $attemptobj->get_access_manager(time());
-$accessmanager->setup_attempt_page($PAGE);
-$output = $PAGE->get_renderer('mod_quiz');
 $messages = $accessmanager->prevent_access();
+$output = $PAGE->get_renderer('mod_quiz');
 if (!$attemptobj->is_preview_user() && $messages) {
     print_error('attempterror', 'quiz', $attemptobj->view_url(),
             $output->access_messages($messages));
@@ -121,6 +120,7 @@ $title = get_string('attempt', 'quiz', $attemptobj->get_attempt_number());
 $headtags = $attemptobj->get_html_head_contributions($page);
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
+$accessmanager->setup_attempt_page($PAGE);
 
 if ($attemptobj->is_last_page($page)) {
     $nextpage = -1;
diff --git a/mod/quiz/review.php b/mod/quiz/review.php
index eacc703..c19afaa 100644
--- a/mod/quiz/review.php
+++ b/mod/quiz/review.php
@@ -52,8 +52,6 @@ $attemptobj->check_review_capability();
 
 // Create an object to manage all the other (non-roles) access rules.
 $accessmanager = $attemptobj->get_access_manager(time());
-$accessmanager->setup_attempt_page($PAGE);
-
 $options = $attemptobj->get_display_options(true);
 
 // Check permissions.
@@ -105,6 +103,7 @@ if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
 $headtags = $attemptobj->get_html_head_contributions($page, $showall);
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
+$accessmanager->setup_attempt_page($PAGE);
 
 // Summary table start. ============================================================================
 
diff --git a/mod/quiz/summary.php b/mod/quiz/summary.php
index 822e307..303638f 100644
--- a/mod/quiz/summary.php
+++ b/mod/quiz/summary.php
@@ -52,9 +52,8 @@ if ($attemptobj->is_preview_user()) {
 
 // Check access.
 $accessmanager = $attemptobj->get_access_manager(time());
-$accessmanager->setup_attempt_page($PAGE);
-$output = $PAGE->get_renderer('mod_quiz');
 $messages = $accessmanager->prevent_access();
+$output = $PAGE->get_renderer('mod_quiz');
 if (!$attemptobj->is_preview_user() && $messages) {
     print_error('attempterror', 'quiz', $attemptobj->view_url(),
             $output->access_messages($messages));
@@ -90,6 +89,7 @@ $PAGE->blocks->add_fake_block($navbc, reset($regions));
 $PAGE->navbar->add(get_string('summaryofattempt', 'quiz'));
 $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
 $PAGE->set_heading($attemptobj->get_course()->fullname);
+$accessmanager->setup_attempt_page($PAGE);
 
 // Display the page.
 echo $output->summary_page($attemptobj, $displayoptions);
-- 
1.7.9.5


From 562dbe408e7f32afc8c7cac8b05b2d0a261c4b28 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 5 Oct 2012 13:38:50 +0200
Subject: [PATCH 769/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 48fc6b2..a5b0b9a 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.04;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.05;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20120927)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121005)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From eccf42746c99425ccd4ec4990f5de48ad6d4fcdd Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 5 Oct 2012 17:12:11 +0100
Subject: [PATCH 770/903] MDL-35395 formslib: a method to disable
 formchangechecker for a form.

---
 lib/formslib.php |   45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/lib/formslib.php b/lib/formslib.php
index 23f65cb..c81dfb7 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -1279,6 +1279,9 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
     /** @var bool Whether to display advanced elements (on page load) */
     var $_showAdvanced = null;
 
+    /** @var bool whether to automatically initialise M.formchangechecker for this form. */
+    protected $_use_form_change_checker = true;
+
     /**
      * The form name is derived from the class name of the wrapper minus the trailing form
      * It is a name with words joined by underscores whereas the id attribute is words joined by underscores.
@@ -1406,8 +1409,32 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         return $this->_showAdvanced;
     }
 
+    /**
+     * Call this method if you don't want the formchangechecker JavaScript to be
+     * automatically initialised for this form.
+     */
+    public function disable_form_change_checker() {
+        $this->_use_form_change_checker = false;
+    }
 
-   /**
+    /**
+     * If you have called {@link disable_form_change_checker()} then you can use
+     * this method to re-enable it. It is enabled by default, so normally you don't
+     * need to call this.
+     */
+    public function enable_form_change_checker() {
+        $this->_use_form_change_checker = true;
+    }
+
+    /**
+     * @return bool whether this form should automatically initialise
+     *      formchangechecker for itself.
+     */
+    public function is_form_change_checker_enabled() {
+        return $this->_use_form_change_checker;
+    }
+
+    /**
     * Accepts a renderer
     *
     * @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
@@ -2312,13 +2339,15 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
             $this->_hiddenHtml .= $form->_pageparams;
         }
 
-        $PAGE->requires->yui_module('moodle-core-formchangechecker',
-                'M.core_formchangechecker.init',
-                array(array(
-                    'formid' => $form->getAttribute('id')
-                ))
-        );
-        $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+        if ($form->is_form_change_checker_enabled()) {
+            $PAGE->requires->yui_module('moodle-core-formchangechecker',
+                    'M.core_formchangechecker.init',
+                    array(array(
+                        'formid' => $form->getAttribute('id')
+                    ))
+            );
+            $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+        }
     }
 
     /**
-- 
1.7.9.5


From 33b59af020dbf90e8bb224d64fea184bf6e0d6cc Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sat, 6 Oct 2012 01:31:19 +0100
Subject: [PATCH 771/903] MDL-35231 theme_serenity: fixed misalignment and
 styling of mod/assignment/action/edit by updating
 custommenu css in theme/serenity/style/core.css

---
 theme/serenity/style/core.css |  157 ++++++++++++++++++++---------------------
 1 file changed, 78 insertions(+), 79 deletions(-)

diff --git a/theme/serenity/style/core.css b/theme/serenity/style/core.css
index f57325a..31ea104 100644
--- a/theme/serenity/style/core.css
+++ b/theme/serenity/style/core.css
@@ -16,34 +16,34 @@ html {
     background: none;
 }
 
-body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea { 
+body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea {
     font-family: Georgia, "Times New Roman", Times, serif;
     color: #2a2513;
 }
 
-#wrapper { 
+#wrapper {
     background: #fff;
     margin: 2% 5%;
     padding: 5px;
     border: 1px solid #c1bc9d;
 }
 
-a { 
+a {
     color: #336699;
 }
 
-a:hover { 
+a:hover {
     text-decoration: underline;
 }
 
-.pagelayout-frontpage #page-content #region-main-box #region-post-box { 
+.pagelayout-frontpage #page-content #region-main-box #region-post-box {
     padding-top: 0;
 }
 
 /* Header
 ------------------------*/
 
-#page-header { 
+#page-header {
     background: #ddd6cc url([[pix:theme|header_grass]]) repeat-x 0 100%;
     margin-bottom: 5px;
 }
@@ -52,7 +52,7 @@ a:hover {
     margin-bottom: 0px;
 }
 
-.headermain { 
+.headermain {
     font-weight: normal;
     margin: 1em 0.5em 0.75em;
 }
@@ -67,10 +67,10 @@ a:hover {
     float:none;
 }
 
-/* Navbar 
+/* Navbar
 -------------------------*/
 
-.navbar { 
+.navbar {
     background: #aeb9c6 url([[pix:theme|breadcrumb]]) repeat-x 0 100%;
     padding: 5px;
 }
@@ -78,21 +78,21 @@ a:hover {
 /* Blocks
 -------------------------*/
 
-.block { 
+.block {
     border-color: #eee;
 }
 
-.block .header { 
+.block .header {
     background: #9eb1bf;
     padding-left: 5px;
 }
 
-.block .title { 
+.block .title {
     background: #867f6a;
     padding-left: 5px;
 }
 
-.block .title h2 { 
+.block .title h2 {
     background: #6e6855;
     margin: 0;
     padding: 5px;
@@ -100,24 +100,24 @@ a:hover {
     color: #fff;
 }
 
-.block_action { 
+.block_action {
     padding: 5px 0 0;
 }
 
-.block .content { 
+.block .content {
     background: #d8d2c6;
     border: 1px solid #867f6a;
 }
 
 .block .minicalendar td,
-.block .minicalendar th { 
+.block .minicalendar th {
     border-color: #d8d2c6;
 }
 
 /* Course
 ----------------------------*/
 
-.headingblock { 
+.headingblock {
     background: url([[pix:theme|headingblock]]) repeat-x 0 0;
     color: #fff;
     font-weight: normal;
@@ -142,10 +142,10 @@ a:hover {
     background: #fff;
 }
 
-/* Forums 
+/* Forums
 -----------------------------*/
 
-.forumpost .topic { 
+.forumpost .topic {
     background: #cad5e1;
     border-width: 1px;
     border-color: #eee #eee #aaa;
@@ -158,11 +158,11 @@ a:hover {
 }
 
 
-.forumpost .starter .subject { 
+.forumpost .starter .subject {
     font-weight: bold;
 }
 
-.forumpost .content { 
+.forumpost .content {
     border-color: #eee;
     border-width: 0 1px 1px;
     border-style: solid;
@@ -172,56 +172,56 @@ a:hover {
 /* Dock
 -----------------------------*/
 
-body.has_dock { 
+body.has_dock {
     margin: 0;
 }
 
-#dock { 
+#dock {
     left: 5%;
     margin-left: -29px;
     border-width: 0;
     background-color: transparent;
 }
 
-#dock .controls { 
+#dock .controls {
     bottom: auto;
     background-color: #DDD6CC;
 }
 
-#dock .dockeditem_container { 
+#dock .dockeditem_container {
     position: relative;
 }
 
-#dock .dockeditem.firstdockitem { 
+#dock .dockeditem.firstdockitem {
     margin-top: 50px;
 }
 
-#dock .dockeditem { 
+#dock .dockeditem {
     background-color: #fff;
     padding: 2px;
     padding-right: 0px;
 }
 
-#dock .dockedtitle { 
+#dock .dockedtitle {
     border-width: 0;
 }
 
-#dock .dockedtitle h2 { 
+#dock .dockedtitle h2 {
     margin: 0;
     padding: 10px 3px;
 }
 
-#dock .dockedtitle.activeitem { 
+#dock .dockedtitle.activeitem {
     background-color: #817b65;
     width: 35px;
 }
 
-#dockeditempanel { 
+#dockeditempanel {
     background-color: #817b65;
     margin-left: 5px;
 }
 
-#dockeditempanel .dockeditempanel_content { 
+#dockeditempanel .dockeditempanel_content {
     background-color: #eee9e0;
     margin: 0 3px;
     position: relative;
@@ -230,78 +230,77 @@ body.has_dock {
     border-color: #6f6856;
 }
 
-#dockeditempanel .dockeditempanel_hd { 
+#dockeditempanel .dockeditempanel_hd {
     background-image: url([[pix:theme|headingblock]]);
     border-width: 0;
 }
 
-#dockeditempanel .dockeditempanel_hd h2 { 
+#dockeditempanel .dockeditempanel_hd h2 {
     font-size: 1em;
     color: #fff;
 }
 
 /*cutom menu */
 /*YUI Reset */
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-active,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-menuvisible {background-position: -10000px -10000px;}
-.yui3-skin-sam #page .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menubuttonnav .yui3-menu-label em {background-position: right center;}
-.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {background-position: 3px center;}
-.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {background-position: 0% 50%;}
-
+#custommenu .yui3-menu-horizontal .yui3-menu-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menu-label-active,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label-menuvisible {
+    background-position: -10000px -10000px;
+}
+#custommenu .yui3-menu-label,
+#custommenu .yui3-menu .yui3-menu .yui3-menu-label,
+#custommenu .yui3-menubuttonnav .yui3-menu-label em {
+    background-position: right center;
+}
+#custommenu .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {
+    background-position: 3px center;
+}
+#custommenu .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {
+    background-position: 0% 50%;
+}
 #custommenu {
     clear: both;
     background-image: url([[pix:theme|headingblock]]);
     margin-bottom: 5px;
 }
-
-.yui3-skin-sam #page .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menuitem-content  {
+#custommenu .yui3-menu-label,
+#custommenu .yui3-menuitem-content {
     color: #fff;
     font-weight: 800;
     line-height: 30px;
 }
-
-.custom_menu_submenu .yui3-menu-label,
-.custom_menu_submenu .yui3-menuitem-content {
-    color: #000 !important;
-    text-shadow: none !important;
+#custommenu .custom_menu_submenu .yui3-menu-label,
+#custommenu .custom_menu_submenu .yui3-menuitem-content {
+    color: #333;
+    text-shadow: none;
     line-height: 25px;
 }
-
-.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-active,
-.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-menuvisible,
-.yui3-skin-sam #page .yui3-menuitem-active .yui3-menuitem-content {
+#custommenu .yui3-menu-label.yui3-menu-label-active,
+#custommenu .yui3-menu-label.yui3-menu-label-menuvisible,
+#custommenu .yui3-menuitem-active .yui3-menuitem-content {
     color: #000;
     background-color: #d8d2c6;
 }
-
-.yui3-skin-sam #page .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-content  {
-    border: none !important;
+#custommenu .yui3-menu-content,
+#custommenu .yui3-menu-content,
+#custommenu .yui3-menu .yui3-menu .yui3-menu-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-content  {
+    border: 0 none;
 }
-
-.yui3-skin-sam .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam .yui3-menu-horizontal .yui3-menuitem-content {
-    border-color:#808080;
-    border-style:solid;
-    border-width:0px 0;
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-content {
+    border: 0 none;
 }
-
-#page .custom_menu_submenu {
-    border: 2px solid #d8d2c6 !important;
+#custommenu .custom_menu_submenu {
+    border: 2px solid #d8d2c6;
     background: #fff;
-     -webkit-border-radius: 2px;
-    -moz-border-radius: 2px;
-    border-radius: 2px;
+    -webkit-border-radius: 2px;
+       -moz-border-radius: 2px;
+            border-radius: 2px;
     -webkit-box-shadow: 0px 1px 3px #ccc;
-    -moz-box-shadow: 0px 1px 3px #ccc;
-    box-shadow: 0px 1px 3px #ccc;
-}
\ No newline at end of file
+       -moz-box-shadow: 0px 1px 3px #ccc;
+            box-shadow: 0px 1px 3px #ccc;
+}
-- 
1.7.9.5


From 7c6d4ed0a7e3073163d8073142e0d84596aa31aa Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 6 Oct 2012 00:34:00 +0000
Subject: [PATCH 772/903] Automatically generated installer lang files

---
 install/lang/he/error.php   |    4 ++--
 install/lang/he/install.php |    8 +++-----
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/install/lang/he/error.php b/install/lang/he/error.php
index 6a2e548..fe6d20a 100644
--- a/install/lang/he/error.php
+++ b/install/lang/he/error.php
@@ -33,13 +33,13 @@ defined('MOODLE_INTERNAL') || die();
 $string['cannotcreatelangdir'] = 'לא ניתן ליצור סיפריית שפה.';
 $string['cannotcreatetempdir'] = 'לא ניתן ליצור סיפרייה זמנית.';
 $string['cannotdownloadcomponents'] = 'לא ניתן להוריד רכיבים.';
-$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ ZIP.';
+$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ 7Zip';
 $string['cannotfindcomponent'] = 'הרכיב לא נמצא.';
 $string['cannotsavemd5file'] = 'לא ניתן לשמור קובץ md5.';
 $string['cannotsavezipfile'] = 'לא ניתן לשמור קובץ ZIP.';
 $string['cannotunzipfile'] = 'לא ניתן לפתוח את קובץ ה-ZIP.';
 $string['componentisuptodate'] = 'הרכיב מעודכן.';
-$string['downloadedfilecheckfailed'] = 'נכשלה בדיקת הקובץ המורד.';
+$string['downloadedfilecheckfailed'] = 'הקובץ אשר ירד נמצא שגוי';
 $string['invalidmd5'] = 'md5 לא חוקי';
 $string['missingrequiredfield'] = 'חסר שדה נדרש כלשהו';
 $string['remotedownloaderror'] = 'הורדת הרכיב לשרת שלך כשלה, אנא וודא את הגדרות ה-proxy שלך. תוספת PHP cURL מומלצת מאוד להתקנה.
diff --git a/install/lang/he/install.php b/install/lang/he/install.php
index d6cb0ae..52508ae 100644
--- a/install/lang/he/install.php
+++ b/install/lang/he/install.php
@@ -101,11 +101,9 @@ $string['welcomep40'] = 'החבילה כוללת בנוסף
 $string['welcomep50'] = 'השימוש בכל היישומים בחבילה זו מפוקח ע"י הרשיונות המתאימים להם. החבילה
 <strong>{$a->installername}</strong>
 השלמה היא
-<a href="http://www.opensource.org/docs/definition_plain.html"> קוד פתוח
-</a>
-והיא מבוזרת תחת רישיון
-<a>
-href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
+<a href="http://www.opensource.org/docs/definition_plain.html">קוד פתוח</a>
+והיא מופצת תחת רשיון
+<a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
 $string['welcomep60'] = 'העמודים הבאים יובילו אותך בצורה פשוטה דרך כמה צעדים לעיצוב הגדרות <strong>Moodle</strong> במחשבך.
 תוכל לאשר את הגדרות  ברירת המחדל או, באפשרותך, לשנותם לפי צרכיך.';
 $string['welcomep70'] = 'הקש על לחצן ה"המשך" למטה כדי להמשיך עם הגדרת ה-<strong>Moodle</strong>';
-- 
1.7.9.5


From 2104c9fdc36fcde4f4c35352257c53fed011cf28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 2 Oct 2012 13:35:32 +0200
Subject: [PATCH 773/903] MDL-35714 run gc before test reset

---
 lib/phpunit/classes/util.php |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index b580259..3534ef8 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -544,6 +544,9 @@ class phpunit_util {
     public static function reset_all_data($logchanges = false) {
         global $DB, $CFG, $USER, $SITE, $COURSE, $PAGE, $OUTPUT, $SESSION, $GROUPLIB_CACHE;
 
+        // Release memory and indirectly call destroy() methods to release resource handles, etc.
+        gc_collect_cycles();
+
         // reset global $DB in case somebody mocked it
         $DB = self::get_global_backup('DB');
 
-- 
1.7.9.5


From f31ee1292a621477c3a0c6766603b3b4f92ccbaf Mon Sep 17 00:00:00 2001
From: Petr Skoda <commits@skodak.org>
Date: Sat, 6 Oct 2012 13:27:04 +0200
Subject: [PATCH 774/903] MDL-35382 fix random course test failures

---
 course/tests/courselib_test.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php
index 42b8057..acf5963 100644
--- a/course/tests/courselib_test.php
+++ b/course/tests/courselib_test.php
@@ -36,7 +36,7 @@ class courselib_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true));
         $oldsections = array();
         $sections = array();
-        foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) {
+        foreach ($DB->get_records('course_sections', array('course'=>$course->id), 'id') as $section) {
             $oldsections[$section->section] = $section->id;
             $sections[$section->id] = $section->section;
         }
-- 
1.7.9.5


From 26d2edcc82c2cd30f01f4207845f74b572d7caea Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Wed, 5 Sep 2012 17:54:26 +0300
Subject: [PATCH 775/903] MDL-35245 - Missing scrollbar in Activity Chooser,
 when in RTL mode

---
 theme/base/style/core.css |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 3aec3d8..4a5151b 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -905,6 +905,9 @@ sup {vertical-align: super;}
     -webkit-box-shadow: inset 0px 0px 30px 0px #CCCCCC;
     -moz-box-shadow: inset 0px 0px 30px 0px #CCCCCC;
 }
+.dir-rtl.jsenabled .choosercontainer #chooseform .alloptions {
+    max-width: 18.3em;
+}
 
 /* Settings for option rows and option subtypes */
 .choosercontainer #chooseform .moduletypetitle,
-- 
1.7.9.5


From 6f0f18a4d46dbcb6ad302b5fb30df2738a8391fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 6 Oct 2012 19:26:37 +0200
Subject: [PATCH 776/903] MDL-35839 fix invalid enrol instance delete cleanup

---
 lib/enrollib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/enrollib.php b/lib/enrollib.php
index b6736c4..bb609fc 100644
--- a/lib/enrollib.php
+++ b/lib/enrollib.php
@@ -1626,7 +1626,7 @@ abstract class enrol_plugin {
         $participants->close();
 
         // now clean up all remainders that were not removed correctly
-        $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name));
+        $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$name));
         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
 
         // finally drop the enrol row
-- 
1.7.9.5


From e9c9610f8b06ba9b5b73fa918cf83b49ebc987ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sun, 7 Oct 2012 21:03:44 +0200
Subject: [PATCH 777/903] MDL-35739 show langs on separate lines in CLI
 installer

This fixes column width issues and compatibility with RTL languages.
---
 admin/cli/install.php |   14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/admin/cli/install.php b/admin/cli/install.php
index 79ff0b7..38aa06e 100644
--- a/admin/cli/install.php
+++ b/admin/cli/install.php
@@ -240,18 +240,8 @@ echo get_string('cliinstallheader', 'install', $CFG->target_release)."\n";
 if ($interactive) {
     cli_separator();
     $languages = get_string_manager()->get_list_of_translations();
-    // format the langs nicely - 3 per line
-    $c = 0;
-    $langlist = '';
-    foreach ($languages as $key=>$lang) {
-        $c++;
-        $length = iconv_strlen($lang, 'UTF-8');
-        $padded = $lang.str_repeat(' ', 38-$length);
-        $langlist .= $padded;
-        if ($c % 3 == 0) {
-            $langlist .= "\n";
-        }
-    }
+    // Do not put the langs into columns because it is not compatible with RTL.
+    $langlist = implode("\n", $languages);
     $default = $CFG->lang;
     cli_heading(get_string('availablelangs', 'install'));
     echo $langlist."\n";
-- 
1.7.9.5


From 77957668cc9038021f35baff3186cfba9b509988 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 4 Oct 2012 16:40:26 +1300
Subject: [PATCH 778/903] MDL-26348 tool_customlang: Fixed up SQL causing
 issues in Oracle

---
 admin/tool/customlang/locallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/admin/tool/customlang/locallib.php b/admin/tool/customlang/locallib.php
index 47bbdfa..878eb4c 100644
--- a/admin/tool/customlang/locallib.php
+++ b/admin/tool/customlang/locallib.php
@@ -488,7 +488,7 @@ class tool_customlang_translator implements renderable {
         list($insql, $inparams) = $DB->get_in_or_equal($filter->component, SQL_PARAMS_NAMED);
 
         $csql = "SELECT COUNT(*)";
-        $fsql = "SELECT s.id, s.*, c.name AS component";
+        $fsql = "SELECT s.*, c.name AS component";
         $sql  = "  FROM {tool_customlang_components} c
                    JOIN {tool_customlang} s ON s.componentid = c.id
                   WHERE s.lang = :lang
-- 
1.7.9.5


From 67728fe717de8095c3ac61a3cf2251dd6b1ad9c5 Mon Sep 17 00:00:00 2001
From: Didier Raboud <didier.raboud@liip.ch>
Date: Wed, 3 Oct 2012 15:53:16 +0200
Subject: [PATCH 779/903] MDL-30754: Make sure to always display breadcrumbs
 when browsing categories.

---
 lib/navigationlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/navigationlib.php b/lib/navigationlib.php
index b24c112..9ba6f13 100644
--- a/lib/navigationlib.php
+++ b/lib/navigationlib.php
@@ -1197,7 +1197,7 @@ class global_navigation extends navigation_node {
                 break;
             case CONTEXT_COURSECAT :
                 // This has already been loaded we just need to map the variable
-                if ($showcategories) {
+                if ($this->show_categories()) {
                     $this->load_all_categories($this->page->context->instanceid, true);
                 }
                 break;
-- 
1.7.9.5


From f062a78344d90365f1f9b3b9c9080f10173ca929 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 8 Oct 2012 09:45:27 +1300
Subject: [PATCH 780/903] MDL-32326 dock: Clarified use of CSS rotation

---
 blocks/dock.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/blocks/dock.js b/blocks/dock.js
index 4eff68c..abd4132 100644
--- a/blocks/dock.js
+++ b/blocks/dock.js
@@ -505,7 +505,7 @@ M.core_dock.fixTitleOrientation = function(item, title, text) {
             break;
     }
 
-    if (Y.UA.ie > 7) {
+    if (Y.UA.ie == 8) {
         // IE8 can flip the text via CSS but not handle SVG
         title.setContent(text);
         title.setAttribute('style', 'writing-mode: tb-rl; filter: flipV flipH;display:inline;');
-- 
1.7.9.5


From cd2a0bf71557b4fa525a0644bc2b9f61d22a7c7b Mon Sep 17 00:00:00 2001
From: Davo Smith <git@davosmith.co.uk>
Date: Wed, 3 Oct 2012 08:46:55 +0100
Subject: [PATCH 781/903] MDL-35288 drag and drop upload - adjust error
 message text when attempting to upload a folder

---
 repository/upload/lang/en/repository_upload.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/repository/upload/lang/en/repository_upload.php b/repository/upload/lang/en/repository_upload.php
index 1d5664d..1a0210a 100644
--- a/repository/upload/lang/en/repository_upload.php
+++ b/repository/upload/lang/en/repository_upload.php
@@ -34,4 +34,4 @@ $string['upload_error_no_file'] = 'No file was uploaded.';
 $string['upload_error_no_tmp_dir'] = 'PHP is missing a temporary folder.';
 $string['upload_error_cant_write'] = 'Failed to write file to disk.';
 $string['upload_error_extension'] = 'A PHP extension stopped the file upload.';
-$string['upload_error_invalid_file'] = 'The file \'{$a}\' has no data in it - did you try to upload a folder?';
\ No newline at end of file
+$string['upload_error_invalid_file'] = 'The file \'{$a}\' is either empty or a folder. To upload folders zip them first.';
\ No newline at end of file
-- 
1.7.9.5


From 2741c017cb193dc2aae94bb7538d5f17175919c7 Mon Sep 17 00:00:00 2001
From: Marina Glancy <marina@moodle.com>
Date: Thu, 4 Oct 2012 11:57:43 +0800
Subject: [PATCH 782/903] MDL-35661 local plugins do not have general settings
 URL

---
 lib/pluginlib.php |    8 --------
 1 file changed, 8 deletions(-)

diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index b224d6d..470fa88 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -2514,12 +2514,4 @@ class plugininfo_local extends plugininfo_base {
     public function get_uninstall_url() {
         return new moodle_url('/admin/localplugins.php', array('delete' => $this->name, 'sesskey' => sesskey()));
     }
-
-    public function get_settings_url() {
-        if (file_exists($this->full_path('settings.php'))) {
-            return new moodle_url('/admin/settings.php', array('section' => 'local_' . $this->name));
-        } else {
-            return parent::get_settings_url();
-        }
-    }
 }
-- 
1.7.9.5


From 768a2ceafd77094496a3e3c732423e695c7c828c Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Tue, 2 Oct 2012 15:52:00 +0800
Subject: [PATCH 783/903] MDL-34448 - mod/data - Fixing separate groups
 viewing all entries.

---
 mod/data/lib.php                              |   32 +++---
 mod/data/tests/fixtures/test_data_records.csv |  132 ++++++++++++-------------
 mod/data/tests/search_test.php                |   28 ++++++
 mod/data/view.php                             |   28 +++++-
 mod/upgrade.txt                               |   11 +++
 5 files changed, 149 insertions(+), 82 deletions(-)

diff --git a/mod/data/lib.php b/mod/data/lib.php
index fc26f78..583ea73 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -3408,21 +3408,28 @@ function data_page_type_list($pagetype, $parentcontext, $currentcontext) {
 /**
  * Get all of the record ids from a database activity.
  *
- * @param int $dataid      The dataid of the database module.
- * @return array $idarray  An array of record ids
+ * @param int    $dataid      The dataid of the database module.
+ * @param object $selectdata  Contains an additional sql statement for the
+ *                            where clause for group and approval fields.
+ * @param array  $params      Parameters that coincide with the sql statement.
+ * @return array $idarray     An array of record ids
  */
-function data_get_all_recordids($dataid) {
+function data_get_all_recordids($dataid, $selectdata = '', $params = null) {
     global $DB;
-    $initsql = 'SELECT c.recordid
-                  FROM {data_fields} f,
-                       {data_content} c
-                 WHERE f.dataid = :dataid
-                   AND f.id = c.fieldid
-              GROUP BY c.recordid';
-    $initrecord = $DB->get_recordset_sql($initsql, array('dataid' => $dataid));
+    $initsql = 'SELECT r.id
+                  FROM {data_records} r
+                 WHERE r.dataid = :dataid';
+    if ($selectdata != '') {
+        $initsql .= $selectdata;
+        $params = array_merge(array('dataid' => $dataid), $params);
+    } else {
+        $params = array('dataid' => $dataid);
+    }
+    $initsql .= ' GROUP BY r.id';
+    $initrecord = $DB->get_recordset_sql($initsql, $params);
     $idarray = array();
     foreach ($initrecord as $data) {
-        $idarray[] = $data->recordid;
+        $idarray[] = $data->id;
     }
     // Close the record set and free up resources.
     $initrecord->close();
@@ -3567,8 +3574,7 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
     } else {
         list($insql, $inparam) = $DB->get_in_or_equal(array('-1'), SQL_PARAMS_NAMED);
     }
-    $nestfromsql .= ' AND c.recordid ' . $insql . $groupsql;
-    $nestfromsql = "$nestfromsql $selectdata";
+    $nestfromsql .= ' AND c.recordid ' . $insql . $selectdata . $groupsql;
     $sqlselect['sql'] = "$nestselectsql $nestfromsql $sortorder";
     $sqlselect['params'] = $inparam;
     return $sqlselect;
diff --git a/mod/data/tests/fixtures/test_data_records.csv b/mod/data/tests/fixtures/test_data_records.csv
index 5ffa5bf..f740429 100644
--- a/mod/data/tests/fixtures/test_data_records.csv
+++ b/mod/data/tests/fixtures/test_data_records.csv
@@ -1,101 +1,101 @@
 id,userid,groupid,dataid,timecreated,timemodified,approved
 1,1,0,1,1234567891,1234567892,1
-2,2,0,1,1234567891,1234567892,1
-3,3,0,1,1234567891,1234567892,1
-4,4,0,1,1234567891,1234567892,1
-5,5,0,1,1234567891,1234567892,1
-6,6,0,1,1234567891,1234567892,1
+2,2,1,1,1234567891,1234567892,1
+3,3,2,1,1234567891,1234567892,1
+4,4,1,1,1234567891,1234567892,1
+5,5,1,1,1234567891,1234567892,1
+6,6,2,1,1234567891,1234567892,1
 7,7,0,1,1234567891,1234567892,1
-8,8,0,1,1234567891,1234567892,1
-9,9,0,1,1234567891,1234567892,1
-10,10,0,1,1234567891,1234567892,1
-11,11,0,1,1234567891,1234567892,1
-12,12,0,1,1234567891,1234567892,1
-13,13,0,1,1234567891,1234567892,1
+8,8,2,1,1234567891,1234567892,1
+9,9,1,1,1234567891,1234567892,1
+10,10,1,1,1234567891,1234567892,1
+11,11,1,1,1234567891,1234567892,1
+12,12,2,1,1234567891,1234567892,1
+13,13,2,1,1234567891,1234567892,1
 14,14,0,1,1234567891,1234567892,1
-15,15,0,1,1234567891,1234567892,1
+15,15,2,1,1234567891,1234567892,1
 16,16,0,1,1234567891,1234567892,1
-17,17,0,1,1234567891,1234567892,1
-18,18,0,1,1234567891,1234567892,1
+17,17,1,1,1234567891,1234567892,1
+18,18,2,1,1234567891,1234567892,1
 19,19,0,1,1234567891,1234567892,1
-20,20,0,1,1234567891,1234567892,1
+20,20,1,1,1234567891,1234567892,1
 21,21,0,1,1234567891,1234567892,1
-22,22,0,1,1234567891,1234567892,1
+22,22,2,1,1234567891,1234567892,1
 23,23,0,1,1234567891,1234567892,1
-24,24,0,1,1234567891,1234567892,1
-25,25,0,1,1234567891,1234567892,1
+24,24,2,1,1234567891,1234567892,1
+25,25,2,1,1234567891,1234567892,1
 26,26,0,1,1234567891,1234567892,1
-27,27,0,1,1234567891,1234567892,1
-28,28,0,1,1234567891,1234567892,1
+27,27,1,1,1234567891,1234567892,1
+28,28,2,1,1234567891,1234567892,1
 29,29,0,1,1234567891,1234567892,1
-30,30,0,1,1234567891,1234567892,1
+30,30,2,1,1234567891,1234567892,1
 31,31,0,1,1234567891,1234567892,1
-32,32,0,1,1234567891,1234567892,1
-33,33,0,1,1234567891,1234567892,1
-34,34,0,1,1234567891,1234567892,1
-35,35,0,1,1234567891,1234567892,1
+32,32,1,1,1234567891,1234567892,1
+33,33,1,1,1234567891,1234567892,1
+34,34,2,1,1234567891,1234567892,1
+35,35,1,1,1234567891,1234567892,1
 36,36,0,1,1234567891,1234567892,1
 37,37,0,1,1234567891,1234567892,1
-38,38,0,1,1234567891,1234567892,1
-39,39,0,1,1234567891,1234567892,1
-40,40,0,1,1234567891,1234567892,1
+38,38,2,1,1234567891,1234567892,1
+39,39,1,1,1234567891,1234567892,1
+40,40,1,1,1234567891,1234567892,1
 41,41,0,1,1234567891,1234567892,1
-42,42,0,1,1234567891,1234567892,1
+42,42,1,1,1234567891,1234567892,1
 43,43,0,1,1234567891,1234567892,1
-44,44,0,1,1234567891,1234567892,1
+44,44,1,1,1234567891,1234567892,1
 45,45,0,1,1234567891,1234567892,1
 46,46,0,1,1234567891,1234567892,1
-47,47,0,1,1234567891,1234567892,1
+47,47,1,1,1234567891,1234567892,1
 48,48,0,1,1234567891,1234567892,1
 49,49,0,1,1234567891,1234567892,1
-50,50,0,1,1234567891,1234567892,1
+50,50,1,1,1234567891,1234567892,1
 51,51,0,1,1234567891,1234567892,1
 52,52,0,1,1234567891,1234567892,1
-53,53,0,1,1234567891,1234567892,1
-54,54,0,1,1234567891,1234567892,1
+53,53,1,1,1234567891,1234567892,1
+54,54,1,1,1234567891,1234567892,1
 55,55,0,1,1234567891,1234567892,1
-56,56,0,1,1234567891,1234567892,1
-57,57,0,1,1234567891,1234567892,1
-58,58,0,1,1234567891,1234567892,1
-59,59,0,1,1234567891,1234567892,1
-60,60,0,1,1234567891,1234567892,1
+56,56,2,1,1234567891,1234567892,1
+57,57,2,1,1234567891,1234567892,1
+58,58,2,1,1234567891,1234567892,1
+59,59,1,1,1234567891,1234567892,1
+60,60,1,1,1234567891,1234567892,1
 61,61,0,1,1234567891,1234567892,1
-62,62,0,1,1234567891,1234567892,1
+62,62,2,1,1234567891,1234567892,1
 63,63,0,1,1234567891,1234567892,1
 64,64,0,1,1234567891,1234567892,1
-65,65,0,1,1234567891,1234567892,1
-66,66,0,1,1234567891,1234567892,1
+65,65,1,1,1234567891,1234567892,1
+66,66,1,1,1234567891,1234567892,1
 67,67,0,1,1234567891,1234567892,1
 68,68,0,1,1234567891,1234567892,1
-69,69,0,1,1234567891,1234567892,1
-70,70,0,1,1234567891,1234567892,1
+69,69,2,1,1234567891,1234567892,1
+70,70,2,1,1234567891,1234567892,1
 71,71,0,1,1234567891,1234567892,1
-72,72,0,1,1234567891,1234567892,1
-73,73,0,1,1234567891,1234567892,1
+72,72,1,1,1234567891,1234567892,1
+73,73,1,1,1234567891,1234567892,1
 74,74,0,1,1234567891,1234567892,1
 75,75,0,1,1234567891,1234567892,1
-76,76,0,1,1234567891,1234567892,1
-77,77,0,1,1234567891,1234567892,1
+76,76,2,1,1234567891,1234567892,1
+77,77,2,1,1234567891,1234567892,1
 78,78,0,1,1234567891,1234567892,1
-79,79,0,1,1234567891,1234567892,1
-80,80,0,1,1234567891,1234567892,1
+79,79,1,1,1234567891,1234567892,1
+80,80,1,1,1234567891,1234567892,1
 81,81,0,1,1234567891,1234567892,1
-82,82,0,1,1234567891,1234567892,1
-83,83,0,1,1234567891,1234567892,1
-84,84,0,1,1234567891,1234567892,1
-85,85,0,1,1234567891,1234567892,1
+82,82,1,1,1234567891,1234567892,1
+83,83,1,1,1234567891,1234567892,1
+84,84,1,1,1234567891,1234567892,1
+85,85,1,1,1234567891,1234567892,1
 86,86,0,1,1234567891,1234567892,1
 87,87,0,1,1234567891,1234567892,1
 88,88,0,1,1234567891,1234567892,1
-89,89,0,1,1234567891,1234567892,1
-90,90,0,1,1234567891,1234567892,1
-91,91,0,1,1234567891,1234567892,1
-92,92,0,1,1234567891,1234567892,1
-93,93,0,1,1234567891,1234567892,1
-94,94,0,1,1234567891,1234567892,1
-95,95,0,1,1234567891,1234567892,1
-96,96,0,1,1234567891,1234567892,1
-97,97,0,1,1234567891,1234567892,1
-98,98,0,1,1234567891,1234567892,1
-99,99,0,1,1234567891,1234567892,1
-100,100,0,1,1234567891,1234567892,1
+89,89,1,1,1234567891,1234567892,1
+90,90,1,1,1234567891,1234567892,0
+91,91,2,1,1234567891,1234567892,0
+92,92,0,1,1234567891,1234567892,0
+93,93,2,1,1234567891,1234567892,0
+94,94,1,1,1234567891,1234567892,0
+95,95,1,1,1234567891,1234567892,0
+96,96,1,1,1234567891,1234567892,0
+97,97,0,1,1234567891,1234567892,0
+98,98,1,1,1234567891,1234567892,0
+99,99,2,1,1234567891,1234567892,0
+100,100,0,1,1234567891,1234567892,0
diff --git a/mod/data/tests/search_test.php b/mod/data/tests/search_test.php
index 150bc5d..2980643 100644
--- a/mod/data/tests/search_test.php
+++ b/mod/data/tests/search_test.php
@@ -71,6 +71,11 @@ class data_advanced_search_sql_test extends advanced_testcase {
     public $datarecordcount = 100;
 
     /**
+     * @var int $groupdatarecordcount  The number of records in the database in groups 0 and 1.
+     */
+    public $groupdatarecordcount = 75;
+
+    /**
      * @var array $datarecordset   Expected record IDs.
      */
     public $datarecordset = array('0' => '6');
@@ -81,6 +86,11 @@ class data_advanced_search_sql_test extends advanced_testcase {
     public $finalrecord = array();
 
     /**
+     * @var int $approvedatarecordcount  The number of approved records in the database.
+     */
+    public $approvedatarecordcount = 89;
+
+    /**
      * Set up function. In this instance we are setting up database
      * records to be used in the unit tests.
      */
@@ -169,6 +179,13 @@ class data_advanced_search_sql_test extends advanced_testcase {
      * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
      * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
      * takes that information and does a search on the database, returning a record.
+     *
+     * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to
+     * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed
+     * from the total so we should only have 75 records total.
+     *
+     * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to
+     * display the records that have been approved. In this record set we have 89 approved records.
      */
     function test_advanced_search_sql_section() {
         global $DB;
@@ -193,5 +210,16 @@ class data_advanced_search_sql_test extends advanced_testcase {
         $allparams = array_merge($html['params'], array('dataid' => $this->recorddata->id));
         $records = $DB->get_records_sql($html['sql'], $allparams);
         $this->assertEquals($records, $this->finalrecord);
+
+        // Test 5
+        $groupsql = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
+        $params = array('currentgroup' => 1);
+        $recordids = data_get_all_recordids($this->recorddata->id, $groupsql, $params);
+        $this->assertEquals($this->groupdatarecordcount, count($recordids));
+
+        // Test 6
+        $approvesql = ' AND r.approved=1 ';
+        $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params);
+        $this->assertEquals($this->approvedatarecordcount, count($recordids));
     }
 }
diff --git a/mod/data/view.php b/mod/data/view.php
index 3e9146e..1b2d85b 100644
--- a/mod/data/view.php
+++ b/mod/data/view.php
@@ -321,6 +321,13 @@
     groups_print_activity_menu($cm, $returnurl);
     $currentgroup = groups_get_activity_group($cm);
     $groupmode = groups_get_activity_groupmode($cm);
+    // If a student is not part of a group and seperate groups is enabled, we don't
+    // want them seeing all records.
+    if ($currentgroup == 0 && $groupmode == 1 && !has_capability('mod/data:manageentries', $context)) {
+        $canviewallrecords = false;
+    } else {
+        $canviewallrecords = true;
+    }
 
     // detect entries not approved yet and show hint instead of not found error
     if ($record and $data->approval and !$record->approved and $record->userid != $USER->id and !has_capability('mod/data:manageentries', $context)) {
@@ -465,7 +472,13 @@ if ($showactivity) {
             $groupselect = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
             $params['currentgroup'] = $currentgroup;
         } else {
-            $groupselect = ' ';
+            if ($canviewallrecords) {
+                $groupselect = ' ';
+            } else {
+                // If separate groups are enabled and the user isn't in a group or
+                // a teacher, manager, admin etc, then just show them entries for 'All participants'.
+                $groupselect = " AND r.groupid = 0";
+            }
         }
 
         // Init some variables to be used by advanced search
@@ -590,10 +603,19 @@ if ($showactivity) {
         $sqlmax     = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
         $allparams  = array_merge($params, $advparams);
 
-        $recordids = data_get_all_recordids($data->id);
+        // Provide initial sql statements and parameters to reduce the number of total records.
+        $selectdata = $groupselect . $approveselect;
+        $initialparams = array();
+        if ($currentgroup) {
+            $initialparams['currentgroup'] = $params['currentgroup'];
+        }
+        if (!$approvecap && $data->approval && isloggedin()) {
+            $initialparams['myid1'] = $params['myid1'];
+        }
+
+        $recordids = data_get_all_recordids($data->id, $selectdata, $initialparams);
         $newrecordids = data_get_advance_search_ids($recordids, $search_array, $data->id);
         $totalcount = count($newrecordids);
-        $selectdata = $groupselect . $approveselect;
 
         if (!empty($advanced)) {
             $advancedsearchsql = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
diff --git a/mod/upgrade.txt b/mod/upgrade.txt
index 72411c8..6eac247 100644
--- a/mod/upgrade.txt
+++ b/mod/upgrade.txt
@@ -21,6 +21,9 @@ optional - no changes needed:
   xxx_dndupload_register() and xxx_dndupload_handle($uploadinfo) see:
   http://docs.moodle.org/dev/Implementing_Course_drag_and_drop_upload_support_in_a_module
 
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
+
 === 2.2 ===
 
 required changes in code:
@@ -29,12 +32,20 @@ required changes in code:
 * textlib->asort() replaced by specialized collatorlib::asort()
 * use new make_temp_directory() and make_cache_directory()
 
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
 
 === 2.1 ===
 
 required changes in code:
 * add new support for basic restore from 1.9
 
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
 
 === 2.0 ===
 
-- 
1.7.9.5


From 92bff8685cc2f827aed0375a4781ef0c12e77e40 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Mon, 1 Oct 2012 23:03:51 +0200
Subject: [PATCH 784/903] MDL-35724 - Right align "Question Type" label in
 Quiz Editing page, when in RTL mode

---
 mod/quiz/styles.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 3ab0f5a..8fe5b30 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -251,6 +251,7 @@ table#categoryquestions {width: 100%;overflow: hidden;table-layout: fixed;}
 #page-mod-quiz-edit div.question div.content .singlequestion .questiontext{display:inline-block;}
 #page-mod-quiz-edit div.question div.content .singlequestion .questionpreview{background-color:#eee;}
 #page-mod-quiz-edit div.question div.content .questiontype{display:block;clear:left;float:left;}
+#page-mod-quiz-edit.dir-rtl div.question div.content .questiontype {clear: right;float: right;}
 #page-mod-quiz-edit div.question div.content .questionpreview {display:block;float:left;margin-left:0.3em;padding-left:0.2em;padding-right:0.2em;}
 #page-mod-quiz-edit div.question div.content .questionpreview a{background-color:#eee;}
 #page-mod-quiz-edit div.question div.content div.quiz_randomquestion .questionpreview{display:inline;float:none;}
-- 
1.7.9.5


From aae3d3445eeecdb181fec66ba9fec21d8782702b Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Mon, 1 Oct 2012 23:13:21 +0200
Subject: [PATCH 785/903] MDL-35724 - Move Question Marks block to the left
 (Question Bank page),in RTL mode

---
 mod/quiz/styles.css |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 8fe5b30..60fe3ec 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -400,7 +400,7 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl div.question {clear: right;}
 #page-mod-quiz-edit.dir-rtl div.question div.qnum {float: right;}
 #page-mod-quiz-edit.dir-rtl div.editq div.question div.content {float: right;height: 40px;}
-#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 50px;right:auto;}
+#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 5px;right:auto;}
 #page-mod-quiz-edit.dir-rtl div.question div.content div.questioncontrols {float: left;left: 0.3em; right:auto;}
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questionname,
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questiontext {float: right; padding-right: 0.3em;}
-- 
1.7.9.5


From 2ed34366f6dc63eb5aa100feae1537b022846aaf Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Mon, 8 Oct 2012 22:54:33 +0200
Subject: [PATCH 786/903] Revert "MDL-34894 course ws unit tests: fix windows
 problem."

This reverts commit 40d651bbbb20b4373b6b56e4e09c90b30ff86484.

With MDL-35714, each test gets gc_collect_cycles() called, so
no need to call it "manually".
---
 course/tests/externallib_test.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
index 605c5d8..984b9ed 100644
--- a/course/tests/externallib_test.php
+++ b/course/tests/externallib_test.php
@@ -580,6 +580,5 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         // Check that the course has been duplicated.
         $this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
-        gc_collect_cycles();
     }
 }
-- 
1.7.9.5


From af861e14dc5c83a5f4d142a0d13de1eb7467349b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?I=C3=B1aki=20Arenaza?= <iarenaza@mondragon.edu>
Date: Fri, 27 Apr 2012 00:23:42 +0200
Subject: [PATCH 787/903] MDL-31968 Make NTLM REMOTE_USER format configurable
 by the admin
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Iñaki Arenaza <iarenaza@mondragon.edu>
---
 auth/ldap/auth.php              |   79 ++++++++++++++++++++++++++++++++++++++-
 auth/ldap/config.html           |   15 ++++++++
 auth/ldap/lang/en/auth_ldap.php |    4 ++
 3 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php
index 88bb10d..c206452 100644
--- a/auth/ldap/auth.php
+++ b/auth/ldap/auth.php
@@ -41,6 +41,18 @@ if (!defined('AUTH_GID_NOGROUP')) {
     define('AUTH_GID_NOGROUP', -2);
 }
 
+// Regular expressions for a valid NTLM username and domain name.
+if (!defined('AUTH_NTLM_VALID_USERNAME')) {
+    define('AUTH_NTLM_VALID_USERNAME', '[^/\\\\\\\\\[\]:;|=,+*?<>@"]+');
+}
+if (!defined('AUTH_NTLM_VALID_DOMAINNAME')) {
+    define('AUTH_NTLM_VALID_DOMAINNAME', '[^\\\\\\\\\/:*?"<>|]+');
+}
+// Default format for remote users if using NTLM SSO
+if (!defined('AUTH_NTLM_DEFAULT_FORMAT')) {
+    define('AUTH_NTLM_DEFAULT_FORMAT', '%domain%\\%username%');
+}
+
 require_once($CFG->libdir.'/authlib.php');
 require_once($CFG->libdir.'/ldaplib.php');
 
@@ -1570,8 +1582,11 @@ class auth_plugin_ldap extends auth_plugin_base {
 
             switch ($this->config->ntlmsso_type) {
                 case 'ntlm':
-                    // Format is DOMAIN\username
-                    $username = substr(strrchr($username, '\\'), 1);
+                    // The format is now configurable, so try to extract the username
+                    $username = $this->get_ntlm_remote_user($username);
+                    if (empty($username)) {
+                        return false;
+                    }
                     break;
                 case 'kerberos':
                     // Format is username@DOMAIN
@@ -1779,6 +1794,9 @@ class auth_plugin_ldap extends auth_plugin_base {
         if (!isset($config->ntlmsso_type)) {
             $config->ntlmsso_type = 'ntlm';
         }
+        if (!isset($config->ntlmsso_remoteuserformat)) {
+            $config->ntlmsso_remoteuserformat = '';
+        }
 
         // Try to remove duplicates before storing the contexts (to avoid problems in sync_users()).
         $config->contexts = explode(';', $config->contexts);
@@ -1818,6 +1836,7 @@ class auth_plugin_ldap extends auth_plugin_base {
         set_config('ntlmsso_subnet', trim($config->ntlmsso_subnet), $this->pluginconfig);
         set_config('ntlmsso_ie_fastpath', (int)$config->ntlmsso_ie_fastpath, $this->pluginconfig);
         set_config('ntlmsso_type', $config->ntlmsso_type, 'auth/ldap');
+        set_config('ntlmsso_remoteuserformat', trim($config->ntlmsso_remoteuserformat), 'auth/ldap');
 
         return true;
     }
@@ -2018,4 +2037,60 @@ class auth_plugin_ldap extends auth_plugin_base {
                                 $this->config->user_attribute, $this->config->search_sub);
     }
 
+
+    /**
+     * A chance to validate form data, and last chance to do stuff
+     * before it is inserted in config_plugin
+     *
+     * @param object object with submitted configuration settings (without system magic quotes)
+     * @param array $err array of error messages (passed by reference)
+     */
+    function validate_form($form, &$err) {
+        if ($form->ntlmsso_type == 'ntlm') {
+            $format = trim($form->ntlmsso_remoteuserformat);
+            if (!empty($format) && !preg_match('/%username%/i', $format)) {
+                $err['ntlmsso_remoteuserformat'] = get_string('auth_ntlmsso_missing_username', 'auth_ldap');
+            }
+        }
+    }
+
+
+    /**
+     * When using NTLM SSO, the format of the remote username we get in
+     * $_SERVER['REMOTE_USER'] may vary, depending on where from and how the web
+     * server gets the data. So we let the admin configure the format using two
+     * place holders (%domain% and %username%). This function tries to extract
+     * the username (stripping the domain part and any separators if they are
+     * present) from the value present in $_SERVER['REMOTE_USER'], using the
+     * configured format.
+     *
+     * @param string $remoteuser The value from $_SERVER['REMOTE_USER'] (converted to UTF-8)
+     *
+     * @return string The remote username (without domain part or
+     *                separators). Empty string if we can't extract the username.
+     */
+    protected function get_ntlm_remote_user($remoteuser) {
+        if (empty($this->config->ntlmsso_remoteuserformat)) {
+            $format = AUTH_NTLM_DEFAULT_FORMAT;
+        } else {
+            $format = $this->config->ntlmsso_remoteuserformat;
+        }
+
+        $format = preg_quote($format);
+        $formatregex = preg_replace(array('#%domain%#', '#%username%#'),
+                                    array('('.AUTH_NTLM_VALID_DOMAINNAME.')', '('.AUTH_NTLM_VALID_USERNAME.')'),
+                                    $format);
+        if (preg_match('#^'.$formatregex.'$#', $remoteuser, $matches)) {
+            $user = end($matches);
+            return $user;
+        }
+
+        /* We are unable to extract the username with the configured format. Probably
+         * the format specified is wrong, so log a warning for the admin and return
+         * an empty username.
+         */
+        error_log($this->errorlogtag.get_string ('auth_ntlmsso_maybeinvalidformat', 'auth_ldap'));
+        return '';
+    }
+
 } // End of the class
diff --git a/auth/ldap/config.html b/auth/ldap/config.html
index 8ad27ef..3efe253 100644
--- a/auth/ldap/config.html
+++ b/auth/ldap/config.html
@@ -94,6 +94,9 @@ if (!isset($config->ntlmsso_ie_fastpath)) {
 if (!isset($config->ntlmsso_type)) {
     $config->ntlmsso_type = 'ntlm';
 }
+if (!isset($config->ntlmsso_remoteuserformat)) {
+    $config->ntlmsso_remoteuserformat = '';
+}
 
 $yesno = array(get_string('no'), get_string('yes'));
 
@@ -539,6 +542,18 @@ $yesno = array(get_string('no'), get_string('yes'));
         <?php print_string('auth_ntlmsso_type','auth_ldap') ?>
     </td>
 </tr>
+<tr valign="top">
+    <td align="right">
+        <label for="ntlmsso_remoteuserformat"><?php print_string('auth_ntlmsso_remoteuserformat_key', 'auth_ldap') ?></label>
+    </td>
+    <td>
+        <input name="ntlmsso_remoteuserformat" id="ntlmsso_remoteuserformat" type="text" size="30" value="<?php echo $config->ntlmsso_remoteuserformat?>" />
+        <?php if (isset($err['ntlmsso_remoteuserformat'])) { echo $OUTPUT->error_text($err['ntlmsso_remoteuserformat']); } ?>
+    </td>
+    <td>
+        <?php print_string('auth_ntlmsso_remoteuserformat', 'auth_ldap') ?>
+    </td>
+</tr>
 <?php
 $help  = get_string('auth_ldapextrafields', 'auth_ldap');
 $help .= get_string('auth_updatelocal_expl', 'auth');
diff --git a/auth/ldap/lang/en/auth_ldap.php b/auth/ldap/lang/en/auth_ldap.php
index bbb0ddb..848169a 100644
--- a/auth/ldap/lang/en/auth_ldap.php
+++ b/auth/ldap/lang/en/auth_ldap.php
@@ -101,6 +101,10 @@ $string['auth_ntlmsso_enabled'] = 'Set to yes to attempt Single Sign On with the
 $string['auth_ntlmsso_enabled_key'] = 'Enable';
 $string['auth_ntlmsso_ie_fastpath'] = 'Set to yes to enable the NTLM SSO fast path (bypasses certain steps and only works if the client\'s browser is MS Internet Explorer).';
 $string['auth_ntlmsso_ie_fastpath_key'] = 'MS IE fast path?';
+$string['auth_ntlmsso_maybeinvalidformat'] = 'Unable to extract the username from the REMOTE_USER header. Is the configured format right?';
+$string['auth_ntlmsso_missing_username'] = 'You need to specify at least %username% in the remote username format';
+$string['auth_ntlmsso_remoteuserformat_key'] = 'Remote username format';
+$string['auth_ntlmsso_remoteuserformat'] = 'If you have chosen \'NTLM\' in \'Authentication type\', you can specify the remote username format here. If you leave this empty, the default DOMAIN\\username format will be used. You can use the optional <b>%domain%</b> placeholder to specify where the domain name appears, and the mandatory <b>%username%</b> placeholder to specify where the username appears. <br /><br />Some widely used formats are <tt>%domain%\\%username%</tt> (MS Windows default), <tt>%domain%/%username%</tt>, <tt>%domain%+%username%</tt> and just <tt>%username%</tt> (if there is no domain part).';
 $string['auth_ntlmsso_subnet'] = 'If set, it will only attempt SSO with clients in this subnet. Format: xxx.xxx.xxx.xxx/bitmask. Separate multiple subnets with \',\' (comma).';
 $string['auth_ntlmsso_subnet_key'] = 'Subnet';
 $string['auth_ntlmsso_type_key'] = 'Authentication type';
-- 
1.7.9.5


From 5364f9c7cdd73b86edf11f318ed4de4beb1d266f Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Tue, 9 Oct 2012 00:34:42 +0000
Subject: [PATCH 788/903] Automatically generated installer lang files

---
 install/lang/sr_cr/install.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/install/lang/sr_cr/install.php b/install/lang/sr_cr/install.php
index 1dc0ec5..6a243d6 100644
--- a/install/lang/sr_cr/install.php
+++ b/install/lang/sr_cr/install.php
@@ -45,7 +45,7 @@ $string['datarootpermission'] = 'Овлашћења над директориј
 $string['dbprefix'] = 'Префикс табеле';
 $string['dirroot'] = 'Moodle директоријум';
 $string['environmenthead'] = 'Проверавање Вашег окружења...';
-$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верѕије и неколико обавезних PHP екстензија.
+$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верзије и неколико обавезних PHP екстензија.
 Пуна провера окружења се врши пре сваке инсталације или ажурирања постојеће верзије. Уколико не знате како да инсталирате нову верзију или омогућите PHP ектензије контактирајте Вашег сервер администратора.';
 $string['errorsinenvironment'] = 'Провера окружења није прошла!';
 $string['installation'] = 'Инсталација';
@@ -75,7 +75,7 @@ $string['pathssubwwwroot'] = 'Пуна веб адреса путем које 
 Ако је адреса нетачна промените URL у свом веб читачу да бисте поново покренули инсталацију са другачијом вредношћу.';
 $string['pathsunsecuredataroot'] = 'Dataroot локација није безбедна';
 $string['pathswrongadmindir'] = 'Админ директоријум не постоји';
-$string['phpextension'] = '{$a} PHP екстенѕија';
+$string['phpextension'] = '{$a} PHP екстензија';
 $string['phpversion'] = 'PHP верзија';
 $string['phpversionhelp'] = '<p>Moodle захтева најмање PHP верзију 4.3.0 или 5.1.0 (5.0.x има  бројне уочене проблеме).</p>
 <p>Тренутно користите верзију {$a}</p>
-- 
1.7.9.5


From 8715a53d90da81beff3c90561ee1274e7359be17 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 5 Oct 2012 11:47:14 +0800
Subject: [PATCH 789/903] MDL-30691 Adminstration: Added css to break long
 word in filter table

---
 admin/tool/customlang/styles.css |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/admin/tool/customlang/styles.css b/admin/tool/customlang/styles.css
index c743bcf..963b289 100644
--- a/admin/tool/customlang/styles.css
+++ b/admin/tool/customlang/styles.css
@@ -67,3 +67,7 @@
 #page-admin-tool-customlang-index .continuebutton {
     margin-top: 1em;
 }
+
+.path-admin-tool-customlang #translator .standard.master.cell.c2 {
+    word-break: break-all;
+}
-- 
1.7.9.5


From add569ebe0ef324599c5435cc50530db4d99f55e Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Thu, 4 Oct 2012 16:11:09 +0800
Subject: [PATCH 790/903] MDL-35787 Mnet: fixed php strict standards warnings

---
 auth/mnet/auth.php            |    3 ++-
 mnet/service/enrol/course.php |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/auth/mnet/auth.php b/auth/mnet/auth.php
index 0a136e8..2e21aaa 100644
--- a/auth/mnet/auth.php
+++ b/auth/mnet/auth.php
@@ -378,7 +378,8 @@ class auth_plugin_mnet extends auth_plugin_base {
                 $extra = $DB->get_records_sql($sql);
 
                 $keys = array_keys($courses);
-                $defaultrole = reset(get_archetype_roles('student'));
+                $studentroles = get_archetype_roles('student');
+                $defaultrole = reset($studentroles);
                 //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
                 foreach ($keys AS $id) {
                     if ($courses[$id]->visible == 0) {
diff --git a/mnet/service/enrol/course.php b/mnet/service/enrol/course.php
index d67eaf6..632e4d3 100644
--- a/mnet/service/enrol/course.php
+++ b/mnet/service/enrol/course.php
@@ -62,7 +62,7 @@ echo $OUTPUT->heading($icon . s($course->fullname));
 
 // collapsible course summary
 if (!empty($course->summary)) {
-    unset($options);
+    $options = new stdClass();
     $options->trusted = false;
     $options->para    = false;
     $options->filter  = false;
-- 
1.7.9.5


From 18f9ad377fc6ac4cc51480bf07be7dc152d056b2 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Tue, 9 Oct 2012 15:22:03 +0800
Subject: [PATCH 791/903] MDL-35787 Mnet: If student role is not defined then
 throw error

---
 auth/mnet/auth.php |   36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/auth/mnet/auth.php b/auth/mnet/auth.php
index 2e21aaa..14a42ac 100644
--- a/auth/mnet/auth.php
+++ b/auth/mnet/auth.php
@@ -379,23 +379,27 @@ class auth_plugin_mnet extends auth_plugin_base {
 
                 $keys = array_keys($courses);
                 $studentroles = get_archetype_roles('student');
-                $defaultrole = reset($studentroles);
-                //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
-                foreach ($keys AS $id) {
-                    if ($courses[$id]->visible == 0) {
-                        unset($courses[$id]);
-                        continue;
+                if (!empty($studentroles)) {
+                    $defaultrole = reset($studentroles);
+                    //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
+                    foreach ($keys AS $id) {
+                        if ($courses[$id]->visible == 0) {
+                            unset($courses[$id]);
+                            continue;
+                        }
+                        $courses[$id]->cat_id          = $courses[$id]->category;
+                        $courses[$id]->defaultroleid   = $defaultrole->id;
+                        unset($courses[$id]->category);
+                        unset($courses[$id]->visible);
+
+                        $courses[$id]->cat_name        = $extra[$id]->cat_name;
+                        $courses[$id]->cat_description = $extra[$id]->cat_description;
+                        $courses[$id]->defaultrolename = $defaultrole->name;
+                        // coerce to array
+                        $courses[$id] = (array)$courses[$id];
                     }
-                    $courses[$id]->cat_id          = $courses[$id]->category;
-                    $courses[$id]->defaultroleid   = $defaultrole->id;
-                    unset($courses[$id]->category);
-                    unset($courses[$id]->visible);
-
-                    $courses[$id]->cat_name        = $extra[$id]->cat_name;
-                    $courses[$id]->cat_description = $extra[$id]->cat_description;
-                    $courses[$id]->defaultrolename = $defaultrole->name;
-                    // coerce to array
-                    $courses[$id] = (array)$courses[$id];
+                } else {
+                    throw new moodle_exception('unknownrole', 'error', '', 'student');
                 }
             } else {
                 // if the array is empty, send it anyway
-- 
1.7.9.5


From e22cff45ab2abedb449c2e8ed54b0fd7b58ee647 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 9 Oct 2012 09:43:08 +0200
Subject: [PATCH 792/903] MDL-35898 include static course caches in test
 resets

---
 lib/phpunit/classes/util.php |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index b580259..6376e14 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -618,6 +618,10 @@ class phpunit_util {
         $GROUPLIB_CACHE = null;
         //TODO MDL-25290: add more resets here and probably refactor them to new core function
 
+        // Rest course and module caches.
+        $reset = 'reset';
+        get_fast_modinfo($reset);
+
         // purge dataroot directory
         self::reset_dataroot();
 
-- 
1.7.9.5


From ad87b3a2cc951ea6908a00eb266c667366edf236 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 9 Oct 2012 10:28:21 +0800
Subject: [PATCH 793/903] MDL-35858 question: Fixed display of feedback in
 cloze questions

---
 question/type/multianswer/module.js    |    2 +-
 question/type/multianswer/renderer.php |    6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/question/type/multianswer/module.js b/question/type/multianswer/module.js
index beb3788..2fbe4e0 100644
--- a/question/type/multianswer/module.js
+++ b/question/type/multianswer/module.js
@@ -27,7 +27,7 @@ M.qtype_multianswer = M.qtype_multianswer || {};
 
 
 M.qtype_multianswer.init = function (Y, questiondiv) {
-    Y.one(questiondiv).all('label.subq').each(function(subqspan, i) {
+    Y.one(questiondiv).all('span.subquestion').each(function(subqspan, i) {
         var feedbackspan = subqspan.one('.feedbackspan');
         if (!feedbackspan) {
             return;
diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php
index 0134eb4..5afe4ff 100644
--- a/question/type/multianswer/renderer.php
+++ b/question/type/multianswer/renderer.php
@@ -227,12 +227,13 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
                         $qa, 'question', 'answerfeedback', $matchinganswer->id),
                 s($correctanswer->answer), $options);
 
-        $output = '';
+        $output = html_writer::start_tag('span', array('class' => 'subquestion'));
         $output .= html_writer::tag('label', get_string('answer'),
                 array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= html_writer::empty_tag('input', $inputattributes);
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
+        $output .= html_writer::end_tag('span');
 
         return $output;
     }
@@ -294,12 +295,13 @@ class qtype_multianswer_multichoice_inline_renderer
                 $subq->format_text($rightanswer->answer, $rightanswer->answerformat,
                         $qa, 'question', 'answer', $rightanswer->id), $options);
 
-        $output = '';
+        $output = html_writer::start_tag('span', array('class' => 'subquestion'));
         $output .= html_writer::tag('label', get_string('answer'),
                 array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= $select;
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
+        $output .= html_writer::end_tag('span');
 
         return $output;
     }
-- 
1.7.9.5


From aedc642091430d8b6cf1f780507d9291d2b45257 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Tue, 9 Oct 2012 16:35:32 +0800
Subject: [PATCH 794/903] MDL-35587 fixed up whitespaces

---
 course/dndupload.js     |   10 +++++-----
 course/dnduploadlib.php |    4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/course/dndupload.js b/course/dndupload.js
index e410d40..2dcaa13 100644
--- a/course/dndupload.js
+++ b/course/dndupload.js
@@ -728,13 +728,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
-                            
+
                             if (result.groupingname) {
                                 resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
                             } else {
                                 resel.div.removeChild(resel.groupingspan);
                             }
-                            
+
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
@@ -915,13 +915,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
-                            
+
                             if (result.groupingname) {
                                 resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
                             } else {
                                 resel.div.removeChild(resel.groupingspan);
-                            }                            
-                            
+                            }
+
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
diff --git a/course/dnduploadlib.php b/course/dnduploadlib.php
index 043b6c7..038c09b 100644
--- a/course/dnduploadlib.php
+++ b/course/dnduploadlib.php
@@ -670,9 +670,9 @@ class dndupload_ajax_processor {
         // if using groupings, then display grouping name
         if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
             $groupings = groups_get_all_groupings($this->course->id);
-            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);        
+            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
         }
-   
+
         echo $OUTPUT->header();
         echo json_encode($resp);
         die();
-- 
1.7.9.5


From 86b1d0eb5facdb1b881cdd30d028786127e8821b Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Tue, 9 Oct 2012 11:59:46 +0200
Subject: [PATCH 795/903] MDL-35898 test reset: Tidyup comment

---
 lib/phpunit/classes/util.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/phpunit/classes/util.php b/lib/phpunit/classes/util.php
index 7096b8d..f9dc68d 100644
--- a/lib/phpunit/classes/util.php
+++ b/lib/phpunit/classes/util.php
@@ -621,7 +621,7 @@ class phpunit_util {
         $GROUPLIB_CACHE = null;
         //TODO MDL-25290: add more resets here and probably refactor them to new core function
 
-        // Rest course and module caches.
+        // Reset course and module caches.
         $reset = 'reset';
         get_fast_modinfo($reset);
 
-- 
1.7.9.5


From d01c6b269b254b722b0a292105e404d38dfbc0e1 Mon Sep 17 00:00:00 2001
From: Simon Coggins <simon.coggins@totaralms.com>
Date: Wed, 10 Oct 2012 08:52:58 +1300
Subject: [PATCH 796/903] MDL-35581 lib: Help popups misaligned for
 right-to-left languages

---
 lib/javascript-static.js  |    9 ++++++++-
 theme/base/style/core.css |    1 +
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 4189c37..471f3d8 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1434,9 +1434,16 @@ M.util.help_icon = {
                     },
 
                     display : function(event, args) {
+                        if (Y.one('html').get('dir') == 'rtl') {
+                            var overlayPosition = [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.LC];
+                        } else {
+                            var overlayPosition = [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.RC];
+                        }
+
                         this.helplink = args.node;
+
                         this.overlay.set('bodyContent', Y.Node.create('<img src="'+M.cfg.loadingicon+'" class="spinner" />'));
-                        this.overlay.set("align", {node:args.node, points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.RC]});
+                        this.overlay.set("align", {node:args.node, points: overlayPosition});
 
                         var fullurl = args.url;
                         if (!args.url.match(/https?:\/\//)) {
diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 3aec3d8..8590e1d 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -479,6 +479,7 @@ body.tag .managelink {padding: 5px;}
 #helppopupbox .yui3-widget-bd {margin:0 1em 1em 1em;border-top:1px solid #eee;}
 #helppopupbox .helpheading {font-size: 1em;}
 #helppopupbox .spinner {margin:1em;}
+.dir-rtl #helppopupbox .yui3-widget-hd {float:left;margin:3px 0 0 3px;}
 
 /**
  * Custom menu
-- 
1.7.9.5


From c5c735f00ea9d9501fc1f27ff7d4ebdb9f709f31 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 10 Oct 2012 00:34:20 +0000
Subject: [PATCH 797/903] Automatically generated installer lang files

---
 install/lang/ro/install.php |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/install/lang/ro/install.php b/install/lang/ro/install.php
index 1971fb3..ec01ae5 100644
--- a/install/lang/ro/install.php
+++ b/install/lang/ro/install.php
@@ -30,15 +30,22 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['admindirname'] = 'Admin Directory';
+$string['admindirname'] = 'Director Admin';
 $string['availablelangs'] = 'Pachete de limbă disponibile';
 $string['chooselanguagehead'] = 'Selectare limbă';
 $string['chooselanguagesub'] = 'Vă rugăm selectaţi limba pentru interfaţa de instalare, limba selectată va fi folosită EXCLUSIV în cadrul procedurii de instalare. Ulterior veţi putea selecta limba în care doriţi să fie afişată interfaţa.';
-$string['dataroot'] = 'Data Directory';
+$string['databasehost'] = 'Gazdă baza de date';
+$string['databasename'] = 'Nume baza de date';
+$string['databasetypehead'] = 'Alegere driver baza de date';
+$string['dataroot'] = 'Director date';
+$string['datarootpermission'] = 'Permisiuni directoare date';
 $string['dbprefix'] = 'Prefix tabele';
 $string['dirroot'] = 'Director Moodle';
 $string['environmenthead'] = 'Se verifică mediul...';
 $string['installation'] = 'Instalare';
+$string['paths'] = 'Căi';
+$string['pathshead'] = 'Confirmare căi';
+$string['phpextension'] = 'extensie PHP {$a}';
 $string['phpversion'] = 'Versiune PHP';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['wwwroot'] = 'Adresă Web';
-- 
1.7.9.5


From 437637a11d046438e184cda92c3a88c60eb40a45 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 11 Oct 2012 10:55:37 +0800
Subject: [PATCH 798/903] MDL-31010 comments: setup_course should update  if
 passed courseid is different from the cached one

---
 comment/locallib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/comment/locallib.php b/comment/locallib.php
index 5a8b0d7..31b2799 100644
--- a/comment/locallib.php
+++ b/comment/locallib.php
@@ -94,7 +94,7 @@ class comment_manager {
      */
     private function setup_course($courseid) {
         global $PAGE, $DB;
-        if (!empty($this->course)) {
+        if (!empty($this->course) && $this->course->id == $courseid) {
             // already set, stop
             return;
         }
-- 
1.7.9.5


From 0cb1a22cba30d68734887f787479767cf21f07c8 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Thu, 11 Oct 2012 14:22:34 +0800
Subject: [PATCH 799/903] MDL-28965 administration: Updating description
 string for the setting navshowallcourses

---
 lang/en/admin.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 8a6a935..919a7a9 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -258,7 +258,7 @@ $string['configmycoursesperpage'] = 'Maximum number of courses to display in any
 $string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
 $string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
 $string['confignavcourselimit'] = 'Limits the number of courses shown to the user when they are either not logged in or are not enrolled in any courses.';
-$string['confignavshowallcourses'] = 'If enabled users will see courses they are enrolled in both within the My Courses branch and the course structure. When disabled users with enrolments will only see the My Courses branch of the navigaiton.';
+$string['confignavshowallcourses'] = 'If enabled users will see courses they are enrolled in both within the My Courses branch and the course structure. When disabled users with enrolments will only see the My Courses branch of the navigaiton. The number of course shown would still be limited by "Course limit(navcourselimit)" setting when user is either not logged in or not enrolled in any course.';
 $string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
 $string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out.  Who should see these notifications?';
 $string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
-- 
1.7.9.5


From 2c484717e1a191d0ce2f7ac0436ac75f30cfa0fb Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 11 Oct 2012 16:02:16 +0800
Subject: [PATCH 800/903] MDL-33815 Online Users block: Add query condition to
 filter out deleted users and lastaccess date
 greater than now

---
 blocks/online_users/block_online_users.php |   24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/blocks/online_users/block_online_users.php b/blocks/online_users/block_online_users.php
index cbf1dac..2efe9a2 100644
--- a/blocks/online_users/block_online_users.php
+++ b/blocks/online_users/block_online_users.php
@@ -31,7 +31,8 @@ class block_online_users extends block_base {
         if (isset($CFG->block_online_users_timetosee)) {
             $timetoshowusers = $CFG->block_online_users_timetosee * 60;
         }
-        $timefrom = 100 * floor((time()-$timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache
+        $now = time();
+        $timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache
 
         //Calculate if we are in separate groups
         $isseparategroups = ($this->page->course->groupmode == SEPARATEGROUPS
@@ -53,18 +54,23 @@ class block_online_users extends block_base {
         }
 
         $userfields = user_picture::fields('u', array('username'));
-
+        $params['now'] = $now;
+        $params['timefrom'] = $timefrom;
         if ($this->page->course->id == SITEID or $this->page->context->contextlevel < CONTEXT_COURSE) {  // Site-level
             $sql = "SELECT $userfields, MAX(u.lastaccess) AS lastaccess
                       FROM {user} u $groupmembers
-                     WHERE u.lastaccess > $timefrom
+                     WHERE u.lastaccess > :timefrom
+                           AND u.lastaccess <= :now
+                           AND u.deleted = 0
                            $groupselect
                   GROUP BY $userfields
                   ORDER BY lastaccess DESC ";
 
            $csql = "SELECT COUNT(u.id)
                       FROM {user} u $groupmembers
-                     WHERE u.lastaccess > $timefrom
+                     WHERE u.lastaccess > :timefrom
+                           AND u.lastaccess <= :now
+                           AND u.deleted = 0
                            $groupselect";
 
         } else {
@@ -77,9 +83,11 @@ class block_online_users extends block_base {
             $sql = "SELECT $userfields, MAX(ul.timeaccess) AS lastaccess
                       FROM {user_lastaccess} ul $groupmembers, {user} u
                       JOIN ($esqljoin) euj ON euj.id = u.id
-                     WHERE ul.timeaccess > $timefrom
+                     WHERE ul.timeaccess > :timefrom
                            AND u.id = ul.userid
                            AND ul.courseid = :courseid
+                           AND ul.timeaccess <= :now
+                           AND u.deleted = 0
                            $groupselect
                   GROUP BY $userfields
                   ORDER BY lastaccess DESC";
@@ -87,9 +95,11 @@ class block_online_users extends block_base {
            $csql = "SELECT COUNT(u.id)
                       FROM {user_lastaccess} ul $groupmembers, {user} u
                       JOIN ($esqljoin) euj ON euj.id = u.id
-                     WHERE ul.timeaccess > $timefrom
+                     WHERE ul.timeaccess > :timefrom
                            AND u.id = ul.userid
                            AND ul.courseid = :courseid
+                           AND ul.timeaccess <= :now
+                           AND u.deleted = 0
                            $groupselect";
 
             $params['courseid'] = $this->page->course->id;
@@ -138,7 +148,7 @@ class block_online_users extends block_base {
             }
             foreach ($users as $user) {
                 $this->content->text .= '<li class="listentry">';
-                $timeago = format_time(time() - $user->lastaccess); //bruno to calculate correctly on frontpage
+                $timeago = format_time($now - $user->lastaccess); //bruno to calculate correctly on frontpage
 
                 if (isguestuser($user)) {
                     $this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16));
-- 
1.7.9.5


From 696527c0fe2cb94d516073d79d337afd51508dd3 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 11 Oct 2012 16:11:58 +0800
Subject: [PATCH 801/903] MDL-21801 Lesson Module: Removing import power point
 functionality

---
 mod/lesson/importppt.php    |  211 --------------------------------------
 mod/lesson/importpptlib.php |  236 -------------------------------------------
 mod/lesson/renderer.php     |    3 -
 3 files changed, 450 deletions(-)
 delete mode 100644 mod/lesson/importppt.php
 delete mode 100644 mod/lesson/importpptlib.php

diff --git a/mod/lesson/importppt.php b/mod/lesson/importppt.php
deleted file mode 100644
index 84bd61b..0000000
--- a/mod/lesson/importppt.php
+++ /dev/null
@@ -1,211 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This is a very rough importer for powerpoint slides
- * Export a powerpoint presentation with powerpoint as html pages
- * Do it with office 2002 (I think?) and no special settings
- * Then zip the directory with all of the html pages
- * and the zip file is what you want to upload
- *
- * The script supports book and lesson.
- *
- * @package    mod
- * @subpackage lesson
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-
-/** include required files */
-require_once("../../config.php");
-require_once($CFG->dirroot.'/mod/lesson/locallib.php');
-require_once($CFG->dirroot.'/mod/lesson/importpptlib.php');
-
-$id     = required_param('id', PARAM_INT);         // Course Module ID
-$pageid = optional_param('pageid', '', PARAM_INT); // Page ID
-
-$url = new moodle_url('/mod/lesson/importppt.php', array('id'=>$id));
-if ($pageid !== '') {
-    $url->param('pageid', $pageid);
-}
-$PAGE->set_url($url);
-
-$cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST);;
-$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
-$lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST));
-
-$modname = 'lesson';
-$mod = $cm;
-require_login($course, false, $cm);
-
-require_login($course, false, $cm);
-$context = get_context_instance(CONTEXT_MODULE, $cm->id);
-require_capability('mod/lesson:edit', $context);
-
-$strimportppt = get_string("importppt", "lesson");
-$strlessons = get_string("modulenameplural", "lesson");
-
-$data = new stdClass;
-$data->id = $cm->id;
-$data->pageid = $pageid;
-$mform = new lesson_importppt_form();
-$mform->set_data($data);
-
-if ($data = $mform->get_data()) {
-    $manager = lesson_page_type_manager::get($lesson);
-    if (!$filename = $mform->get_new_filename('pptzip')) {
-        print_error('invalidfile', 'lesson');
-    }
-    if (!$package = $mform->save_stored_file('pptzip', $context->id, 'mod_lesson', 'ppt_imports', $lesson->id, '/', $filename, true)) {
-        print_error('unabletosavefile', 'lesson');
-    }
-    // extract package content
-    $packer = get_file_packer('application/zip');
-    $package->extract_to_storage($packer, $context->id, 'mod_lesson', 'imported_files', $lesson->id, '/');
-
-    $fs = get_file_storage();
-    if ($files = $fs->get_area_files($context->id, 'mod_lesson', 'imported_files', $lesson->id)) {
-
-        $pages = array();
-        foreach ($files as $key=>$file) {
-            if ($file->get_mimetype() != 'text/html') {
-                continue;
-            }
-            $filenameinfo = pathinfo($file->get_filepath().$file->get_filename());
-
-            $page = new stdClass;
-            $page->title = '';
-            $page->contents = array();
-            $page->images = array();
-            $page->source = $filenameinfo['basename'];
-
-            $string = strip_tags($file->get_content(),'<div><img>');
-            $imgs = array();
-            preg_match_all("/<img[^>]*(src\=\"(".$filenameinfo['filename']."\_image[^>^\"]*)\"[^>]*)>/i", $string, $imgs);
-            foreach ($imgs[2] as $img) {
-                $imagename = basename($img);
-                foreach ($files as $file) {
-                    if ($imagename === $file->get_filename()) {
-                        $page->images[] = clone($file);
-                    }
-                }
-            }
-
-            $matches = array();
-            // this will look for a non nested tag that is closed
-            // want to allow <b><i>(maybe more) tags but when we do that
-            // the preg_match messes up.
-            preg_match_all("/(<([\w]+)[^>]*>)([^<\\2>]*)(<\/\\2>)/", $string, $matches);
-            $countmatches = count($matches[1]);
-            for($i = 0; $i < $countmatches; $i++) { // go through all of our div matches
-
-                $class = lesson_importppt_isolate_class($matches[1][$i]); // first step in isolating the class
-
-                // check for any static classes
-                switch ($class) {
-                    case 'T':  // class T is used for Titles
-                        $page->title = $matches[3][$i];
-                        break;
-                    case 'B':  // I would guess that all bullet lists would start with B then go to B1, B2, etc
-                    case 'B1': // B1-B4 are just insurance, should just hit B and all be taken care of
-                    case 'B2':
-                    case 'B3':
-                    case 'B4':
-                        $page->contents[] = lesson_importppt_build_list($matches, '<ul>', $i, 0);  // this is a recursive function that will grab all the bullets and rebuild the list in html
-                        break;
-                    default:
-                        if ($matches[3][$i] != '&#13;') {  // odd crap generated... sigh
-                            if (substr($matches[3][$i], 0, 1) == ':') {  // check for leading :    ... hate MS ...
-                                $page->contents[] = substr($matches[3][$i], 1);  // get rid of :
-                            } else {
-                                $page->contents[] = $matches[3][$i];
-                            }
-                        }
-                        break;
-                }
-            }
-            $pages[] = $page;
-        }
-
-        $branchtables = lesson_create_objects($pages, $lesson->id);
-
-        // first set up the prevpageid and nextpageid
-        if (empty($pageid)) { // adding it to the top of the lesson
-            $prevpageid = 0;
-            // get the id of the first page.  If not found, then no pages in the lesson
-            if (!$nextpageid = $DB->get_field('lesson_pages', 'id', array('prevpageid' => 0, 'lessonid' => $lesson->id))) {
-                $nextpageid = 0;
-            }
-        } else {
-            // going after an actual page
-            $prevpageid = $pageid;
-            $nextpageid = $DB->get_field('lesson_pages', 'nextpageid', array('id' => $pageid));
-        }
-
-        foreach ($branchtables as $branchtable) {
-
-            // set the doubly linked list
-            $branchtable->page->nextpageid = $nextpageid;
-            $branchtable->page->prevpageid = $prevpageid;
-
-            // insert the page
-            $id = $DB->insert_record('lesson_pages', $branchtable->page);
-
-            if (!empty($branchtable->page->images)) {
-                $changes = array('contextid'=>$context->id, 'component'=>'mod_lesson', 'filearea'=>'page_contents', 'itemid'=>$id, 'timemodified'=>time());
-                foreach ($branchtable->page->images as $image) {
-                    $fs->create_file_from_storedfile($changes, $image);
-                }
-            }
-
-            // update the link of the page previous to the one we just updated
-            if ($prevpageid != 0) {  // if not the first page
-                $DB->set_field("lesson_pages", "nextpageid", $id, array("id" => $prevpageid));
-            }
-
-            // insert the answers
-            foreach ($branchtable->answers as $answer) {
-                $answer->pageid = $id;
-                $DB->insert_record('lesson_answers', $answer);
-            }
-
-            $prevpageid = $id;
-        }
-
-        // all done with inserts.  Now check to update our last page (this is when we import between two lesson pages)
-        if ($nextpageid != 0) {  // if the next page is not the end of lesson
-            $DB->set_field("lesson_pages", "prevpageid", $id, array("id" => $nextpageid));
-        }
-    }
-
-    // Remove all unzipped files!
-    $fs->delete_area_files($context->id, 'mod_lesson', 'imported_files', $lesson->id);
-
-    redirect("$CFG->wwwroot/mod/$modname/view.php?id=$cm->id", get_string('pptsuccessfullimport', 'lesson'), 5);
-}
-
-$PAGE->navbar->add($strimportppt);
-$PAGE->set_title($strimportppt);
-$PAGE->set_heading($strimportppt);
-echo $OUTPUT->header();
-
-/// Print upload form
-echo $OUTPUT->heading_with_help($strimportppt, 'importppt', 'lesson');
-echo $OUTPUT->box_start('generalbox boxaligncenter');
-$mform->display();
-echo $OUTPUT->box_end();
-echo $OUTPUT->footer();
diff --git a/mod/lesson/importpptlib.php b/mod/lesson/importpptlib.php
deleted file mode 100644
index 8550e61..0000000
--- a/mod/lesson/importpptlib.php
+++ /dev/null
@@ -1,236 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Contains functions used by importppt.php that naturally pertain to importing
- * powerpoint presentations into the lesson module
- *
- * @package    mod
- * @subpackage lesson
- * @copyright  2009 Sam Hemelryk
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * A recursive function to build a html list
- *
- * @param array $matches
- * @param string $list
- * @param int $i
- * @param int $depth
- * @return string
- */
-function lesson_importppt_build_list(array &$matches, $list, &$i, $depth) {
-    while($i < count($matches[1])) {
-
-        $class = lesson_importppt_isolate_class($matches[1][$i]);
-
-        if (strstr($class, 'B')) {  // make sure we are still working with bullet classes
-            if ($class == 'B') {
-                $this_depth = 0;  // calling class B depth 0
-            } else {
-                // set the depth number.  So B1 is depth 1 and B2 is depth 2 and so on
-                $this_depth = substr($class, 1);
-                if (!is_numeric($this_depth)) {
-                    print_error('invalidnum');
-                }
-            }
-            if ($this_depth < $depth) {
-                // we are moving back a level in the nesting
-                break;
-            }
-            if ($this_depth > $depth) {
-                // we are moving in a lvl in nesting
-                $list .= '<ul>';
-                $list = lesson_importppt_build_list($matches, $list, $i, $this_depth);
-                // once we return back, should go to the start of the while
-                continue;
-            }
-            // no depth changes, so add the match to our list
-            if ($cleanstring = lesson_importppt_clean_text($matches[3][$i])) {
-                $list .= '<li>'.lesson_importppt_clean_text($matches[3][$i]).'</li>';
-            }
-            $i++;
-        } else {
-            // not a B class, so get out of here...
-            break;
-        }
-    }
-    // end the list and return it
-    $list .= '</ul>';
-    return $list;
-
-}
-
-/**
- * Given an html tag, this function will
- *
- * @param string $string
- * @return string
- */
-function lesson_importppt_isolate_class($string) {
-    if($class = strstr($string, 'class=')) { // first step in isolating the class
-        $class = substr($class, strpos($class, '=')+1);  // this gets rid of <div blawblaw class=  there are no "" or '' around the class name   ...sigh...
-        if (strstr($class, ' ')) {
-            // spaces found, so cut off everything off after the first space
-            return substr($class, 0, strpos($class, ' '));
-        } else {
-            // no spaces so nothing else in the div tag, cut off the >
-            return substr($class, 0, strpos($class, '>'));
-        }
-    } else {
-        // no class defined in the tag
-        return '';
-    }
-}
-
-/**
- * This function strips off the random chars that ppt puts infront of bullet lists
- *
- * @param string $string
- * @return string
- */
-function lesson_importppt_clean_text($string) {
-    $chop = 1; // default: just a single char infront of the content
-
-    // look for any other crazy things that may be infront of the content
-    if (strstr($string, '&lt;') and strpos($string, '&lt;') == 0) {  // look for the &lt; in the sting and make sure it is in the front
-        $chop = 4;  // increase the $chop
-    }
-    // may need to add more later....
-
-    $string = substr($string, $chop);
-
-    if ($string != '&#13;') {
-        return $string;
-    } else {
-        return false;
-    }
-}
-
-/**
- *  Creates objects an object with the page and answers that are to be inserted into the database
- *
- * @param array $pageobjects
- * @param int $lessonid
- * @return array
- */
-function lesson_create_objects($pageobjects, $lessonid) {
-
-    $branchtables = array();
-    $branchtable = new stdClass;
-
-    // all pages have this info
-    $page = new stdClass();
-    $page->lessonid = $lessonid;
-    $page->prevpageid = 0;
-    $page->nextpageid = 0;
-    $page->qtype = LESSON_PAGE_BRANCHTABLE;
-    $page->qoption = 0;
-    $page->layout = 1;
-    $page->display = 1;
-    $page->timecreated = time();
-    $page->timemodified = 0;
-
-    // all answers are the same
-    $answer = new stdClass();
-    $answer->lessonid = $lessonid;
-    $answer->jumpto = LESSON_NEXTPAGE;
-    $answer->grade = 0;
-    $answer->score = 0;
-    $answer->flags = 0;
-    $answer->timecreated = time();
-    $answer->timemodified = 0;
-    $answer->answer = "Next";
-    $answer->response = "";
-
-    $answers[] = clone($answer);
-
-    $answer->jumpto = LESSON_PREVIOUSPAGE;
-    $answer->answer = "Previous";
-
-    $answers[] = clone($answer);
-
-    $branchtable->answers = $answers;
-
-    $i = 1;
-
-    foreach ($pageobjects as $pageobject) {
-        if ($pageobject->title == '') {
-            $page->title = "Page $i";  // no title set so make a generic one
-        } else {
-            $page->title = $pageobject->title;
-        }
-        $page->contents = '';
-
-        // nab all the images first
-        $page->images = $pageobject->images;
-        foreach ($page->images as $image) {
-            $imagetag = '<img src="@@PLUGINFILE@@'.$image->get_filepath().$image->get_filename().'" title="'.$image->get_filename().'" />';
-            $imagetag = str_replace("\n", '', $imagetag);
-            $imagetag = str_replace("\r", '', $imagetag);
-            $imagetag = str_replace("'", '"', $imagetag);  // imgstyle
-            $page->contents .= $imagetag;
-        }
-        // go through the contents array and put <p> tags around each element and strip out \n which I have found to be unneccessary
-        foreach ($pageobject->contents as $content) {
-            $content = str_replace("\n", '', $content);
-            $content = str_replace("\r", '', $content);
-            $content = str_replace('&#13;', '', $content);  // puts in returns?
-            $content = '<p>'.$content.'</p>';
-            $page->contents .= $content;
-        }
-
-        $branchtable->page = clone($page);  // add the page
-        $branchtables[] = clone($branchtable);  // add it all to our array
-        $i++;
-    }
-
-    return $branchtables;
-}
-
-/**
- * Form displayed to the user asking them to select a file to upload
- *
- * @copyright  2009 Sam Hemelryk
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class lesson_importppt_form extends moodleform {
-
-    public function definition() {
-        global $COURSE;
-
-        $mform = $this->_form;
-
-        $mform->addElement('hidden', 'id');
-        $mform->setType('id', PARAM_INT);
-
-        $mform->addElement('hidden', 'pageid');
-        $mform->setType('pageid', PARAM_INT);
-
-        $filepickeroptions = array();
-        $filepickeroptions['filetypes'] = array('*.zip');
-        $filepickeroptions['maxbytes'] = $COURSE->maxbytes;
-        $mform->addElement('filepicker', 'pptzip', get_string('upload'), null, $filepickeroptions);
-        $mform->addRule('pptzip', null, 'required', null, 'client');
-
-        $this->add_action_buttons(null, get_string("uploadthisfile"));
-    }
-
-}
\ No newline at end of file
diff --git a/mod/lesson/renderer.php b/mod/lesson/renderer.php
index 765b7ca..a37f40b 100644
--- a/mod/lesson/renderer.php
+++ b/mod/lesson/renderer.php
@@ -364,9 +364,6 @@ class mod_lesson_renderer extends plugin_renderer_base {
         $importquestionsurl = new moodle_url('/mod/lesson/import.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid));
         $links[] = html_writer::link($importquestionsurl, get_string('importquestions', 'lesson'));
 
-        $importppturl = new moodle_url('/mod/lesson/importppt.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid));
-        $links[] = html_writer::link($importppturl, get_string('importppt', 'lesson'));
-
         $manager = lesson_page_type_manager::get($lesson);
         foreach ($manager->get_add_page_type_links($prevpageid) as $link) {
             $link['addurl']->param('firstpage', 1);
-- 
1.7.9.5


From 84b3cbab33b27774018c6e2593ae75179537f4fe Mon Sep 17 00:00:00 2001
From: Jonathan Harker <jon@jon.geek.nz>
Date: Fri, 12 Oct 2012 13:31:47 +1300
Subject: [PATCH 802/903] MDL-36015 lib/bennu: use static functions correctly.

---
 lib/bennu/bennu.class.php          |    4 ++--
 lib/bennu/iCalendar_parameters.php |   10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/bennu/bennu.class.php b/lib/bennu/bennu.class.php
index 57d643f..b278c14 100644
--- a/lib/bennu/bennu.class.php
+++ b/lib/bennu/bennu.class.php
@@ -13,14 +13,14 @@
  */
 
 class Bennu {
-    function timestamp_to_datetime($t = NULL) {
+    static function timestamp_to_datetime($t = NULL) {
         if($t === NULL) {
             $t = time();
         }
         return gmstrftime('%Y%m%dT%H%M%SZ', $t);
     }
 
-    function generate_guid() {
+    static function generate_guid() {
         // Implemented as per the Network Working Group draft on UUIDs and GUIDs
     
         // These two octets get special treatment
diff --git a/lib/bennu/iCalendar_parameters.php b/lib/bennu/iCalendar_parameters.php
index 6614b39..d264083 100644
--- a/lib/bennu/iCalendar_parameters.php
+++ b/lib/bennu/iCalendar_parameters.php
@@ -14,7 +14,7 @@
  */
 
 class iCalendar_parameter {
-    function multiple_values_allowed($parameter) {
+    static function multiple_values_allowed($parameter) {
         switch($parameter) {
             case 'DELEGATED-FROM':
             case 'DELEGATED-TO':
@@ -25,7 +25,7 @@ class iCalendar_parameter {
         }
     }
 
-    function default_value($parameter) {
+    static function default_value($parameter) {
         switch($parameter) {
             case 'CUTYPE':   return 'INDIVIDUAL';
             case 'FBTYPE':   return 'BUSY';
@@ -38,7 +38,7 @@ class iCalendar_parameter {
         }
     }
 
-    function is_valid_value(&$parent_property, $parameter, $value) {
+    static function is_valid_value(&$parent_property, $parameter, $value) {
         switch($parameter) {
             // These must all be a URI
             case 'ALTREP':
@@ -191,7 +191,7 @@ class iCalendar_parameter {
         }
     }
 
-    function do_value_formatting($parameter, $value) {
+    static function do_value_formatting($parameter, $value) {
         switch($parameter) {
             // Parameters of type CAL-ADDRESS or URI MUST be double-quoted
             case 'ALTREP':
@@ -232,7 +232,7 @@ class iCalendar_parameter {
         }
     }
 
-    function undo_value_formatting($parameter, $value) {
+    static function undo_value_formatting($parameter, $value) {
     }
 
 }
-- 
1.7.9.5


From 0e8aa5027eb7cb2bfa66e55f164c2d3409a8e02b Mon Sep 17 00:00:00 2001
From: Damyon Wiese <damyon.wiese@netspot.com.au>
Date: Fri, 12 Oct 2012 11:58:11 +0800
Subject: [PATCH 803/903] MDL-35726: Use a different form identifier for each
 form when using "Save and next"

This prevents a bug where the next student feedback will default to the values that
were on the last submitted form. This is a similar case to having multiple instances
of the same form on the same page - each one needs a unique identifier to distinguish
between them. In this case I include the $rownum which changes as you go to each student
in the list.
---
 mod/assign/gradeform.php |   11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/mod/assign/gradeform.php b/mod/assign/gradeform.php
index 8f73ac1..366d5d8 100644
--- a/mod/assign/gradeform.php
+++ b/mod/assign/gradeform.php
@@ -60,6 +60,17 @@ class mod_assign_grade_form extends moodleform {
     }
 
     /**
+     * This is required so when using "Save and next", each form is not defaulted to the previous form.
+     * Giving each form a unique identitifer is enough to prevent this (include the rownum in the form name).
+     *
+     * @return string - The unique identifier for this form.
+     */
+    protected function get_form_identifier() {
+        $params = $this->_customdata[2];
+        return get_class($this) . '_' . $params['rownum'];
+    }
+
+    /**
      * Perform minimal validation on the grade form
      * @param array $data
      * @param array $files
-- 
1.7.9.5


From cc3f17d86d232e7b122e714bcd339d78a3ad23c2 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 12 Oct 2012 22:57:39 +0100
Subject: [PATCH 804/903] MDL-35986 theme_canvas: add custommenu and
 block-region to layout files general.php,
 frontpage.php and report.php to fix regression in
 theme/serenity since MDL-33110.

---
 theme/canvas/layout/frontpage.php |  135 ++++++++++++++++++++-----------------
 theme/canvas/layout/general.php   |   30 ++++++---
 theme/canvas/layout/report.php    |   24 +++++--
 3 files changed, 111 insertions(+), 78 deletions(-)

diff --git a/theme/canvas/layout/frontpage.php b/theme/canvas/layout/frontpage.php
index a8b573d..c2d54c8 100644
--- a/theme/canvas/layout/frontpage.php
+++ b/theme/canvas/layout/frontpage.php
@@ -1,19 +1,24 @@
 <?php
 
-$hasheading = ($PAGE->heading);
-$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
-$hasfooter = (empty($PAGE->layout_options['nofooter']));
 $hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
 $hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$showsidepre = $hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT);
+$showsidepost = $hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT);
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 $bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre && !$showsidepost) {
     $bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
+} else if ($showsidepost && !$showsidepre) {
     $bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else if (!$showsidepost && !$showsidepre) {
     $bodyclasses[] = 'content-only';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -30,20 +35,24 @@ echo $OUTPUT->doctype() ?>
 
 <!-- START OF HEADER -->
 
-	<div id="wrapper" class="clearfix">
-
-    	<div id="page-header">
-			<div id="page-header-wrapper" class="clearfix">
-	        	<h1 class="headermain"><?php echo $PAGE->heading ?></h1>
-	    	    <div class="headermenu">
-    	    		<?php
-	    	    	    echo $OUTPUT->login_info();
-    	    	    	echo $OUTPUT->lang_menu();
-	        		    echo $PAGE->headingmenu;
-			        ?>
-		    	</div>
-	    	</div>
-	    </div>
+    <div id="wrapper" class="clearfix">
+
+        <div id="page-header">
+            <div id="page-header-wrapper" class="clearfix">
+                <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+                <div class="headermenu">
+                    <?php
+                        echo $OUTPUT->login_info();
+                        echo $OUTPUT->lang_menu();
+                        echo $PAGE->headingmenu;
+                    ?>
+                </div>
+            </div>
+        </div>
+
+        <?php if ($hascustommenu) { ?>
+            <div id="custommenu"><?php echo $custommenu; ?></div>
+        <?php } ?>
 
         <div class="clearer"></div> <!-- temporarily added on 06/25/10 -->
 
@@ -51,60 +60,60 @@ echo $OUTPUT->doctype() ?>
 
 <!-- START OF CONTENT -->
 
-		<div id="page-content-wrapper" class="clearfix">
-    		<div id="page-content">
-	    	    <div id="region-main-box">
-    	    	    <div id="region-post-box">
-
-        	    	    <div id="region-main-wrap">
-            	    	    <div id="region-main">
-                	    	    <div class="region-content">
-                    	    	    <?php echo $OUTPUT->main_content() ?>
-	                        	</div>
-		                    </div>
-    		            </div>
-
-        		        <?php if ($hassidepre) { ?>
-            		    <div id="region-pre">
-                		    <div class="region-content">
-                    		    <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
-		                    </div>
-    		            </div>
-        		        <?php } ?>
-
-	        	        <?php if ($hassidepost) { ?>
-    	        	    <div id="region-post">
-        	        	    <div class="region-content">
-            	        	    <?php echo $OUTPUT->blocks_for_region('side-post') ?>
-	                	    </div>
-		                </div>
-    		            <?php } ?>
-
-	        	    </div>
-	    	    </div>
-		    </div>
-		</div>
+        <div id="page-content-wrapper" class="clearfix">
+            <div id="page-content">
+                <div id="region-main-box">
+                    <div id="region-post-box">
+
+                        <div id="region-main-wrap">
+                            <div id="region-main">
+                                <div class="region-content">
+                                    <?php echo $OUTPUT->main_content() ?>
+                                </div>
+                            </div>
+                        </div>
+
+                        <?php if ($hassidepre) { ?>
+                        <div id="region-pre" class="block-region">
+                            <div class="region-content">
+                                <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
+                            </div>
+                        </div>
+                        <?php } ?>
+
+                        <?php if ($hassidepost) { ?>
+                        <div id="region-post" class="block-region">
+                            <div class="region-content">
+                                <?php echo $OUTPUT->blocks_for_region('side-post') ?>
+                            </div>
+                        </div>
+                        <?php } ?>
+
+                    </div>
+                </div>
+            </div>
+        </div>
 
 <!-- END OF CONTENT -->
 
 <!-- START OF FOOTER -->
 
-	    <div id="page-footer">
-    	    <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
+        <div id="page-footer">
+            <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
 
-	        <?php
-		        echo $OUTPUT->login_info();
-    		    echo $OUTPUT->home_link();
-        		echo $OUTPUT->standard_footer_html();
-	        ?>
-    	</div>
+            <?php
+                echo $OUTPUT->login_info();
+                echo $OUTPUT->home_link();
+                echo $OUTPUT->standard_footer_html();
+            ?>
+        </div>
 
 <!-- END OF FOOTER -->
 
-	</div> <!-- END #wrapper -->
+    </div> <!-- END #wrapper -->
 
 </div><!-- END #page -->
 
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/theme/canvas/layout/general.php b/theme/canvas/layout/general.php
index cda6005..5261314 100644
--- a/theme/canvas/layout/general.php
+++ b/theme/canvas/layout/general.php
@@ -3,17 +3,27 @@
 $hasheading = ($PAGE->heading);
 $hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
 $hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
+$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 $bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre && !$showsidepost) {
     $bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
+} else if ($showsidepost && !$showsidepre) {
     $bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else if (!$showsidepost && !$showsidepre) {
     $bodyclasses[] = 'content-only';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -49,6 +59,10 @@ echo $OUTPUT->doctype() ?>
             </div>
         </div>
 
+        <?php if ($hascustommenu) { ?>
+            <div id="custommenu"><?php echo $custommenu; ?></div>
+        <?php } ?>
+
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
                 <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
@@ -76,7 +90,7 @@ echo $OUTPUT->doctype() ?>
                         </div>
 
                         <?php if ($hassidepre) { ?>
-                        <div id="region-pre">
+                        <div id="region-pre" class="block-region">
                             <div class="region-content">
                                 <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
                             </div>
@@ -84,7 +98,7 @@ echo $OUTPUT->doctype() ?>
                         <?php } ?>
 
                         <?php if ($hassidepost) { ?>
-                        <div id="region-post">
+                        <div id="region-post" class="block-region">
                             <div class="region-content">
                                 <?php echo $OUTPUT->blocks_for_region('side-post') ?>
                             </div>
@@ -119,4 +133,4 @@ echo $OUTPUT->doctype() ?>
 
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/theme/canvas/layout/report.php b/theme/canvas/layout/report.php
index fce6e89..06607e3 100644
--- a/theme/canvas/layout/report.php
+++ b/theme/canvas/layout/report.php
@@ -3,17 +3,23 @@
 $hasheading = ($PAGE->heading);
 $hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
 $hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
 
 $bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre ) {
     $bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
-    $bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else {
     $bodyclasses[] = 'content-only';
 }
+if ($hascustommenu) {
+    $bodyclasses[] = 'has_custom_menu';
+}
 
 echo $OUTPUT->doctype() ?>
 <html <?php echo $OUTPUT->htmlattributes() ?>>
@@ -49,6 +55,10 @@ echo $OUTPUT->doctype() ?>
             </div>
         </div>
 
+        <?php if ($hascustommenu) { ?>
+            <div id="custommenu"><?php echo $custommenu; ?></div>
+        <?php } ?>
+
         <?php if ($hasnavbar) { ?>
             <div class="navbar clearfix">
                 <div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
@@ -106,4 +116,4 @@ echo $OUTPUT->doctype() ?>
 
 <?php echo $OUTPUT->standard_end_of_body_html() ?>
 </body>
-</html>
\ No newline at end of file
+</html>
-- 
1.7.9.5


From 7358b1742f4e416e0cca05166e098d55389a1ca0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 9 Oct 2012 23:04:51 +0200
Subject: [PATCH 805/903] MDL-35854 fix username generator

This eliminates infinite loop and also fixes potentially invalid email derived from usernames created from unicode first/last name.
---
 lib/phpunit/classes/data_generator.php |    6 ++++--
 lib/phpunit/tests/generator_test.php   |    5 +++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/lib/phpunit/classes/data_generator.php b/lib/phpunit/classes/data_generator.php
index 8225f23..8bfd798 100644
--- a/lib/phpunit/classes/data_generator.php
+++ b/lib/phpunit/classes/data_generator.php
@@ -156,9 +156,11 @@ EOD;
         }
 
         if (!isset($record['username'])) {
-            $record['username'] = textlib::strtolower($record['firstname']).textlib::strtolower($record['lastname']);
+            $record['username'] = 'username'.$i;
+            $j = 2;
             while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
-                $record['username'] = $record['username'].'_'.$i;
+                $record['username'] = 'username'.$i.'_'.$j;
+                $j++;
             }
         }
 
diff --git a/lib/phpunit/tests/generator_test.php b/lib/phpunit/tests/generator_test.php
index 316ee70..3787b34 100644
--- a/lib/phpunit/tests/generator_test.php
+++ b/lib/phpunit/tests/generator_test.php
@@ -44,6 +44,11 @@ class core_phpunit_generator_testcase extends advanced_testcase {
         $count = $DB->count_records('user');
         $user = $generator->create_user();
         $this->assertEquals($count+1, $DB->count_records('user'));
+        $this->assertSame($user->username, clean_param($user->username, PARAM_USERNAME));
+        $this->assertSame($user->email, clean_param($user->email, PARAM_EMAIL));
+        $user = $generator->create_user(array('firstname'=>'Žluťoučký', 'lastname'=>'Koníček'));
+        $this->assertSame($user->username, clean_param($user->username, PARAM_USERNAME));
+        $this->assertSame($user->email, clean_param($user->email, PARAM_EMAIL));
 
         $count = $DB->count_records('course_categories');
         $category = $generator->create_category();
-- 
1.7.9.5


From ad7d20c3803f9f373cb3780acc72badb6aacdfba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 9 Oct 2012 14:50:13 +0200
Subject: [PATCH 806/903] MDL-35469 fix Gecko based browser checks

The problem is that latest firefox versions stopped using dates because they lost the meaning over the time.
---
 lib/moodlelib.php |   45 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 167a653..ce332ff 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -8393,18 +8393,45 @@ function check_php_version($version='5.2.4') {
 
 
       case 'Gecko':   /// Gecko based browsers
-          if (empty($version) and substr_count($agent, 'Camino')) {
-              // MacOS X Camino support
-              $version = 20041110;
+          // Do not look for dates any more, we expect real Firefox version here.
+          if (empty($version)) {
+              $version = 1;
+          } else if ($version > 20000000) {
+              // This is just a guess, it is not supposed to be 100% accurate!
+              if (preg_match('/^201/', $version)) {
+                  $version = 3.6;
+              } else if (preg_match('/^200[7-9]/', $version)) {
+                  $version = 3;
+              } else if (preg_match('/^2006/', $version)) {
+                  $version = 2;
+              } else {
+                  $version = 1.5;
+              }
           }
-
-          // the proper string - Gecko/CCYYMMDD Vendor/Version
-          // Faster version and work-a-round No IDN problem.
-          if (preg_match("/Gecko\/([0-9]+)/i", $agent, $match)) {
-              if ($match[1] > $version) {
-                      return true;
+          if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $agent, $match)) {
+              // Use real Firefox version if specified in user agent string.
+              if (version_compare($match[2], $version) >= 0) {
+                  return true;
+              }
+          } else if (preg_match("/Gecko\/([0-9\.]+)/i", $agent, $match)) {
+              // Gecko might contain date or Firefox revision, let's just guess the Firefox version from the date.
+              $browserver = $match[1];
+              if ($browserver > 20000000) {
+                  // This is just a guess, it is not supposed to be 100% accurate!
+                  if (preg_match('/^201/', $browserver)) {
+                      $browserver = 3.6;
+                  } else if (preg_match('/^200[7-9]/', $browserver)) {
+                      $browserver = 3;
+                  } else if (preg_match('/^2006/', $version)) {
+                      $browserver = 2;
+                  } else {
+                      $browserver = 1.5;
                   }
               }
+              if (version_compare($browserver, $version) >= 0) {
+                  return true;
+              }
+          }
           break;
 
 
-- 
1.7.9.5


From a4848f6ef76b6e165397e9d51faf88706a4e4dc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Tue, 9 Oct 2012 15:48:27 +0200
Subject: [PATCH 807/903] MDL-35469 test for the new Gecko user agent handling

---
 lib/tests/moodlelib_test.php |  120 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 118 insertions(+), 2 deletions(-)

diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 6beb856..521252a 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -49,8 +49,17 @@ class moodlelib_testcase extends advanced_testcase {
             '1.5'     => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8) Gecko/20051107 Firefox/1.5'),
             '1.5.0.1' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1'),
             '2.0'     => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1',
-                'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)'),
-            '3.0.6' => array('SUSE' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6'),
+                               'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)'),
+            '3.0.6'   => array('SUSE' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6'),
+            '3.6'     => array('Linux' => 'Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/3.6'),
+            '11.0'    => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko Firefox/11.0'),
+            '15.0a2'  => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2'),
+            '18.0'    => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/18.0 Firefox/18.0'),
+        ),
+        'SeaMonkey' => array(
+            '2.0' => array('Windows' => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0'),
+            '2.1' => array('Linux' => 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110609 Firefox/4.0.1 SeaMonkey/2.1'),
+            '2.3' => array('FreeBSD' => 'Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0) Gecko/20110818 Firefox/6.0 SeaMonkey/2.3'),
         ),
         'Safari' => array(
             '312' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312'),
@@ -248,6 +257,113 @@ class moodlelib_testcase extends advanced_testcase {
         $this->assertTrue(check_browser_version('Firefox'));
         $this->assertTrue(check_browser_version('Firefox', '1.5'));
         $this->assertFalse(check_browser_version('Firefox', '3.0'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.0.6']['Windows XP'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Gecko', '1'));
+        $this->assertFalse(check_browser_version('Gecko', 20030516));
+        $this->assertFalse(check_browser_version('Gecko', 20051106));
+        $this->assertFalse(check_browser_version('Gecko', 2006010100));
+        $this->assertFalse(check_browser_version('Firefox', '1.5'));
+        $this->assertFalse(check_browser_version('Firefox', '3.0'));
+        $this->assertFalse(check_browser_version('Gecko', '2'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', '1.5'));
+        $this->assertTrue(check_browser_version('Gecko', '1'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertFalse(check_browser_version('Firefox', '3.0'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', '1.5'));
+        $this->assertTrue(check_browser_version('Firefox', '3.0'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', '3.6'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertFalse(check_browser_version('Firefox', '4'));
+        $this->assertFalse(check_browser_version('Firefox', '10'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', '1.5'));
+        $this->assertTrue(check_browser_version('Firefox', '3.0'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', '3.6'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertFalse(check_browser_version('Firefox', '4'));
+        $this->assertFalse(check_browser_version('Firefox', '10'));
+        $this->assertFalse(check_browser_version('Firefox', '18'));
+        $this->assertFalse(check_browser_version('Gecko', '4'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['15.0a2']['Windows'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', '1.5'));
+        $this->assertTrue(check_browser_version('Firefox', '3.0'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', '3.6'));
+        $this->assertTrue(check_browser_version('Gecko', '15.0'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertTrue(check_browser_version('Firefox', '4'));
+        $this->assertTrue(check_browser_version('Firefox', '10'));
+        $this->assertTrue(check_browser_version('Firefox', '15'));
+        $this->assertFalse(check_browser_version('Firefox', '18'));
+        $this->assertFalse(check_browser_version('Gecko', '18'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['18.0']['Mac OS X'];
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', '1.5'));
+        $this->assertTrue(check_browser_version('Firefox', '3.0'));
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', '3.6'));
+        $this->assertTrue(check_browser_version('Gecko', '15.0'));
+        $this->assertTrue(check_browser_version('Gecko', '18.0'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertTrue(check_browser_version('Firefox', '4'));
+        $this->assertTrue(check_browser_version('Firefox', '10'));
+        $this->assertTrue(check_browser_version('Firefox', '15'));
+        $this->assertTrue(check_browser_version('Firefox', '18'));
+        $this->assertFalse(check_browser_version('Firefox', '19'));
+        $this->assertFalse(check_browser_version('Gecko', '19'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.0']['Windows'];
+
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertFalse(check_browser_version('Gecko', '3.6'));
+        $this->assertFalse(check_browser_version('Gecko', '4.0'));
+        $this->assertFalse(check_browser_version('Firefox'));
+
+        $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.1']['Linux'];
+        $this->assertTrue(check_browser_version('Gecko', '2'));
+        $this->assertTrue(check_browser_version('Gecko', '3.6'));
+        $this->assertTrue(check_browser_version('Gecko', '4.0'));
+        $this->assertTrue(check_browser_version('Gecko', 20030516));
+        $this->assertTrue(check_browser_version('Gecko', 20051106));
+        $this->assertTrue(check_browser_version('Gecko', 2006010100));
+        $this->assertTrue(check_browser_version('Firefox'));
+        $this->assertTrue(check_browser_version('Firefox', 4.0));
+        $this->assertFalse(check_browser_version('Firefox', 5));
+        $this->assertFalse(check_browser_version('Gecko', '18.0'));
+
     }
 
     function test_get_browser_version_classes() {
-- 
1.7.9.5


From b66c3031f63a1a97320767673a9a9f35a4076e9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 13 Oct 2012 17:54:30 +0200
Subject: [PATCH 808/903] MDL-35917 fix cohort phpdocs

Credit goes to Brian Kremer, thanks!
---
 cohort/lib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cohort/lib.php b/cohort/lib.php
index 367b19e..4ab8ab7 100644
--- a/cohort/lib.php
+++ b/cohort/lib.php
@@ -126,7 +126,7 @@ function cohort_delete_category($category) {
 }
 
 /**
- * Remove cohort member
+ * Add cohort member
  * @param  int $cohortid
  * @param  int $userid
  * @return void
@@ -143,7 +143,7 @@ function cohort_add_member($cohortid, $userid) {
 }
 
 /**
- * Add cohort member
+ * Remove cohort member
  * @param  int $cohortid
  * @param  int $userid
  * @return void
-- 
1.7.9.5


From 8d800a1b8e31aa6f57f33f42cce9cb51c8bd7fd1 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Sun, 14 Oct 2012 23:22:08 +0200
Subject: [PATCH 809/903] Revert "MDL-31968 Make NTLM REMOTE_USER format
 configurable by the admin"

This reverts commit af861e14dc5c83a5f4d142a0d13de1eb7467349b.

Note that MDL-31968 will be in charge of backporting this to stables
if everything goes well under master (once MDL-31968 is tested and closed)
---
 auth/ldap/auth.php              |   79 +--------------------------------------
 auth/ldap/config.html           |   15 --------
 auth/ldap/lang/en/auth_ldap.php |    4 --
 3 files changed, 2 insertions(+), 96 deletions(-)

diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php
index c206452..88bb10d 100644
--- a/auth/ldap/auth.php
+++ b/auth/ldap/auth.php
@@ -41,18 +41,6 @@ if (!defined('AUTH_GID_NOGROUP')) {
     define('AUTH_GID_NOGROUP', -2);
 }
 
-// Regular expressions for a valid NTLM username and domain name.
-if (!defined('AUTH_NTLM_VALID_USERNAME')) {
-    define('AUTH_NTLM_VALID_USERNAME', '[^/\\\\\\\\\[\]:;|=,+*?<>@"]+');
-}
-if (!defined('AUTH_NTLM_VALID_DOMAINNAME')) {
-    define('AUTH_NTLM_VALID_DOMAINNAME', '[^\\\\\\\\\/:*?"<>|]+');
-}
-// Default format for remote users if using NTLM SSO
-if (!defined('AUTH_NTLM_DEFAULT_FORMAT')) {
-    define('AUTH_NTLM_DEFAULT_FORMAT', '%domain%\\%username%');
-}
-
 require_once($CFG->libdir.'/authlib.php');
 require_once($CFG->libdir.'/ldaplib.php');
 
@@ -1582,11 +1570,8 @@ class auth_plugin_ldap extends auth_plugin_base {
 
             switch ($this->config->ntlmsso_type) {
                 case 'ntlm':
-                    // The format is now configurable, so try to extract the username
-                    $username = $this->get_ntlm_remote_user($username);
-                    if (empty($username)) {
-                        return false;
-                    }
+                    // Format is DOMAIN\username
+                    $username = substr(strrchr($username, '\\'), 1);
                     break;
                 case 'kerberos':
                     // Format is username@DOMAIN
@@ -1794,9 +1779,6 @@ class auth_plugin_ldap extends auth_plugin_base {
         if (!isset($config->ntlmsso_type)) {
             $config->ntlmsso_type = 'ntlm';
         }
-        if (!isset($config->ntlmsso_remoteuserformat)) {
-            $config->ntlmsso_remoteuserformat = '';
-        }
 
         // Try to remove duplicates before storing the contexts (to avoid problems in sync_users()).
         $config->contexts = explode(';', $config->contexts);
@@ -1836,7 +1818,6 @@ class auth_plugin_ldap extends auth_plugin_base {
         set_config('ntlmsso_subnet', trim($config->ntlmsso_subnet), $this->pluginconfig);
         set_config('ntlmsso_ie_fastpath', (int)$config->ntlmsso_ie_fastpath, $this->pluginconfig);
         set_config('ntlmsso_type', $config->ntlmsso_type, 'auth/ldap');
-        set_config('ntlmsso_remoteuserformat', trim($config->ntlmsso_remoteuserformat), 'auth/ldap');
 
         return true;
     }
@@ -2037,60 +2018,4 @@ class auth_plugin_ldap extends auth_plugin_base {
                                 $this->config->user_attribute, $this->config->search_sub);
     }
 
-
-    /**
-     * A chance to validate form data, and last chance to do stuff
-     * before it is inserted in config_plugin
-     *
-     * @param object object with submitted configuration settings (without system magic quotes)
-     * @param array $err array of error messages (passed by reference)
-     */
-    function validate_form($form, &$err) {
-        if ($form->ntlmsso_type == 'ntlm') {
-            $format = trim($form->ntlmsso_remoteuserformat);
-            if (!empty($format) && !preg_match('/%username%/i', $format)) {
-                $err['ntlmsso_remoteuserformat'] = get_string('auth_ntlmsso_missing_username', 'auth_ldap');
-            }
-        }
-    }
-
-
-    /**
-     * When using NTLM SSO, the format of the remote username we get in
-     * $_SERVER['REMOTE_USER'] may vary, depending on where from and how the web
-     * server gets the data. So we let the admin configure the format using two
-     * place holders (%domain% and %username%). This function tries to extract
-     * the username (stripping the domain part and any separators if they are
-     * present) from the value present in $_SERVER['REMOTE_USER'], using the
-     * configured format.
-     *
-     * @param string $remoteuser The value from $_SERVER['REMOTE_USER'] (converted to UTF-8)
-     *
-     * @return string The remote username (without domain part or
-     *                separators). Empty string if we can't extract the username.
-     */
-    protected function get_ntlm_remote_user($remoteuser) {
-        if (empty($this->config->ntlmsso_remoteuserformat)) {
-            $format = AUTH_NTLM_DEFAULT_FORMAT;
-        } else {
-            $format = $this->config->ntlmsso_remoteuserformat;
-        }
-
-        $format = preg_quote($format);
-        $formatregex = preg_replace(array('#%domain%#', '#%username%#'),
-                                    array('('.AUTH_NTLM_VALID_DOMAINNAME.')', '('.AUTH_NTLM_VALID_USERNAME.')'),
-                                    $format);
-        if (preg_match('#^'.$formatregex.'$#', $remoteuser, $matches)) {
-            $user = end($matches);
-            return $user;
-        }
-
-        /* We are unable to extract the username with the configured format. Probably
-         * the format specified is wrong, so log a warning for the admin and return
-         * an empty username.
-         */
-        error_log($this->errorlogtag.get_string ('auth_ntlmsso_maybeinvalidformat', 'auth_ldap'));
-        return '';
-    }
-
 } // End of the class
diff --git a/auth/ldap/config.html b/auth/ldap/config.html
index 3efe253..8ad27ef 100644
--- a/auth/ldap/config.html
+++ b/auth/ldap/config.html
@@ -94,9 +94,6 @@ if (!isset($config->ntlmsso_ie_fastpath)) {
 if (!isset($config->ntlmsso_type)) {
     $config->ntlmsso_type = 'ntlm';
 }
-if (!isset($config->ntlmsso_remoteuserformat)) {
-    $config->ntlmsso_remoteuserformat = '';
-}
 
 $yesno = array(get_string('no'), get_string('yes'));
 
@@ -542,18 +539,6 @@ $yesno = array(get_string('no'), get_string('yes'));
         <?php print_string('auth_ntlmsso_type','auth_ldap') ?>
     </td>
 </tr>
-<tr valign="top">
-    <td align="right">
-        <label for="ntlmsso_remoteuserformat"><?php print_string('auth_ntlmsso_remoteuserformat_key', 'auth_ldap') ?></label>
-    </td>
-    <td>
-        <input name="ntlmsso_remoteuserformat" id="ntlmsso_remoteuserformat" type="text" size="30" value="<?php echo $config->ntlmsso_remoteuserformat?>" />
-        <?php if (isset($err['ntlmsso_remoteuserformat'])) { echo $OUTPUT->error_text($err['ntlmsso_remoteuserformat']); } ?>
-    </td>
-    <td>
-        <?php print_string('auth_ntlmsso_remoteuserformat', 'auth_ldap') ?>
-    </td>
-</tr>
 <?php
 $help  = get_string('auth_ldapextrafields', 'auth_ldap');
 $help .= get_string('auth_updatelocal_expl', 'auth');
diff --git a/auth/ldap/lang/en/auth_ldap.php b/auth/ldap/lang/en/auth_ldap.php
index 848169a..bbb0ddb 100644
--- a/auth/ldap/lang/en/auth_ldap.php
+++ b/auth/ldap/lang/en/auth_ldap.php
@@ -101,10 +101,6 @@ $string['auth_ntlmsso_enabled'] = 'Set to yes to attempt Single Sign On with the
 $string['auth_ntlmsso_enabled_key'] = 'Enable';
 $string['auth_ntlmsso_ie_fastpath'] = 'Set to yes to enable the NTLM SSO fast path (bypasses certain steps and only works if the client\'s browser is MS Internet Explorer).';
 $string['auth_ntlmsso_ie_fastpath_key'] = 'MS IE fast path?';
-$string['auth_ntlmsso_maybeinvalidformat'] = 'Unable to extract the username from the REMOTE_USER header. Is the configured format right?';
-$string['auth_ntlmsso_missing_username'] = 'You need to specify at least %username% in the remote username format';
-$string['auth_ntlmsso_remoteuserformat_key'] = 'Remote username format';
-$string['auth_ntlmsso_remoteuserformat'] = 'If you have chosen \'NTLM\' in \'Authentication type\', you can specify the remote username format here. If you leave this empty, the default DOMAIN\\username format will be used. You can use the optional <b>%domain%</b> placeholder to specify where the domain name appears, and the mandatory <b>%username%</b> placeholder to specify where the username appears. <br /><br />Some widely used formats are <tt>%domain%\\%username%</tt> (MS Windows default), <tt>%domain%/%username%</tt>, <tt>%domain%+%username%</tt> and just <tt>%username%</tt> (if there is no domain part).';
 $string['auth_ntlmsso_subnet'] = 'If set, it will only attempt SSO with clients in this subnet. Format: xxx.xxx.xxx.xxx/bitmask. Separate multiple subnets with \',\' (comma).';
 $string['auth_ntlmsso_subnet_key'] = 'Subnet';
 $string['auth_ntlmsso_type_key'] = 'Authentication type';
-- 
1.7.9.5


From 6738413b335155cea349082d57a8781bc9c5fd4a Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Mon, 15 Oct 2012 00:20:33 +0200
Subject: [PATCH 810/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index a5b0b9a..4fc7f14 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.05;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.06;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121005)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121014)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 887d6e175e5bf198c3278354f78fe674d6373843 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Mon, 15 Oct 2012 00:34:57 +0000
Subject: [PATCH 811/903] Automatically generated installer lang files

---
 install/lang/bg/install.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/bg/install.php b/install/lang/bg/install.php
index f3bdac4..ff283b1 100644
--- a/install/lang/bg/install.php
+++ b/install/lang/bg/install.php
@@ -51,4 +51,5 @@ $string['pathssubdataroot'] = 'Тази директория е място, къ
 $string['pathssubdirroot'] = 'Пълен път до директорията на Moodle.';
 $string['pathssubwwwroot'] = 'Пълен интернет адрес, на който ще се отваря Moodle. Не е възможно Moodle да се отваря чрез различни адреси. Ако Вашият сайт има няколко адреса трябва на всеки от другите адреси да направите пренасочване към този. Ако Вашият сайт се отваря както глобално от Интернет, така и от локална мрежа, настройте DNS, така че потребителите от локалната мрежа също да могат да ползват глобалния адрес. Ако адресът не е коректен, моля, променете адреса в браузъра си и започнете инсталирането с правилния адрес.';
 $string['phpextension'] = '{$a} разширение на PHP';
+$string['phpversionhelp'] = '<p>Moodle изисква версия на PHP най-малко 4.3.0 или 5.1.0 (5.0.x има значителен брой известни проблеми).</p> <p>Вие използвате в момента версия {$a}</p> <p>Трябва да обновите PHP или да се преместите на нов хост (сървър) с по-нова версия на PHP!<br /> (В случая с 5.0.x може да опитате да инсталирате по-старата версия 4.4.x)</p>';
 $string['wwwroot'] = 'Уеб адрес';
-- 
1.7.9.5


From 82525f5963b2a288dfa9c01201e62dea8bfbc788 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 9 Oct 2012 11:12:37 +0800
Subject: [PATCH 812/903] MDL-35664 filepicker: Filepicker knows about the
 current path and uses it

---
 repository/filepicker.js |   32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/repository/filepicker.js b/repository/filepicker.js
index 9654045..5e848cf 100644
--- a/repository/filepicker.js
+++ b/repository/filepicker.js
@@ -16,6 +16,7 @@
  * this.viewmode, store current view mode
  * this.pathbar, reference to the Node with path bar
  * this.pathnode, a Node element representing one folder in a path bar (not attached anywhere, just used for template)
+ * this.currentpath, the current path in the repository (or last requested path)
  *
  * Filepicker options:
  * =====
@@ -39,7 +40,7 @@
  * this.filelist, cached filelist
  * this.pages
  * this.page
- * this.filepath, current path
+ * this.filepath, current path (each element of the array is a part of the breadcrumb)
  * this.logindata, cached login form
  */
 
@@ -932,6 +933,7 @@ M.core_filepicker.init = function(Y, options) {
                         // save current path and filelist (in case we want to jump to other viewmode)
                         this.filepath = e.node.origpath;
                         this.filelist = e.node.origlist;
+                        this.currentpath = e.node.path;
                         this.print_path();
                         this.content_scrolled();
                     }
@@ -967,7 +969,6 @@ M.core_filepicker.init = function(Y, options) {
                         if (this.active_repo.dynload) {
                             this.list({'path':node.path});
                         } else {
-                            this.filepath = node.path;
                             this.filelist = node.children;
                             this.view_files();
                         }
@@ -1002,7 +1003,6 @@ M.core_filepicker.init = function(Y, options) {
                         if (this.active_repo.dynload) {
                             this.list({'path':node.path});
                         } else {
-                            this.filepath = node.path;
                             this.filelist = node.children;
                             this.view_files();
                         }
@@ -1022,9 +1022,13 @@ M.core_filepicker.init = function(Y, options) {
             }
             this.active_repo.nextpagerequested = true;
             var nextpage = this.active_repo.page+1;
-            var args = {page:nextpage, repo_id:this.active_repo.id, path:this.active_repo.path};
+            var args = {
+                page: nextpage,
+                repo_id: this.active_repo.id,
+            };
             var action = this.active_repo.issearchresult ? 'search' : 'list';
             this.request({
+                path: this.currentpath,
                 scope: this,
                 action: action,
                 client_id: this.options.client_id,
@@ -1032,10 +1036,20 @@ M.core_filepicker.init = function(Y, options) {
                 params: args,
                 callback: function(id, obj, args) {
                     var scope = args.scope;
-                    // check that we are still in the same repository and are expecting this page
+                    // Check that we are still in the same repository and are expecting this page. We have no way
+                    // to compare the requested page and the one returned, so we assume that if the last chunk
+                    // of the breadcrumb is similar, then we probably are on the same page.
+                    var samepage = true;
+                    if (obj.path && scope.filepath) {
+                        var pathbefore = scope.filepath[scope.filepath.length-1];
+                        var pathafter = obj.path[obj.path.length-1];
+                        if (pathbefore.path != pathafter.path) {
+                            samepage = false;
+                        }
+                    }
                     if (scope.active_repo.hasmorepages && obj.list && obj.page &&
                             obj.repo_id == scope.active_repo.id &&
-                            obj.page == scope.active_repo.page+1 && obj.path == scope.path) {
+                            obj.page == scope.active_repo.page+1 && samepage) {
                         scope.parse_repository_options(obj, true);
                         scope.view_files(obj.list)
                     }
@@ -1564,6 +1578,10 @@ M.core_filepicker.init = function(Y, options) {
             if (!args.repo_id) {
                 args.repo_id = this.active_repo.id;
             }
+            if (!args.path) {
+                args.path = '';
+            }
+            this.currentpath = args.path;
             this.request({
                 action: 'list',
                 client_id: this.options.client_id,
@@ -1707,7 +1725,7 @@ M.core_filepicker.init = function(Y, options) {
             toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
                 e.preventDefault();
                 if (!this.active_repo.norefresh) {
-                    this.list();
+                    this.list({ path: this.currentpath });
                 }
             }, this);
             toolbar.one('.fp-tb-search form').
-- 
1.7.9.5


From 4f977aea5e185c933cc0624aa873d4c106a2095e Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 9 Oct 2012 11:01:39 +0800
Subject: [PATCH 813/903] MDL-35892 repository: prepare_listing recursively
 prepares the data

---
 repository/lib.php |  115 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 75 insertions(+), 40 deletions(-)

diff --git a/repository/lib.php b/repository/lib.php
index b416284..f60bed4 100644
--- a/repository/lib.php
+++ b/repository/lib.php
@@ -2018,59 +2018,56 @@ abstract class repository {
     public function get_listing($path = '', $page = '') {
     }
 
+
     /**
-     * Prepares list of files before passing it to AJAX, makes sure data is in the correct
-     * format and stores formatted values.
+     * Prepare the breadcrumb.
      *
-     * @param array|stdClass $listing result of get_listing() or search() or file_get_drafarea_files()
-     * @return array
+     * @param array $breadcrumb contains each element of the breadcrumb.
+     * @return array of breadcrumb elements.
+     * @since 2.3.3
      */
-    public static function prepare_listing($listing) {
+    protected static function prepare_breadcrumb($breadcrumb) {
         global $OUTPUT;
-
-        $defaultfoldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
-        // prepare $listing['path'] or $listing->path
-        if (is_array($listing) && isset($listing['path']) && is_array($listing['path'])) {
-            $path = &$listing['path'];
-        } else if (is_object($listing) && isset($listing->path) && is_array($listing->path)) {
-            $path = &$listing->path;
-        }
-        if (isset($path)) {
-            $len = count($path);
-            for ($i=0; $i<$len; $i++) {
-                if (is_array($path[$i]) && !isset($path[$i]['icon'])) {
-                    $path[$i]['icon'] = $defaultfoldericon;
-                } else if (is_object($path[$i]) && !isset($path[$i]->icon)) {
-                    $path[$i]->icon = $defaultfoldericon;
-                }
+        $foldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
+        $len = count($breadcrumb);
+        for ($i = 0; $i < $len; $i++) {
+            if (is_array($breadcrumb[$i]) && !isset($breadcrumb[$i]['icon'])) {
+                $breadcrumb[$i]['icon'] = $foldericon;
+            } else if (is_object($breadcrumb[$i]) && !isset($breadcrumb[$i]->icon)) {
+                $breadcrumb[$i]->icon = $foldericon;
             }
         }
+        return $breadcrumb;
+    }
 
-        // prepare $listing['list'] or $listing->list
-        if (is_array($listing) && isset($listing['list']) && is_array($listing['list'])) {
-            $listing['list'] = array_values($listing['list']); // convert to array
-            $files = &$listing['list'];
-        } else if (is_object($listing) && isset($listing->list) && is_array($listing->list)) {
-            $listing->list = array_values($listing->list); // convert to array
-            $files = &$listing->list;
-        } else {
-            return $listing;
-        }
-        $len = count($files);
-        for ($i=0; $i<$len; $i++) {
-            if (is_object($files[$i])) {
-                $file = (array)$files[$i];
+    /**
+     * Prepare the file/folder listing.
+     *
+     * @param array $list of files and folders.
+     * @return array of files and folders.
+     * @since 2.3.3
+     */
+    protected static function prepare_list($list) {
+        global $OUTPUT;
+        $foldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
+
+        // Reset the array keys because non-numeric keys will create an object when converted to JSON.
+        $list = array_values($list);
+
+        $len = count($list);
+        for ($i = 0; $i < $len; $i++) {
+            if (is_object($list[$i])) {
+                $file = (array)$list[$i];
                 $converttoobject = true;
             } else {
-                $file = & $files[$i];
+                $file =& $list[$i];
                 $converttoobject = false;
             }
             if (isset($file['size'])) {
                 $file['size'] = (int)$file['size'];
                 $file['size_f'] = display_size($file['size']);
             }
-            if (isset($file['license']) &&
-                    get_string_manager()->string_exists($file['license'], 'license')) {
+            if (isset($file['license']) && get_string_manager()->string_exists($file['license'], 'license')) {
                 $file['license_f'] = get_string($file['license'], 'license');
             }
             if (isset($file['image_width']) && isset($file['image_height'])) {
@@ -2105,15 +2102,53 @@ abstract class repository {
             }
             if (!isset($file['icon'])) {
                 if ($isfolder) {
-                    $file['icon'] = $defaultfoldericon;
+                    $file['icon'] = $foldericon;
                 } else if ($filename) {
                     $file['icon'] = $OUTPUT->pix_url(file_extension_icon($filename, 24))->out(false);
                 }
             }
+
+            // Recursively loop over children.
+            if (isset($file['children'])) {
+                $file['children'] = self::prepare_list($file['children']);
+            }
+
+            // Convert the array back to an object.
             if ($converttoobject) {
-                $files[$i] = (object)$file;
+                $list[$i] = (object)$file;
             }
         }
+        return $list;
+    }
+
+    /**
+     * Prepares list of files before passing it to AJAX, makes sure data is in the correct
+     * format and stores formatted values.
+     *
+     * @param array|stdClass $listing result of get_listing() or search() or file_get_drafarea_files()
+     * @return array
+     */
+    public static function prepare_listing($listing) {
+        $wasobject = false;
+        if (is_object($listing)) {
+            $listing = (array) $listing;
+            $wasobject = true;
+        }
+
+        // Prepare the breadcrumb, passed as 'path'.
+        if (isset($listing['path']) && is_array($listing['path'])) {
+            $listing['path'] = self::prepare_breadcrumb($listing['path']);
+        }
+
+        // Prepare the listing of objects.
+        if (isset($listing['list']) && is_array($listing['list'])) {
+            $listing['list'] = self::prepare_list($listing['list']);
+        }
+
+        // Convert back to an object.
+        if ($wasobject) {
+            $listing = (object) $listing;
+        }
         return $listing;
     }
 
-- 
1.7.9.5


From 4981d1242011f0360640b6b4f4bee6b7b4f07174 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Mon, 15 Oct 2012 10:56:34 +0800
Subject: [PATCH 814/903] MDL-35889 blocks: Adding a legend to the fieldset

---
 blocks/search_forums/block_search_forums.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/blocks/search_forums/block_search_forums.php b/blocks/search_forums/block_search_forums.php
index cf22705..0e780f1 100644
--- a/blocks/search_forums/block_search_forums.php
+++ b/blocks/search_forums/block_search_forums.php
@@ -27,6 +27,7 @@ class block_search_forums extends block_base {
 
         $this->content->text  = '<div class="searchform">';
         $this->content->text .= '<form action="'.$CFG->wwwroot.'/mod/forum/search.php" style="display:inline"><fieldset class="invisiblefieldset">';
+        $this->content->text .= '<legend class="accesshide">'.$strsearch.'</legend>';
         $this->content->text .= '<input name="id" type="hidden" value="'.$this->page->course->id.'" />';  // course
         $this->content->text .= '<label class="accesshide" for="searchform_search">'.$strsearch.'</label>'.
                                 '<input id="searchform_search" name="search" type="text" size="16" />';
-- 
1.7.9.5


From 46ba9fded8ac1c4abd20f9b760612fc3b7705ffd Mon Sep 17 00:00:00 2001
From: Mark Nielsen <mark@moodlerooms.com>
Date: Mon, 15 Oct 2012 16:48:21 +0800
Subject: [PATCH 815/903] MDL-33621 rating: fixed view help error for global
 scale rating

---
 lib/outputrenderers.php |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index dd03dc8..b263027 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1638,7 +1638,13 @@ class core_renderer extends renderer_base {
             $ratinghtml .= html_writer::empty_tag('input', $attributes);
 
             if (!$rating->settings->scale->isnumeric) {
-                $ratinghtml .= $this->help_icon_scale($rating->settings->scale->courseid, $rating->settings->scale);
+                // If a global scale, try to find current course ID from the context
+                if (empty($rating->settings->scale->courseid) and $coursecontext = $rating->context->get_course_context(false)) {
+                    $courseid = $coursecontext->instanceid;
+                } else {
+                    $courseid = $rating->settings->scale->courseid;
+                }
+                $ratinghtml .= $this->help_icon_scale($courseid, $rating->settings->scale);
             }
             $ratinghtml .= html_writer::end_tag('span');
             $ratinghtml .= html_writer::end_tag('div');
-- 
1.7.9.5


From 6e763244ed799bb4eb4fc4f049429f9b99b90f86 Mon Sep 17 00:00:00 2001
From: Mark Nielsen <mark@moodlerooms.com>
Date: Mon, 15 Oct 2012 17:18:34 +0800
Subject: [PATCH 816/903] MDL-34837 backup: Restore does not fail when some
 courses have the same name

---
 backup/util/dbops/restore_dbops.class.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php
index fb7beb3..e856ead 100644
--- a/backup/util/dbops/restore_dbops.class.php
+++ b/backup/util/dbops/restore_dbops.class.php
@@ -1505,7 +1505,8 @@ abstract class restore_dbops {
             }
             $currentfullname = $fullname.$suffixfull;
             $currentshortname = substr($shortname, 0, 100 - strlen($suffixshort)).$suffixshort; // < 100cc
-            $coursefull  = $DB->get_record_select('course', 'fullname = ? AND id != ?', array($currentfullname, $courseid));
+            $coursefull  = $DB->get_record_select('course', 'fullname = ? AND id != ?',
+                    array($currentfullname, $courseid), '*', IGNORE_MULTIPLE);
             $courseshort = $DB->get_record_select('course', 'shortname = ? AND id != ?', array($currentshortname, $courseid));
             $counter++;
         } while ($coursefull || $courseshort);
-- 
1.7.9.5


From caa0e70577066e4ad96fc58b6125246af0afc63f Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Tue, 9 Oct 2012 15:56:40 +0800
Subject: [PATCH 817/903] MDL-25275 - mod/data - Added a check box to
 eliminate date searches if desired.

---
 mod/data/field/date/field.class.php |   26 ++++++++++++++------------
 mod/data/lang/en/data.php           |    1 +
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php
index 313058c..2fa245d 100644
--- a/mod/data/field/date/field.class.php
+++ b/mod/data/field/date/field.class.php
@@ -55,12 +55,13 @@ class data_field_date extends data_field_base {
 
     //Enable the following three functions once core API issues have been addressed.
     function display_search_field($value=0) {
-        $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
-           . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value)
-           . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value);
-       return $selectors;
+        $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value['timestamp'])
+           . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value['timestamp'])
+           . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value['timestamp']);
+        $datecheck = html_writer::checkbox('f_'.$this->field->id.'_z', 1, $value['usedate']);
+        $str = $selectors . ' ' . $datecheck . ' ' . get_string('usedate', 'data');
 
-        //return print_date_selector('f_'.$this->field->id.'_d', 'f_'.$this->field->id.'_m', 'f_'.$this->field->id.'_y', $value, true);
+        return $str;
     }
 
     function generate_sql($tablealias, $value) {
@@ -70,21 +71,22 @@ class data_field_date extends data_field_base {
         $i++;
         $name = "df_date_$i";
         $varcharcontent = $DB->sql_compare_text("{$tablealias}.content");
-        return array(" ({$tablealias}.fieldid = {$this->field->id} AND $varcharcontent = :$name) ", array($name=>$value));
+        return array(" ({$tablealias}.fieldid = {$this->field->id} AND $varcharcontent = :$name) ", array($name => $value['timestamp']));
     }
 
     function parse_search_field() {
-
         $day   = optional_param('f_'.$this->field->id.'_d', 0, PARAM_INT);
         $month = optional_param('f_'.$this->field->id.'_m', 0, PARAM_INT);
         $year  = optional_param('f_'.$this->field->id.'_y', 0, PARAM_INT);
-        if (!empty($day) && !empty($month) && !empty($year)) {
-            return make_timestamp($year, $month, $day, 12, 0, 0, 0, false);
-        }
-        else {
+        $usedate = optional_param('f_'.$this->field->id.'_z', 0, PARAM_INT);
+        $data = array();
+        if (!empty($day) && !empty($month) && !empty($year) && $usedate == 1) {
+            $data['timestamp'] = make_timestamp($year, $month, $day, 12, 0, 0, 0, false);
+            $data['usedate'] = 1;
+            return $data;
+        } else {
             return 0;
         }
-
     }
 
     function update_content($recordid, $value, $name='') {
diff --git a/mod/data/lang/en/data.php b/mod/data/lang/en/data.php
index ed005e6..53887ec 100644
--- a/mod/data/lang/en/data.php
+++ b/mod/data/lang/en/data.php
@@ -338,6 +338,7 @@ $string['uploadrecords_help'] = 'Entries may be uploaded via text file. The form
 The field enclosure is a character that surrounds each field in each record. It can normally be left unset.';
 $string['uploadrecords_link'] = 'mod/data/import';
 $string['url'] = 'Url';
+$string['usedate'] = 'Include in search.';
 $string['usestandard'] = 'Use a preset';
 $string['usestandard_help'] = 'To use a preset available to the whole site, select it from the list. (If you have added a preset to the list using the save as preset feature then you have the option of deleting it.)';
 $string['viewfromdate'] = 'Read only from';
-- 
1.7.9.5


From 25ba0f48399d3b115f4007a1f4fb45d4179dbb2b Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 16 Oct 2012 10:26:33 +0800
Subject: [PATCH 818/903] MDL-21801 - mod_lesson: version bump

To reflect the new (ppt-less) state
---
 mod/lesson/version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/lesson/version.php b/mod/lesson/version.php
index e663af6..d75f2aa 100644
--- a/mod/lesson/version.php
+++ b/mod/lesson/version.php
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700;    // Requires this Moodle version
 $module->component = 'mod_lesson'; // Full name of the plugin (used for diagnostics)
 $module->cron      = 0;
-- 
1.7.9.5


From 0c09da65ce22b788686ab55e23ec7b0ed8ff012d Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Mon, 8 Oct 2012 09:03:49 +0800
Subject: [PATCH 819/903] MDL-35265 - blog - Update code for removing orphaned
 blog association data.

Conflicts:
	version.php
---
 lib/db/upgrade.php |   16 ++++++++++++++++
 version.php        |    2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php
index e617e1b..91263db 100644
--- a/lib/db/upgrade.php
+++ b/lib/db/upgrade.php
@@ -969,5 +969,21 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2012062502.03);
     }
 
+    if ($oldversion < 2012062502.07) {
+        // Find all orphaned blog associations that might exist.
+        $sql = "SELECT ba.id
+                  FROM {blog_association} ba
+             LEFT JOIN {post} p
+                    ON p.id = ba.blogid
+                 WHERE p.id IS NULL";
+        $orphanedrecordids = $DB->get_records_sql($sql);
+        // Now delete these associations.
+        foreach ($orphanedrecordids as $orphanedrecord) {
+            $DB->delete_records('blog_association', array('id' => $orphanedrecord->id));
+        }
+
+        upgrade_main_savepoint(true, 2012062502.07);
+    }
+
     return true;
 }
diff --git a/version.php b/version.php
index 4fc7f14..e835adf 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.06;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.07;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 672bea4cfea50067cbf7ee86e9d797629b3d6855 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Mon, 15 Oct 2012 16:26:17 +0800
Subject: [PATCH 820/903] MDL-29762 Blocks: Modified checks to show image in
 html block

---
 blocks/html/lib.php |   21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/blocks/html/lib.php b/blocks/html/lib.php
index a2555c3..e0469d3 100644
--- a/blocks/html/lib.php
+++ b/blocks/html/lib.php
@@ -30,15 +30,32 @@
  * @param bool $forcedownload whether or not force download
  * @param array $options additional options affecting the file serving
  * @return bool
+ * @todo MDL-36050 improve capability check on stick blocks, so we can check user capability before sending images.
  */
 function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
-    global $SCRIPT;
+    global $DB, $CFG;
 
     if ($context->contextlevel != CONTEXT_BLOCK) {
         send_file_not_found();
     }
 
-    require_course_login($course);
+    // If block is in course context, then check if user has capability to access course.
+    if ($context->get_course_context(false)) {
+        require_course_login($course);
+    } else if ($CFG->forcelogin) {
+        require_login();
+    } else {
+        // Get parent context and see if user have proper permission.
+        $parentcontext = $context->get_parent_context();
+        if ($parentcontext->contextlevel === CONTEXT_COURSECAT) {
+            // Check if category is visible and user can view this category.
+            $category = $DB->get_record('course_categories', array('id' => $parentcontext->instanceid), '*', MUST_EXIST);
+            if (!$category->visible) {
+                require_capability('moodle/category:viewhiddencategories', $parentcontext);
+            }
+        }
+        // At this point there is no way to check SYSTEM or USER context, so ignoring it.
+    }
 
     if ($filearea !== 'content') {
         send_file_not_found();
-- 
1.7.9.5


From 1ffbad6404d8c142cc782818a537ffb7d8e48d69 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Tue, 16 Oct 2012 13:32:34 +0800
Subject: [PATCH 821/903] MDL-33857 fixed up whitespace

---
 lib/filebrowser/file_info.php                |   18 +++++++++---------
 lib/filebrowser/file_info_context_course.php |    4 ++--
 lib/filebrowser/file_info_context_module.php |    2 +-
 mod/workshop/fileinfolib.php                 |    2 +-
 4 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/lib/filebrowser/file_info.php b/lib/filebrowser/file_info.php
index 0900d68..a6af3f7 100644
--- a/lib/filebrowser/file_info.php
+++ b/lib/filebrowser/file_info.php
@@ -115,7 +115,7 @@ abstract class file_info {
                 $likes[] = $DB->sql_like($prefix.'filename', ':filename'.$cnt, false);
                 $params['filename'.$cnt] = '%'.$ext;
             }
-            $sql .= ' AND ('.join(' OR ', $likes).')';
+            $sql .= ' AND (' . join(' OR ', $likes) . ')';
         }
         return array($sql, $params);
      }
@@ -144,7 +144,7 @@ abstract class file_info {
             } else {
                 $filename = $fileinfo->get_visible_name();
                 $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-                if (!empty($extension) && in_array('.'.$extension, $extensions)) {
+                if (!empty($extension) && in_array('.' . $extension, $extensions)) {
                     $nonemptylist[] = $fileinfo;
                 }
             }
@@ -178,7 +178,7 @@ abstract class file_info {
                 if ($extensions !== '*') {
                     $filename = $fileinfo->get_visible_name();
                     $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
-                    if (empty($extension) || !in_array('.'.$extension, $extensions)) {
+                    if (empty($extension) || !in_array('.' . $extension, $extensions)) {
                         continue;
                     }
                 }
@@ -213,12 +213,12 @@ abstract class file_info {
     public function get_params_rawencoded() {
         $params = $this->get_params();
         $encoded = array();
-        $encoded[] = 'contextid='.$params['contextid'];
-        $encoded[] = 'component='.$params['component'];
-        $encoded[] = 'filearea='.$params['filearea'];
-        $encoded[] = 'itemid='.(is_null($params['itemid']) ? -1 : $params['itemid']);
-        $encoded[] = 'filepath='.(is_null($params['filepath']) ? '' : rawurlencode($params['filepath']));
-        $encoded[] = 'filename='.((is_null($params['filename']) or $params['filename'] === '.') ? '' : rawurlencode($params['filename']));
+        $encoded[] = 'contextid=' . $params['contextid'];
+        $encoded[] = 'component=' . $params['component'];
+        $encoded[] = 'filearea=' . $params['filearea'];
+        $encoded[] = 'itemid=' . (is_null($params['itemid']) ? -1 : $params['itemid']);
+        $encoded[] = 'filepath=' . (is_null($params['filepath']) ? '' : rawurlencode($params['filepath']));
+        $encoded[] = 'filename=' . ((is_null($params['filename']) or $params['filename'] === '.') ? '' : rawurlencode($params['filename']));
 
         return $encoded;
     }
diff --git a/lib/filebrowser/file_info_context_course.php b/lib/filebrowser/file_info_context_course.php
index c88740a..5e61f56 100644
--- a/lib/filebrowser/file_info_context_course.php
+++ b/lib/filebrowser/file_info_context_course.php
@@ -376,7 +376,7 @@ class file_info_context_course extends file_info {
             if ($child = $this->get_file_info($area[0], $area[1], 0, '/', '.')) {
                 if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
                     $children[] = $child;
-                    if (($countonly !== false) && count($children)>=$countonly) {
+                    if (($countonly !== false) && count($children) >= $countonly) {
                         return $countonly;
                     }
                 }
@@ -397,7 +397,7 @@ class file_info_context_course extends file_info {
                 if ($child = $this->browser->get_file_info($modcontext)) {
                     if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
                         $children[] = $child;
-                        if (($countonly !== false) && count($children)>=$countonly) {
+                        if (($countonly !== false) && count($children) >= $countonly) {
                             return $countonly;
                         }
                     }
diff --git a/lib/filebrowser/file_info_context_module.php b/lib/filebrowser/file_info_context_module.php
index 5636503..f4b2e52 100644
--- a/lib/filebrowser/file_info_context_module.php
+++ b/lib/filebrowser/file_info_context_module.php
@@ -280,7 +280,7 @@ class file_info_context_module extends file_info {
             array('mod_'.$this->modname, 'intro'),
             array('backup', 'activity')
         );
-        foreach ($this->areas as $area=>$desctiption) {
+        foreach ($this->areas as $area => $desctiption) {
             $areas[] = array('mod_'.$this->modname, $area);
         }
 
diff --git a/mod/workshop/fileinfolib.php b/mod/workshop/fileinfolib.php
index 35afd24..0427819 100644
--- a/mod/workshop/fileinfolib.php
+++ b/mod/workshop/fileinfolib.php
@@ -98,7 +98,7 @@ class workshop_file_info_submissions_container extends file_info {
     }
 
     /**
-     * Help function to return files matching extensions or their count
+     * Helper function to return files matching extensions or their count
      *
      * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
      * @param bool|int $countonly if false returns the children, if an int returns just the
-- 
1.7.9.5


From 16ab3642e777e41dd99588d114b7f9d7174316d3 Mon Sep 17 00:00:00 2001
From: Ankit Agarwal <ankit@moodle.com>
Date: Tue, 16 Oct 2012 13:16:41 +0800
Subject: [PATCH 822/903] MDL-35880 user: Adding a heading to profile edit
 page

---
 user/edit.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/user/edit.php b/user/edit.php
index aa88131..0ca7509 100644
--- a/user/edit.php
+++ b/user/edit.php
@@ -293,6 +293,7 @@ $PAGE->set_title("$course->shortname: $streditmyprofile");
 $PAGE->set_heading($course->fullname);
 
 echo $OUTPUT->header();
+echo $OUTPUT->heading($userfullname);
 
 if ($email_changed) {
     echo $email_changed_html;
-- 
1.7.9.5


From e191c71d55c7fb624f8f056eb0bb9316df0ffae9 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Tue, 16 Oct 2012 16:20:12 +0800
Subject: [PATCH 823/903] MDL-34228 - version.php - bump for new capability

---
 version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/version.php b/version.php
index e835adf..223594a 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.07;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.08;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-- 
1.7.9.5


From 98268916ff989b76c268e11566aae044899d1d20 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 20 Sep 2012 17:18:33 +0800
Subject: [PATCH 824/903] MDL-35171 Forms: Date selector always gets UTF-8
 strings

---
 lib/formslib.php             |   38 ++++++++++++++---------------
 lib/moodlelib.php            |   54 +++++++++++++++++++++++++++++++-----------
 lib/tests/moodlelib_test.php |   36 ++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 33 deletions(-)

diff --git a/lib/formslib.php b/lib/formslib.php
index c81dfb7..866ad43 100644
--- a/lib/formslib.php
+++ b/lib/formslib.php
@@ -81,25 +81,25 @@ function form_init_date_js() {
         $function = 'M.form.dateselector.init_date_selectors';
         $config = array(array(
             'firstdayofweek'    => get_string('firstdayofweek', 'langconfig'),
-            'mon'               => strftime('%a', strtotime("Monday")),
-            'tue'               => strftime('%a', strtotime("Tuesday")),
-            'wed'               => strftime('%a', strtotime("Wednesday")),
-            'thu'               => strftime('%a', strtotime("Thursday")),
-            'fri'               => strftime('%a', strtotime("Friday")),
-            'sat'               => strftime('%a', strtotime("Saturday")),
-            'sun'               => strftime('%a', strtotime("Sunday")),
-            'january'           => strftime('%B', strtotime("January 1")),
-            'february'          => strftime('%B', strtotime("February 1")),
-            'march'             => strftime('%B', strtotime("March 1")),
-            'april'             => strftime('%B', strtotime("April 1")),
-            'may'               => strftime('%B', strtotime("May 1")),
-            'june'              => strftime('%B', strtotime("June 1")),
-            'july'              => strftime('%B', strtotime("July 1")),
-            'august'            => strftime('%B', strtotime("August 1")),
-            'september'         => strftime('%B', strtotime("September 1")),
-            'october'           => strftime('%B', strtotime("October 1")),
-            'november'          => strftime('%B', strtotime("November 1")),
-            'december'          => strftime('%B', strtotime("December 1"))
+            'mon'               => date_format_string(strtotime("Monday"), '%a', 99),
+            'tue'               => date_format_string(strtotime("Tuesday"), '%a', 99),
+            'wed'               => date_format_string(strtotime("Wednesday"), '%a', 99),
+            'thu'               => date_format_string(strtotime("Thursday"), '%a', 99),
+            'fri'               => date_format_string(strtotime("Friday"), '%a', 99),
+            'sat'               => date_format_string(strtotime("Saturday"), '%a', 99),
+            'sun'               => date_format_string(strtotime("Sunday"), '%a', 99),
+            'january'           => date_format_string(strtotime("January 1"), '%B', 99),
+            'february'          => date_format_string(strtotime("February 1"), '%B', 99),
+            'march'             => date_format_string(strtotime("March 1"), '%B', 99),
+            'april'             => date_format_string(strtotime("April 1"), '%B', 99),
+            'may'               => date_format_string(strtotime("May 1"), '%B', 99),
+            'june'              => date_format_string(strtotime("June 1"), '%B', 99),
+            'july'              => date_format_string(strtotime("July 1"), '%B', 99),
+            'august'            => date_format_string(strtotime("August 1"), '%B', 99),
+            'september'         => date_format_string(strtotime("September 1"), '%B', 99),
+            'october'           => date_format_string(strtotime("October 1"), '%B', 99),
+            'november'          => date_format_string(strtotime("November 1"), '%B', 99),
+            'december'          => date_format_string(strtotime("December 1"), '%B', 99)
         ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 167a653..41b538f 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -2071,13 +2071,7 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour
     // (because it's impossible to specify UTF-8 to fetch locale info in Win32)
 
     if (abs($timezone) > 13) {   /// Server time
-        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
-            $format = textlib::convert($format, 'utf-8', $localewincharset);
-            $datestring = strftime($format, $date);
-            $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
-        } else {
-            $datestring = strftime($format, $date);
-        }
+        $datestring = date_format_string($date, $format, $timezone);
         if ($fixday) {
             $daystring  = ltrim(str_replace(array(' 0', ' '), '', strftime(' %d', $date)));
             $datestring = str_replace('DD', $daystring, $datestring);
@@ -2089,13 +2083,7 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour
 
     } else {
         $date += (int)($timezone * 3600);
-        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
-            $format = textlib::convert($format, 'utf-8', $localewincharset);
-            $datestring = gmstrftime($format, $date);
-            $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
-        } else {
-            $datestring = gmstrftime($format, $date);
-        }
+        $datestring = date_format_string($date, $format, $timezone);
         if ($fixday) {
             $daystring  = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %d', $date)));
             $datestring = str_replace('DD', $daystring, $datestring);
@@ -2110,6 +2098,44 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour
 }
 
 /**
+ * Returns a formatted date ensuring it is UTF-8.
+ *
+ * If we are running under Windows convert to Windows encoding and then back to UTF-8
+ * (because it's impossible to specify UTF-8 to fetch locale info in Win32).
+ *
+ * This function does not do any calculation regarding the user preferences and should
+ * therefore receive the final date timestamp, format and timezone. Timezone being only used
+ * to differenciate the use of server time or not (strftime() against gmstrftime()).
+ *
+ * @param int $date the timestamp.
+ * @param string $format strftime format.
+ * @param int|float $timezone the numerical timezone, typically returned by {@link get_user_timezone_offset()}.
+ * @return string the formatted date/time.
+ * @since 2.3.3
+ */
+function date_format_string($date, $format, $tz = 99) {
+    global $CFG;
+    if (abs($tz) > 13) {
+        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
+            $format = textlib::convert($format, 'utf-8', $localewincharset);
+            $datestring = strftime($format, $date);
+            $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
+        } else {
+            $datestring = strftime($format, $date);
+        }
+    } else {
+        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
+            $format = textlib::convert($format, 'utf-8', $localewincharset);
+            $datestring = gmstrftime($format, $date);
+            $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
+        } else {
+            $datestring = gmstrftime($format, $date);
+        }
+    }
+    return $datestring;
+}
+
+/**
  * Given a $time timestamp in GMT (seconds since epoch),
  * returns an array that represents the date in user time
  *
diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 6beb856..43c2f97 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -1993,4 +1993,40 @@ class moodlelib_testcase extends advanced_testcase {
         );
         $this->assertEquals(convert_to_array($obj), $ar);
     }
+
+    /**
+     * Test the function date_format_string().
+     */
+    function test_date_format_string() {
+        // Forcing locale and timezone.
+        $oldlocale = setlocale(LC_TIME, '0');
+        setlocale(LC_TIME, 'en_AU.UTF-8');
+        $systemdefaulttimezone = date_default_timezone_get();
+        date_default_timezone_set('Australia/Perth');
+
+        // Note: date_format_string() uses the timezone only to differenciate
+        // the server time from the UTC time. It does not modify the timestamp.
+        // Hence similar results for timezones <= 13.
+        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 99);
+        $this->assertEquals($str, 'Saturday, 01 January 2011, 06:00 PM');
+
+        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 0);
+        $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM');
+
+        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', -12);
+        $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM');
+
+        $str = date_format_string(1293876000, 'Žluťoučký koníček %A', 99);
+        $this->assertEquals($str, 'Žluťoučký koníček Saturday');
+
+        $str = date_format_string(1293876000, '言語設定言語 %A', 99);
+        $this->assertEquals($str, '言語設定言語 Saturday');
+
+        $str = date_format_string(1293876000, '简体中文简体 %A', 99);
+        $this->assertEquals($str, '简体中文简体 Saturday');
+
+        // Restore system default values.
+        date_default_timezone_set($systemdefaulttimezone);
+        setlocale(LC_TIME, $oldlocale);
+    }
 }
-- 
1.7.9.5


From 335636f55db85faa54d6854d62d614402a5b5152 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 16 Oct 2012 11:50:25 +0800
Subject: [PATCH 825/903] MDL-35412 core: Moving get_string out of if
 statement

---
 lib/moodlelib.php |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 41b538f..1de567f 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -2116,7 +2116,8 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour
 function date_format_string($date, $format, $tz = 99) {
     global $CFG;
     if (abs($tz) > 13) {
-        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
+        if ($CFG->ostype == 'WINDOWS') {
+            $localewincharset = get_string('localewincharset', 'langconfig');
             $format = textlib::convert($format, 'utf-8', $localewincharset);
             $datestring = strftime($format, $date);
             $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
@@ -2124,7 +2125,8 @@ function date_format_string($date, $format, $tz = 99) {
             $datestring = strftime($format, $date);
         }
     } else {
-        if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
+        if ($CFG->ostype == 'WINDOWS') {
+            $localewincharset = get_string('localewincharset', 'langconfig');
             $format = textlib::convert($format, 'utf-8', $localewincharset);
             $datestring = gmstrftime($format, $date);
             $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
-- 
1.7.9.5


From 456352585a8386a67a69e315886ad42fac3c0907 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 16 Oct 2012 17:21:11 +0800
Subject: [PATCH 826/903] MDL-35412 phpunit: date_format_string() is case
 insensitive

---
 lib/tests/moodlelib_test.php |   55 +++++++++++++++++++++++++++++-------------
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php
index 43c2f97..09c2fad 100644
--- a/lib/tests/moodlelib_test.php
+++ b/lib/tests/moodlelib_test.php
@@ -2004,26 +2004,47 @@ class moodlelib_testcase extends advanced_testcase {
         $systemdefaulttimezone = date_default_timezone_get();
         date_default_timezone_set('Australia/Perth');
 
+        $tests = array(
+            array(
+                'tz' => 99,
+                'str' => '%A, %d %B %Y, %I:%M %p',
+                'expected' => 'Saturday, 01 January 2011, 06:00 PM'
+            ),
+            array(
+                'tz' => 0,
+                'str' => '%A, %d %B %Y, %I:%M %p',
+                'expected' => 'Saturday, 01 January 2011, 10:00 AM'
+            ),
+            array(
+                'tz' => -12,
+                'str' => '%A, %d %B %Y, %I:%M %p',
+                'expected' => 'Saturday, 01 January 2011, 10:00 AM'
+            ),
+            array(
+                'tz' => 99,
+                'str' => 'Žluťoučký koníček %A',
+                'expected' => 'Žluťoučký koníček Saturday'
+            ),
+            array(
+                'tz' => 99,
+                'str' => '言語設定言語 %A',
+                'expected' => '言語設定言語 Saturday'
+            ),
+            array(
+                'tz' => 99,
+                'str' => '简体中文简体 %A',
+                'expected' => '简体中文简体 Saturday'
+            ),
+        );
+
         // Note: date_format_string() uses the timezone only to differenciate
         // the server time from the UTC time. It does not modify the timestamp.
         // Hence similar results for timezones <= 13.
-        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 99);
-        $this->assertEquals($str, 'Saturday, 01 January 2011, 06:00 PM');
-
-        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 0);
-        $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM');
-
-        $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', -12);
-        $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM');
-
-        $str = date_format_string(1293876000, 'Žluťoučký koníček %A', 99);
-        $this->assertEquals($str, 'Žluťoučký koníček Saturday');
-
-        $str = date_format_string(1293876000, '言語設定言語 %A', 99);
-        $this->assertEquals($str, '言語設定言語 Saturday');
-
-        $str = date_format_string(1293876000, '简体中文简体 %A', 99);
-        $this->assertEquals($str, '简体中文简体 Saturday');
+        // On different systems case of AM PM changes so compare case insensitive.
+        foreach ($tests as $test) {
+            $str = date_format_string(1293876000, $test['str'], $test['tz']);
+            $this->assertEquals(textlib::strtolower($test['expected']), textlib::strtolower($str));
+        }
 
         // Restore system default values.
         date_default_timezone_set($systemdefaulttimezone);
-- 
1.7.9.5


From 9081825ea32de62ca9ef045d8af65a990ff0c0ed Mon Sep 17 00:00:00 2001
From: Jason Platts <j.platts@open.ac.uk>
Date: Tue, 16 Oct 2012 12:09:51 +0100
Subject: [PATCH 827/903] MDL-36075 Forms: Date selector in forms errors in
 IE7

---
 lib/form/yui/dateselector/dateselector.js |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/form/yui/dateselector/dateselector.js b/lib/form/yui/dateselector/dateselector.js
index 1109b22..9414db0 100644
--- a/lib/form/yui/dateselector/dateselector.js
+++ b/lib/form/yui/dateselector/dateselector.js
@@ -220,7 +220,7 @@ YUI.add('moodle-form-dateselector', function(Y) {
                     config.september,
                     config.october,
                     config.november,
-                    config.december ],
+                    config.december ]
             });
             this.calendar.changePageEvent.subscribe(function(){
                 this.fix_position();
-- 
1.7.9.5


From 6ab522802f798f76b64f44f6ebfc9da627d9def6 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 17 Oct 2012 00:34:38 +0000
Subject: [PATCH 828/903] Automatically generated installer lang files

---
 install/lang/ms/admin.php    |   42 +++++++++++++++++++++
 install/lang/ms/install.php  |   83 ++++++++++++++++++++++++++++++++++++++++++
 install/lang/ms/moodle.php   |   35 ++++++++++++++++++
 install/lang/zh_tw/admin.php |    9 +++++
 4 files changed, 169 insertions(+)
 create mode 100644 install/lang/ms/admin.php
 create mode 100644 install/lang/ms/install.php
 create mode 100644 install/lang/ms/moodle.php

diff --git a/install/lang/ms/admin.php b/install/lang/ms/admin.php
new file mode 100644
index 0000000..3673ceb
--- /dev/null
+++ b/install/lang/ms/admin.php
@@ -0,0 +1,42 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 't';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueerror'] = 'Ralat, nilai tidak betul "{$a->value}" untuk "{$a->option}"';
+$string['cliincorrectvalueretry'] = 'Nilai yang salah, sila cuba lagi';
+$string['clitypevalue'] = 'taip nilai';
+$string['clitypevaluedefault'] = 'taip nilai, tekan Enter untuk gunakan nilai lalai ({$a})';
+$string['cliunknowoption'] = 'Pilihan yang tidak diketahui:
+  {$a}
+Sila gunakan pilihan --help';
+$string['cliyesnoprompt'] = 'tapi y (ya) atau t (tidak)';
diff --git a/install/lang/ms/install.php b/install/lang/ms/install.php
new file mode 100644
index 0000000..a9240fc2
--- /dev/null
+++ b/install/lang/ms/install.php
@@ -0,0 +1,83 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['admindirname'] = 'Direktori admin';
+$string['availablelangs'] = 'Senarai bahasa yang tersedia';
+$string['chooselanguagehead'] = 'Pilih bahasa';
+$string['chooselanguagesub'] = 'Sila pilih bahasa untuk pemasangan. Bahasa ini juga akan digunakan sebagai bahasa lalai untuk laman, ia boleh diubah kemudian.';
+$string['clialreadyinstalled'] = 'config.php fail sudah wujud, sila gunakan admin/cli/upgrade.php jika anda mahu menaik taraf laman web anda.';
+$string['cliinstallheader'] = 'Baris arahan pemasangan program Moodle {$a}';
+$string['databasehost'] = 'Hos pangkalan data';
+$string['databasename'] = 'Nama pangkalan data';
+$string['databasetypehead'] = 'Pilih pemacu pangkalan data';
+$string['dataroot'] = 'Direktori data';
+$string['dbprefix'] = 'Awalan jadual';
+$string['dirroot'] = 'Direktori Moodle';
+$string['environmenthead'] = 'Memeriksa persekitaran anda ...';
+$string['environmentsub2'] = 'Setiap pelepasan Moodle mempunyai keperluan minimum versi PHP dan beberapa sambungan mandatori PHP. Persekitaran penuh disemak sebelum setiap pemasangan dan naik taraf. Sila hubungi pentadbir pelayan jika anda tidak tahu bagaimana untuk memasang versi baru atau membolehkan sambungan PHP.';
+$string['errorsinenvironment'] = 'Semakan persekitaran gagal!';
+$string['installation'] = 'Pemasangan';
+$string['langdownloaderror'] = 'Malangnya bahasa "{$a}" tidak boleh dimuat turun. Proses pemasangan akan diteruskan dalam bahasa Bahasa Inggeris.';
+$string['memorylimithelp'] = '<p> Had memori PHP untuk pelayan anda  ditetapkan kepada {$a}. </p>
+
+<p> Hal ini akan menyebabkan Moodle untuk mendapat masalah memori di kemudian hari, terutama jika anda mempunyai banyak modul yang diaktifkan dan/atau ramai pengguna. </p>
+
+<p> Kami menyarankan anda mengkonfigurasikan PHP dengan had yang lebih tinggi jika memungkinkan, seperti 40M. Ada beberapa cara untuk melakukan hal ini yang anda boleh cuba: </p>
+<ol>
+<li> Jika anda mampu, kompil semula PHP dengan <i>--enable-memory-limit.</i> Hal ini akan membolehkan Moodle untuk menetapkan batas memori itu sendiri. </li>
+<li> Jika anda mempunyai akses ke fail php.ini, anda boleh menukar setting <b>memory_limit</b> di sana untuk sesuatu seperti 40M. Jika anda tidak mempunyai akses anda mungkin boleh meminta pentadbir anda untuk melakukan ini untuk anda. </li>
+<li> Pada beberapa server PHP anda boleh mencipta baris fail .htaccess di direktori Moodle mengandungi ini: <blockquote><div> php_value memory_limit 40M </div></blockquote><p> Namun, pada beberapa server ini akan mencegah <b>semua</b> laman PHP dari berjalan (anda akan melihat ralat ketika anda melihat halaman), sehingga anda hapuskan file .htaccess. </p></li></ol>';
+$string['paths'] = 'Laluan';
+$string['pathserrcreatedataroot'] = 'Direktori data ({$a->dataroot}) tidak boleh diwujudkan oleh pemasang.';
+$string['pathshead'] = 'Sahkan laluan';
+$string['pathsrodataroot'] = 'Direktori dataroot tidak dapat ditulis.';
+$string['pathsroparentdataroot'] = 'Direktori induk ({$a->parent}) tidak boleh tulis. Direktori data ({$a->dataroot}) tidak boleh diwujudkan oleh pemasang.';
+$string['pathssubadmindir'] = 'Beberapa webhos menggunakan /admin sebagai URL khas untuk anda akses panel kawalan atau sesuatu yang lain. Malangnya, ini bertentangan dengan lokasi standard untuk halaman pentadbiran Moodle. Anda boleh memperbaiki ini dengan menamakan semula direktori admin dalam pemasangan anda, dan meletakkan nama baru di sini. Sebagai contoh: <br /> <br /> <b> moodleadmin </ b> <br /> <br />
+Ini akan memulihkan pautan admin dalam Moodle.';
+$string['pathssubdataroot'] = 'Anda perlukan lokasi di mana Moodle boleh menyimpan fail yang dimuat naik. Direktori ini sepatutnya boleh dibaca DAN BOLEH DITULIS oleh pengguna web server (biasanya \'nobody\' atau \'apache\'), tetapi ia mestilah tidak boleh diakses secara langsung melalui laman web. Pemasang akan cuba untuk mewujudkannya jika belum ada.';
+$string['pathssubdirroot'] = 'Direktori laluan penuh untuk pemasangan Moodle.';
+$string['pathssubwwwroot'] = 'Alamat penuh web di mana Moodle akan dicapai. Adalah tidak mungkin untuk mengakses Moodle menggunakan pelbagai alamat. Jika laman anda mempunyai beberapa alamat awam, anda mesti menubuhkan pelencongan kekal kepada semua mereka kecuali yang satu ini. Jika laman web anda boleh diakses kedua-duanya dari Intranet dan Internet menggunakan alamat awam di sini dan menubuhkan DNS supaya pengguna Intranet boleh menggunakan alamat awam juga. Jika alamat itu tidak betul, sila ubah URL di pelayar anda untuk memulakan semula pemasangan dengan nilai yang berbeza.';
+$string['pathsunsecuredataroot'] = 'Lokasi dataroot tidak selamat';
+$string['pathswrongadmindir'] = 'Direktori admin tidak wujud';
+$string['phpextension'] = 'Sambungan PHP {$a}';
+$string['phpversion'] = 'Versi PHP';
+$string['phpversionhelp'] = '<p> Moodle memerlukan versi PHP minimal 4.3.0 atau 5.1.0 (5.0.x memiliki sejumlah masalah yang diketahui). </p>
+<p> Anda sedang menjalankan versi {$a} </p>
+<p> Anda harus upgrade PHP atau berpindah ke host dengan versi terbaru PHP! <br /> (Dalam kes 5.0.x Anda juga boleh turun taraf ke versi 4.4.x) </p>';
+$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
+$string['welcomep20'] = 'Anda melihat halaman ini kerana anda telah berjaya memasang dan melancarkan pakej <strong>{$a->packname} {$a->packversion}</strong> di komputer anda. Tahniah!';
+$string['welcomep30'] = 'Keluaran ini <strong>{$a->installername}</strong> termasuk aplikasi untuk mencipta sebuah persekitaran di mana <strong>Moodle</strong> akan beroperasi, iaitu:';
+$string['welcomep40'] = 'Pakej ini juga termasuk <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
+$string['welcomep50'] = 'Penggunaan semua aplikasi di dalam pakej ini dikawal oleh lesen masing-masing. Pakej lengkap <strong>{$a->installername}</strong> adalah <a href="http://www.opensource.org/docs/definition_plain.html">sumber terbuka</a> dan diedarkan di bawah lesen <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
+$string['welcomep60'] = 'Laman-laman berikut akan membawa anda melalui beberapa langkah-langkah mudah diikuti untuk mengkonfigurasi dan menetapkan <strong>Moodle</strong> pada komputer anda. Anda mungkin menerima tetapan lalai atau, dengan pilihan, meminda untuk disesuaikan dengan keperluan anda.';
+$string['welcomep70'] = 'Klik butang "Seterusnya" di bawah untuk meneruskan penubuhan <strong>Moodle</strong>.';
+$string['wwwroot'] = 'Alamat Web';
diff --git a/install/lang/ms/moodle.php b/install/lang/ms/moodle.php
new file mode 100644
index 0000000..145ec13
--- /dev/null
+++ b/install/lang/ms/moodle.php
@@ -0,0 +1,35 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Bahasa';
+$string['next'] = 'Seterusnya';
+$string['previous'] = 'Sebelum';
diff --git a/install/lang/zh_tw/admin.php b/install/lang/zh_tw/admin.php
index ef41512..5eb6cc3 100644
--- a/install/lang/zh_tw/admin.php
+++ b/install/lang/zh_tw/admin.php
@@ -30,5 +30,14 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueerror'] = '錯誤，不正確的值 "{$a->value}" 用於 "{$a->option}"';
+$string['cliincorrectvalueretry'] = '不正確的值，請再試一次';
+$string['clitypevalue'] = '打入一值';
+$string['clitypevaluedefault'] = '打入一值，按Enter可使用預設值({$a})';
+$string['cliunknowoption'] = '不認得的選項：  {$a}
+請使用 --幫助 選項。';
+$string['cliyesnoprompt'] = '輸入y(是) 或n(否)';
 $string['environmentrequireinstall'] = '必須安裝/啟用';
 $string['environmentrequireversion'] = '要求版本為 {$a->needed} ，您目前版本為 {$a->current}';
-- 
1.7.9.5


From db05d5953493cf9b1a3bff717acdd65a237c9397 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Wed, 17 Oct 2012 13:54:45 +0800
Subject: [PATCH 829/903] MDL-36076 qtype multichoice: validation fails on '0'
 answer.

---
 .../type/multichoice/edit_multichoice_form.php     |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/question/type/multichoice/edit_multichoice_form.php b/question/type/multichoice/edit_multichoice_form.php
index e94c202..031605e 100644
--- a/question/type/multichoice/edit_multichoice_form.php
+++ b/question/type/multichoice/edit_multichoice_form.php
@@ -110,10 +110,10 @@ class qtype_multichoice_edit_form extends question_edit_form {
             //check no of choices
             $trimmedanswer = trim($answer['text']);
             $fraction = (float) $data['fraction'][$key];
-            if (empty($trimmedanswer) && empty($fraction)) {
+            if ($trimmedanswer === '' && empty($fraction)) {
                 continue;
             }
-            if (empty($trimmedanswer)) {
+            if ($trimmedanswer === '') {
                 $errors['fraction['.$key.']'] = get_string('errgradesetanswerblank', 'qtype_multichoice');
             }
 
-- 
1.7.9.5


From dd5e3ac22261c7a14c0fb64f44cce2f2e1ba631d Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 18 Oct 2012 00:34:55 +0000
Subject: [PATCH 830/903] Automatically generated installer lang files

---
 install/lang/it/langconfig.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/it/langconfig.php b/install/lang/it/langconfig.php
index 1b8da44..4e2760f 100644
--- a/install/lang/it/langconfig.php
+++ b/install/lang/it/langconfig.php
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = '';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Italiano';
-- 
1.7.9.5


From c034e59beef142d2e21b19e7f85c48a742184214 Mon Sep 17 00:00:00 2001
From: David Tang <khtang@yahoo.com>
Date: Wed, 17 Oct 2012 12:51:25 +0100
Subject: [PATCH 831/903] MDL-31629 auth_shibboleth Use correct language
 string location

---
 auth/shibboleth/index.php |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/auth/shibboleth/index.php b/auth/shibboleth/index.php
index a1e4a1c..95639a4 100644
--- a/auth/shibboleth/index.php
+++ b/auth/shibboleth/index.php
@@ -25,7 +25,7 @@
 
     // Check whether Shibboleth is configured properly
     if (empty($pluginconfig->user_attribute)) {
-        print_error('shib_not_set_up_error', 'auth');
+        print_error('shib_not_set_up_error', 'auth_shibboleth');
      }
 
 /// If we can find the Shibboleth attribute, save it in session and return to main login page
@@ -91,9 +91,9 @@
     // If we can find any (user independent) Shibboleth attributes but no user
     // attributes we probably didn't receive any user attributes
     elseif (!empty($_SERVER['HTTP_SHIB_APPLICATION_ID']) || !empty($_SERVER['Shib-Application-ID'])) {
-        print_error('shib_no_attributes_error', 'auth' , '', '\''.$pluginconfig->user_attribute.'\', \''.$pluginconfig->field_map_firstname.'\', \''.$pluginconfig->field_map_lastname.'\' and \''.$pluginconfig->field_map_email.'\'');
+        print_error('shib_no_attributes_error', 'auth_shibboleth' , '', '\''.$pluginconfig->user_attribute.'\', \''.$pluginconfig->field_map_firstname.'\', \''.$pluginconfig->field_map_lastname.'\' and \''.$pluginconfig->field_map_email.'\'');
     } else {
-        print_error('shib_not_set_up_error', 'auth');
+        print_error('shib_not_set_up_error', 'auth_shibboleth');
     }
 
 
-- 
1.7.9.5


From 4e15f69cb1a0e0b438083bc379135d11005631d7 Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Thu, 18 Oct 2012 14:13:18 +0800
Subject: [PATCH 832/903] MDL-35489 users: Check added before using form data

---
 user/filters/text.php |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/user/filters/text.php b/user/filters/text.php
index 2f54d4e..8be8f1f 100644
--- a/user/filters/text.php
+++ b/user/filters/text.php
@@ -62,7 +62,12 @@ class user_filter_text extends user_filter_type {
                 // no data - no change except for empty filter
                 return false;
             }
-            return array('operator'=>(int)$formdata->$operator, 'value'=>$formdata->$field);
+            // If field value is set then use it, else it's null.
+            $fieldvalue = null;
+            if (isset($formdata->$field)) {
+                $fieldvalue = $formdata->$field;
+            }
+            return array('operator' => (int)$formdata->$operator, 'value' =>  $fieldvalue);
         }
 
         return false;
-- 
1.7.9.5


From b1c5155cbcd1885096a7a8a5cc35405a86c0a815 Mon Sep 17 00:00:00 2001
From: Aparup Banerjee <aparup@moodle.com>
Date: Thu, 18 Oct 2012 19:43:28 +0800
Subject: [PATCH 833/903] weekly release 2.3.3+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 223594a..b25cd6c 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.08;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.09;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121014)'; // Human-friendly version name
+$release  = '2.3.3+ (Build: 20121018)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From e2694e9dd6089856a14b62ddebc1a0de5b06783d Mon Sep 17 00:00:00 2001
From: Gilles-Philippe Leblanc <gilles-philippe.leblanc@umontreal.ca>
Date: Thu, 18 Oct 2012 08:51:51 -0400
Subject: [PATCH 834/903] MDL-31708 wiki: Wiki 2.0 non-group member can see
 edit option in navigation block

---
 mod/wiki/lang/en/wiki.php |    2 ++
 mod/wiki/lib.php          |    2 +-
 mod/wiki/locallib.php     |    2 +-
 mod/wiki/pagelib.php      |   11 ++---------
 4 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/mod/wiki/lang/en/wiki.php b/mod/wiki/lang/en/wiki.php
index 80fbdf4..d332563 100644
--- a/mod/wiki/lang/en/wiki.php
+++ b/mod/wiki/lang/en/wiki.php
@@ -22,8 +22,10 @@ $string['backoldversion'] = 'Back to old version';
 $string['backpage'] = 'Back to page';
 $string['backtomapmenu'] = 'Back to map menu';
 $string['changerate'] = 'Do you wish to change it?';
+$string['cannoteditpage'] = 'You can not edit this page.';
 $string['cannotmanagefiles'] = 'You don\'t have permission to manage the wiki files.';
 $string['cannotviewfiles'] = 'You don\'t have permission to view the wiki files.';
+$string['cannotviewpage'] = 'You can not view this page.';
 $string['comparesel'] = 'Compare selected';
 $string['comments'] = 'Comments';
 $string['commentscount'] = 'Comments ({$a})';
diff --git a/mod/wiki/lib.php b/mod/wiki/lib.php
index 133178a..974c46d 100644
--- a/mod/wiki/lib.php
+++ b/mod/wiki/lib.php
@@ -531,7 +531,7 @@ function wiki_extend_navigation(navigation_node $navref, $course, $module, $cm)
             $node = $navref->add(get_string('view', 'wiki'), $link, navigation_node::TYPE_SETTING);
         }
 
-        if (has_capability('mod/wiki:editpage', $context)) {
+        if (wiki_user_can_edit($subwiki)) {
             $link = new moodle_url('/mod/wiki/edit.php', array('pageid' => $pageid));
             $node = $navref->add(get_string('edit', 'wiki'), $link, navigation_node::TYPE_SETTING);
         }
diff --git a/mod/wiki/locallib.php b/mod/wiki/locallib.php
index ff3b67a..079ce2a 100644
--- a/mod/wiki/locallib.php
+++ b/mod/wiki/locallib.php
@@ -767,7 +767,7 @@ function wiki_user_can_view($subwiki) {
         //      Each person owns a wiki.
         if ($wiki->wikimode == 'collaborative' || $wiki->wikimode == 'individual') {
             // Only members of subwiki group could view that wiki
-            if ($subwiki->groupid == groups_get_activity_group($cm)) {
+            if (groups_is_member($subwiki->groupid)) {
                 // Only view capability needed
                 return has_capability('mod/wiki:viewpage', $context);
 
diff --git a/mod/wiki/pagelib.php b/mod/wiki/pagelib.php
index 4fe9d50..511f48f 100644
--- a/mod/wiki/pagelib.php
+++ b/mod/wiki/pagelib.php
@@ -172,13 +172,8 @@ abstract class page_wiki {
             if (!$manage and !($edit and groups_is_member($currentgroup))) {
                 unset($this->tabs['edit']);
             }
-        } else {
-            if (!has_capability('mod/wiki:editpage', $PAGE->context)) {
-                unset($this->tabs['edit']);
-            }
         }
 
-
         if (empty($options)) {
             $this->tabs_options = array('activetab' => substr(get_class($this), 10));
         } else {
@@ -326,8 +321,7 @@ class page_wiki_view extends page_wiki {
                 }
             }
         } else {
-            // @TODO: Tranlate it
-            echo "You can not view this page";
+            echo get_string('cannotviewpage', 'wiki');
         }
     }
 
@@ -420,8 +414,7 @@ class page_wiki_edit extends page_wiki {
         if (wiki_user_can_edit($this->subwiki)) {
             $this->print_edit();
         } else {
-            // @TODO: Translate it
-            echo "You can not edit this page";
+            echo get_string('cannoteditpage', 'wiki');
         }
     }
 
-- 
1.7.9.5


From c8ee9dde6089de247cd5c005d5fe2d67f8435513 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Thu, 18 Oct 2012 13:38:18 +0100
Subject: [PATCH 835/903] MDL-35510 theme_mymobile: RTL fixes for course and
 category names in style/jmobile11_rtl.css

---
 theme/mymobile/style/jmobile11_rtl.css |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/theme/mymobile/style/jmobile11_rtl.css b/theme/mymobile/style/jmobile11_rtl.css
index 7d2ba26..30466f5 100644
--- a/theme/mymobile/style/jmobile11_rtl.css
+++ b/theme/mymobile/style/jmobile11_rtl.css
@@ -41,8 +41,6 @@
     padding-right: 7px;
 }
 
-.dir-rtl .ui-li-count { left:38px; right:auto;}
-
 .dir-rtl .ui-checkbox .ui-btn, .dir-rtl .ui-radio .ui-btn {
     text-align: right;
 }
@@ -51,4 +49,14 @@
 
 .path-mod-quiz.dir-rtl .que .control {
     width: 75%;
+}
+
+.dir-rtl .categorybox .ui-btn-inner,
+.dir-rtl .coursebox .ui-btn-inner {
+    text-align: right;
+ }
+
+.dir-rtl .categorybox .ui-btn-text,
+.dir-rtl .coursebox .ui-btn-text {
+    padding-right: 25px;
 }
\ No newline at end of file
-- 
1.7.9.5


From 09725180cff2633cf8ad678ec1209257656d70c9 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 19 Oct 2012 00:35:15 +0000
Subject: [PATCH 836/903] Automatically generated installer lang files

---
 install/lang/zh_tw/install.php |   16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/install/lang/zh_tw/install.php b/install/lang/zh_tw/install.php
index 07cb23e..c63fa29 100644
--- a/install/lang/zh_tw/install.php
+++ b/install/lang/zh_tw/install.php
@@ -34,10 +34,18 @@ $string['admindirname'] = '管理目錄';
 $string['availablelangs'] = '可使用的語言包';
 $string['chooselanguagehead'] = '選擇一種語言';
 $string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。稍後您可以根據需要重新選擇用於網站和使用者的語言。';
+$string['clialreadyconfigured'] = '檔案 config.php  已經存在，若你要安裝這一網站，請使用dmin/cli/install_database.php';
+$string['clialreadyinstalled'] = '檔案 config.php  已經存在，若你要升級這一網站，請使用admin/cli/upgrade.php';
+$string['cliinstallheader'] = 'Moodle {$a} 指令行安裝程式';
+$string['databasehost'] = '資料庫主機';
+$string['databasename'] = '資料庫名稱';
+$string['databasetypehead'] = '選擇資料庫磁碟機';
 $string['dataroot'] = '資料目錄';
+$string['datarootpermission'] = '資料目錄存取授權';
 $string['dbprefix'] = '資料表名稱的前置字元';
 $string['dirroot'] = 'Moodle目錄';
 $string['environmenthead'] = '檢查您的環境中...';
+$string['errorsinenvironment'] = '環境檢查失敗';
 $string['installation'] = '安裝';
 $string['langdownloaderror'] = '很不幸地，語言“{$a}”並未安裝。安裝過程將以英文繼續。';
 $string['memorylimithelp'] = '<p>PHP記憶體上限目前設定為{$a}。</p>
@@ -50,6 +58,14 @@ $string['memorylimithelp'] = '<p>PHP記憶體上限目前設定為{$a}。</p>
 <li>在一些PHP伺服器上，您可以在Moodle目錄下，建立.htaccess檔，包含這行:<p><blockquote>php_value memory_limit 16M</blockquote></p>
 <p>然而，在一些伺服器上，這將造成<b>所有的</b> PHP 網頁無法運作(當您看這些網頁時，您就會看到錯誤) 因此，您就必須將 .htaccess 檔案移除。
 </ol>';
+$string['paths'] = '路徑';
+$string['pathserrcreatedataroot'] = '資料目錄 ({$a->dataroot})無法由這安裝程式建立';
+$string['pathshead'] = '確認路徑';
+$string['pathsrodataroot'] = '資料根目錄是無法寫入的';
+$string['pathssubdirroot'] = 'Moodle安裝的完整目錄徑路';
+$string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全';
+$string['pathswrongadmindir'] = '管理目錄不存在';
+$string['phpextension'] = '{$a} PHP擴展';
 $string['phpversion'] = 'PHP版本';
 $string['phpversionhelp'] = '<p>Moodle 需要至少4.1.0.的PHP版本 </p>
 <p>您目前執行的是{$a} 版</p>
-- 
1.7.9.5


From d2d17341e8eff08767cc7dd4e830d0855433487a Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 19 Oct 2012 13:21:03 +0800
Subject: [PATCH 837/903] MDL-21625 Question bank: Add accessibility to table
 layout for viewing question list

---
 mod/quiz/editlib.php |    9 ++++++++
 question/editlib.php |   58 ++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/mod/quiz/editlib.php b/mod/quiz/editlib.php
index 6d16aa7..f64e282 100644
--- a/mod/quiz/editlib.php
+++ b/mod/quiz/editlib.php
@@ -1138,6 +1138,15 @@ class quiz_question_bank_view extends question_bank_view {
                 'editaction', 'previewaction');
     }
 
+     /**
+     * Specify the column heading
+     *
+     * @return string Column name for the heading
+     */
+    protected function heading_column() {
+        return 'questionnametext';
+    }
+
     protected function default_sort() {
         $this->requiredcolumns['qtype'] = $this->knowncolumntypes['qtype'];
         $this->requiredcolumns['questionnametext'] = $this->knowncolumntypes['questionnametext'];
diff --git a/question/editlib.php b/question/editlib.php
index e688add..e4f811e 100644
--- a/question/editlib.php
+++ b/question/editlib.php
@@ -134,6 +134,9 @@ abstract class question_bank_column_base {
      */
     protected $qbank;
 
+    /** @var bool determine whether the column is td or th. */
+    protected $isheading = false;
+
     /**
      * Constructor.
      * @param $qbank the question_bank_view we are helping to render.
@@ -150,6 +153,13 @@ abstract class question_bank_column_base {
     protected function init() {
     }
 
+    /**
+     * Set the column as heading
+     */
+    public function set_as_heading() {
+        $this->isheading = true;
+    }
+
     public function is_extra_row() {
         return false;
     }
@@ -258,8 +268,20 @@ abstract class question_bank_column_base {
         $this->display_end($question, $rowclasses);
     }
 
+    /**
+     * Output the opening column tag.  If it is set as heading, it will use <th> tag instead of <td>
+     *
+     * @param stdClass $question
+     * @param array $rowclasses
+     */
     protected function display_start($question, $rowclasses) {
-        echo '<td class="' . $this->get_classes() . '">';
+        $tag = 'td';
+        $attr = array('class' => $this->get_classes());
+        if ($this->isheading) {
+            $tag = 'th';
+            $attr['scope'] = 'row';
+        }
+        echo html_writer::start_tag($tag, $attr);
     }
 
     /**
@@ -292,8 +314,18 @@ abstract class question_bank_column_base {
      */
     protected abstract function display_content($question, $rowclasses);
 
+    /**
+     * Output the closing column tag
+     *
+     * @param type $question
+     * @param type $rowclasses
+     */
     protected function display_end($question, $rowclasses) {
-        echo "</td>\n";
+        $tag = 'td';
+        if ($this->isheading) {
+            $tag = 'th';
+        }
+        echo html_writer::end_tag($tag);
     }
 
     /**
@@ -885,7 +917,7 @@ class question_bank_view {
         $this->lastchangedid = optional_param('lastchanged',0,PARAM_INT);
 
         $this->init_column_types();
-        $this->init_columns($this->wanted_columns());
+        $this->init_columns($this->wanted_columns(), $this->heading_column());
         $this->init_sort();
 
         $PAGE->requires->yui2_lib('container');
@@ -901,6 +933,15 @@ class question_bank_view {
         return $columns;
     }
 
+    /**
+     * Specify the column heading
+     *
+     * @return string Column name for the heading
+     */
+    protected function heading_column() {
+        return 'questionname';
+    }
+
     protected function known_field_types() {
         return array(
             new question_bank_checkbox_column($this),
@@ -923,7 +964,13 @@ class question_bank_view {
         }
     }
 
-    protected function init_columns($wanted) {
+    /**
+     * Initializing table columns
+     *
+     * @param array $wanted Collection of column names
+     * @param string $heading The name of column that is set as heading
+     */
+    protected function init_columns($wanted, $heading = '') {
         $this->visiblecolumns = array();
         $this->extrarows = array();
         foreach ($wanted as $colname) {
@@ -938,6 +985,9 @@ class question_bank_view {
             }
         }
         $this->requiredcolumns = array_merge($this->visiblecolumns, $this->extrarows);
+        if (array_key_exists($heading, $this->requiredcolumns)) {
+            $this->requiredcolumns[$heading]->set_as_heading();
+        }
     }
 
     /**
-- 
1.7.9.5


From 3a15a7519c5aa4d7d65252de87267c3c21a76c6f Mon Sep 17 00:00:00 2001
From: Aaron Barnes <aaron@io.net.nz>
Date: Fri, 19 Oct 2012 00:13:40 +1300
Subject: [PATCH 838/903] MDL-36107 scorm: Fix non-static method call

---
 mod/scorm/lib.php |   27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/mod/scorm/lib.php b/mod/scorm/lib.php
index 27b4722..c3de373 100644
--- a/mod/scorm/lib.php
+++ b/mod/scorm/lib.php
@@ -1328,22 +1328,25 @@ function scorm_dndupload_handle($uploadinfo) {
  * @param array $grades grades array of users with grades - used when $userid = 0
  */
 function scorm_set_completion($scorm, $userid, $completionstate = COMPLETION_COMPLETE, $grades = array()) {
-    if (!completion_info::is_enabled()) {
-        return;
-    }
-
     $course = new stdClass();
     $course->id = $scorm->course;
+    $completion = new completion_info($course);
+
+    // Check if completion is enabled site-wide, or for the course
+    if (!$completion->is_enabled()) {
+        return;
+    }
 
     $cm = get_coursemodule_from_instance('scorm', $scorm->id, $scorm->course);
-    if (!empty($cm)) {
-        $completion = new completion_info($course);
-        if (empty($userid)) { //we need to get all the relevant users from $grades param.
-            foreach ($grades as $grade) {
-                $completion->update_state($cm, $completionstate, $grade->userid);
-            }
-        } else {
-            $completion->update_state($cm, $completionstate, $userid);
+    if (empty($cm) || !$completion->is_enabled($cm)) {
+            return;
+    }
+
+    if (empty($userid)) { //we need to get all the relevant users from $grades param.
+        foreach ($grades as $grade) {
+            $completion->update_state($cm, $completionstate, $grade->userid);
         }
+    } else {
+        $completion->update_state($cm, $completionstate, $userid);
     }
 }
-- 
1.7.9.5


From 75441ef5b2a33518c9fd2aeece79db2f62aebd35 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 19 Oct 2012 15:46:09 +0800
Subject: [PATCH 839/903] MDL-21625 Question bank: fixing whitespace

---
 mod/quiz/editlib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/quiz/editlib.php b/mod/quiz/editlib.php
index f64e282..d02f57b 100644
--- a/mod/quiz/editlib.php
+++ b/mod/quiz/editlib.php
@@ -1138,7 +1138,7 @@ class quiz_question_bank_view extends question_bank_view {
                 'editaction', 'previewaction');
     }
 
-     /**
+    /**
      * Specify the column heading
      *
      * @return string Column name for the heading
-- 
1.7.9.5


From ea67a0679dd2016dcffc29c0ebe1bf3e73940cae Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 19 Oct 2012 16:07:05 +0800
Subject: [PATCH 840/903] MDL-35910 Assignment 2.2: Fixed included files in
 assignment zip. If Marking button is enabled,
 assignment is open and is not finalized, then don't
 add file to zip

---
 mod/assignment/type/upload/assignment.class.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/assignment/type/upload/assignment.class.php b/mod/assignment/type/upload/assignment.class.php
index 91c5f5f..8ca17bd 100644
--- a/mod/assignment/type/upload/assignment.class.php
+++ b/mod/assignment/type/upload/assignment.class.php
@@ -1164,9 +1164,9 @@ class assignment_upload extends assignment_base {
         }
         $filename = str_replace(' ', '_', clean_filename($this->course->shortname.'-'.$this->assignment->name.'-'.$groupname.$this->assignment->id.".zip")); //name of new zip file.
         foreach ($submissions as $submission) {
-            // If assignment is open and submission is not finalized then don't add it to zip.
+            // If assignment is open and submission is not finalized and marking button enabled then don't add it to zip.
             $submissionstatus = $this->is_finalized($submission);
-            if ($this->isopen() && empty($submissionstatus)) {
+            if ($this->isopen() && empty($submissionstatus) && !empty($this->assignment->var4)) {
                 continue;
             }
             $a_userid = $submission->userid; //get userid
-- 
1.7.9.5


From 44da3c50fee04559a064b785d74baede356ce277 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Tue, 16 Oct 2012 10:44:34 +0200
Subject: [PATCH 841/903] MDL-36070 - Points label hides UP and Down ordering
 arrows and Delete Icon on Quiz edit page, in RTL
 mode (theme/standard)

---
 mod/quiz/styles.css |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 322ccdd..23e019d 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -401,7 +401,7 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl div.question {clear: right;}
 #page-mod-quiz-edit.dir-rtl div.question div.qnum {float: right;}
 #page-mod-quiz-edit.dir-rtl div.editq div.question div.content {float: right;height: 40px;}
-#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 5px;right:auto;}
+#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 50px;right:auto;}
 #page-mod-quiz-edit.dir-rtl div.question div.content div.questioncontrols {float: left;left: 0.3em; right:auto;}
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questionname,
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questiontext {float: right; padding-right: 0.3em;}
@@ -414,4 +414,4 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl .quizpagedelete {left: 0.2em;right:auto;}
 #page-mod-quiz-edit.dir-rtl div.quizcontents {clear: right;float: right;}
 #page-mod-quiz-edit.dir-rtl .questionbankwindow.block {float: left;}
-#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
\ No newline at end of file
+#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
-- 
1.7.9.5


From 00c7657edf4dee69b62aaf9846f6ae0532ad8f73 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sun, 14 Oct 2012 13:49:07 +0200
Subject: [PATCH 842/903] MDL-36033 - Left align Numeric value fields in
 Calculated and Numeric question, when in RTL mode

---
 mod/quiz/styles.css                 |    4 +++-
 question/type/calculated/styles.css |   14 ++++++++++++++
 question/type/numerical/styles.css  |   12 ++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 322ccdd..f3fbb42 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -414,4 +414,6 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl .quizpagedelete {left: 0.2em;right:auto;}
 #page-mod-quiz-edit.dir-rtl div.quizcontents {clear: right;float: right;}
 #page-mod-quiz-edit.dir-rtl .questionbankwindow.block {float: left;}
-#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
\ No newline at end of file
+#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
+.path-question-type.dir-rtl input[name="defaultmark"],
+#page-mod-quiz-edit.dir-rtl div.points input {direction: ltr;text-align: left;}
diff --git a/question/type/calculated/styles.css b/question/type/calculated/styles.css
index 132b629..d8f5dbf 100644
--- a/question/type/calculated/styles.css
+++ b/question/type/calculated/styles.css
@@ -6,3 +6,17 @@
 .que.calculated .answer input[type="text"] {
     width: 30%;
 }
+
+/* Numeric INPUT text boxes should be left aligned in RTL mode
+*/
+#page-question-type-calculated.dir-rtl input[name^="answer"],
+#page-question-type-calculated.dir-rtl input[name^="unit"],
+#page-question-type-calculated.dir-rtl input[name^="multiplier"],
+#page-question-type-calculated.dir-rtl input[name^="calcmax"],
+#page-question-type-calculated.dir-rtl input[name^="calcmin"],
+#page-question-type-calculated.dir-rtl input[name^="number"],
+#page-question-type-calculated.dir-rtl input[name^="tolerance"]
+{
+    direction: ltr;
+    text-align: left;
+}
diff --git a/question/type/numerical/styles.css b/question/type/numerical/styles.css
index 784c855..50958df 100644
--- a/question/type/numerical/styles.css
+++ b/question/type/numerical/styles.css
@@ -6,3 +6,15 @@
 .que.numerical .answer input[type="text"] {
     width: 30%;
 }
+
+/* Numeric INPUT text boxes should be left aligned in RTL mode
+*/
+#page-question-type-numerical.dir-rtl input[name="unitpenalty"],
+#page-question-type-numerical.dir-rtl input[name^="answer"],
+#page-question-type-numerical.dir-rtl input[name^="tolerance"],
+#page-question-type-numerical.dir-rtl input[name^="multiplier"],
+#page-question-type-numerical.dir-rtl input[name^="unit"]
+{
+    direction: ltr;
+    text-align: left;
+}
-- 
1.7.9.5


From 28788427423d18d41294d956ca72161ed94679a2 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Fri, 19 Oct 2012 16:49:34 +0800
Subject: [PATCH 843/903] MDL-36103 tablelib: links to user profiles are wrong
 in courses.

---
 lib/tablelib.php |   17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/lib/tablelib.php b/lib/tablelib.php
index 6de22af..2a08616 100644
--- a/lib/tablelib.php
+++ b/lib/tablelib.php
@@ -727,16 +727,19 @@ class flexible_table {
     function col_fullname($row) {
         global $COURSE, $CFG;
 
-        if (!$this->download) {
-            $profileurl = new moodle_url('/user/profile.php', array('id' => $row->{$this->useridfield}));
-            if ($COURSE->id != SITEID) {
-                $profileurl->param('course', $COURSE->id);
-            }
-            return html_writer::link($profileurl, fullname($row));
+        $name = fullname($row);
+        if ($this->download) {
+            return $name;
+        }
 
+        $userid = $row->{$this->useridfield};
+        if ($COURSE->id == SITEID) {
+            $profileurl = new moodle_url('/user/profile.php', array('id' => $userid));
         } else {
-            return fullname($row);
+            $profileurl = new moodle_url('/user/view.php',
+                    array('id' => $userid, 'course' => $COURSE->id));
         }
+        return html_writer::link($profileurl, $name);
     }
 
     /**
-- 
1.7.9.5


From 86483349663d735a85d09c072ab5197000b45ddb Mon Sep 17 00:00:00 2001
From: Rajesh Taneja <rajesh@moodle.com>
Date: Fri, 19 Oct 2012 11:58:25 +0800
Subject: [PATCH 844/903] MDL-36131 AJAX: Conditional activities will behave
 same as in non-ajax mode

---
 course/lib.php                    |   12 ++++++++----
 course/yui/toolboxes/toolboxes.js |   27 ++++++++++++++++++++-------
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index ef150d0..fcbd1b6 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1548,8 +1548,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                 $linkclasses = '';
                 $textclasses = '';
                 if ($accessiblebutdim) {
-                    $linkclasses .= ' dimmed';
-                    $textclasses .= ' dimmed_text';
+                    $linkclasses .= ' dimmed conditionalhidden';
+                    $textclasses .= ' dimmed_text conditionalhidden';
                     $accesstext = '<span class="accesshide">'.
                         get_string('hiddenfromstudents').': </span>';
                 } else {
@@ -1731,11 +1731,15 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
             // see the activity itself, or for staff)
             if (!$mod->uservisible) {
                 echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
-            } else if ($canviewhidden && !empty($CFG->enableavailability) && $mod->visible) {
+            } else if ($canviewhidden && !empty($CFG->enableavailability)) {
+                $visibilityclass = '';
+                if (!$mod->visible) {
+                    $visibilityclass = 'accesshide';
+                }
                 $ci = new condition_info($mod);
                 $fullinfo = $ci->get_full_information();
                 if($fullinfo) {
-                    echo '<div class="availabilityinfo">'.get_string($mod->showavailability
+                    echo '<div class="availabilityinfo '.$visibilityclass.'">'.get_string($mod->showavailability
                         ? 'userrestriction_visible'
                         : 'userrestriction_hidden','condition',
                         $fullinfo).'</div>';
diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
index 0f70c2c..db7dae8 100644
--- a/course/yui/toolboxes/toolboxes.js
+++ b/course/yui/toolboxes/toolboxes.js
@@ -33,7 +33,11 @@ YUI.add('moodle-course-toolboxes', function(Y) {
         SECTIONIDPREFIX : 'section-',
         SECTIONLI : 'li.section',
         SHOW : 'a.editing_show',
-        SHOWHIDE : 'a.editing_showhide'
+        SHOWHIDE : 'a.editing_showhide',
+        CONDITIONALHIDDEN : 'conditionalhidden',
+        AVAILABILITYINFODIV : 'div.availabilityinfo',
+        SHOWCLASS : 'editing_show',
+        ACCESSHIDECLASS : 'accesshide'
     };
 
     /**
@@ -68,18 +72,14 @@ YUI.add('moodle-course-toolboxes', function(Y) {
 
             var status = '';
             var value;
-            if (dimarea.hasClass(toggle_class)) {
+            if (button.hasClass(CSS.SHOWCLASS)) {
                 status = 'hide';
                 value = 1;
             } else {
                 status = 'show';
                 value = 0;
             }
-
-            // Change the UI
-            dimarea.toggleClass(toggle_class);
-            // We need to toggle dimming on the description too
-            element.all(CSS.CONTENTAFTERLINK).toggleClass(CSS.DIMMEDTEXT);
+            // Update button info.
             var newstring = M.util.get_string(status, 'moodle');
             hideicon.setAttrs({
                 'alt' : newstring,
@@ -88,6 +88,19 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             button.set('title', newstring);
             button.set('className', 'editing_'+status);
 
+            // If activity is conditionally hidden, then don't toggle.
+            if (!dimarea.hasClass(CSS.CONDITIONALHIDDEN)) {
+                // Change the UI.
+                dimarea.toggleClass(toggle_class);
+                // We need to toggle dimming on the description too.
+                element.all(CSS.CONTENTAFTERLINK).toggleClass(CSS.DIMMEDTEXT);
+            }
+            // Toggle availablity info for conditional activities.
+            var availabilityinfo = element.one(CSS.AVAILABILITYINFODIV);
+
+            if (availabilityinfo) {
+                availabilityinfo.toggleClass(CSS.ACCESSHIDECLASS);
+            }
             return value;
         },
         /**
-- 
1.7.9.5


From 98197952cc12587ed11d8dd13922b19df137b772 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 19 Oct 2012 19:56:32 +0800
Subject: [PATCH 845/903] weekly release 2.3.2+ (fix!)

---
 version.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/version.php b/version.php
index b25cd6c..6ccbfde 100644
--- a/version.php
+++ b/version.php
@@ -34,7 +34,7 @@ $version  = 2012062502.09;              // YYYYMMDD      = weekly release date o
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.3+ (Build: 20121018)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121018)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From d5fd21b6efed1eb925ef2ff3cb977e927a3d68af Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Tue, 9 Oct 2012 12:30:30 +0100
Subject: [PATCH 846/903] MDL-35571 theme_magazine: RTL fixes - WIKI title
 headings, ajax frontpage category/course chooser,
 right align logo, left align course name, left
 align login & user info.

---
 theme/magazine/style/core.css |   79 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 73 insertions(+), 6 deletions(-)

diff --git a/theme/magazine/style/core.css b/theme/magazine/style/core.css
index a617287..2cd9613 100644
--- a/theme/magazine/style/core.css
+++ b/theme/magazine/style/core.css
@@ -52,6 +52,10 @@ div#headerinner {
     line-height: 30px;
     min-width: 400px;
 }
+.dir-rtl #headright {
+    float: left;
+    min-width: 300px;
+}
 
 #headright a {
     color: #fff;
@@ -66,6 +70,10 @@ div#headerinner {
     font-size: 9px;
 }
 
+.dir-rtl #headright div.langmenu {
+    float: left !important;
+}
+
 #headleft {
     float: left;
     height: 30px;
@@ -74,6 +82,10 @@ div#headerinner {
     font-size: 12px;
 }
 
+.dir-rtl #headleft {
+    float: right;
+}
+
 /** Logo and menu bar divs and wrap **/
 
 #textcontainer-wrap {
@@ -99,6 +111,10 @@ div.thetitle {
     float: left;
 }
 
+.dir-rtl div.thetitle {
+    float: right;
+}
+
 #nologo {
     width: 337px;
     float: left;
@@ -107,6 +123,11 @@ div.thetitle {
     margin-top: 40px;
     }
 
+.dir-rtl #nologo {
+    float: right;
+    padding-right: 3px;
+}
+
 #nologo.nomenu {
     width: 100%;
 }
@@ -118,25 +139,27 @@ div.thetitle {
     font-weight: 800;
     letter-spacing: -1px;
     line-height: 45px;
-
-
 }
+
 #nologo a:hover {
     text-decoration: none;
 }
+
 div.rightinfo {
     float: right;
     min-width: 470px;
     height: 130px;
     overflow: hidden;
 }
+.dir-rtl div.rightinfo {
+    float: left;
+}
 
 #menucontainer {
     height: 45px;
     margin-top: 40px;
 }
 
-
 /** main content wraps **/
 
 #outercontainer {
@@ -191,6 +214,10 @@ div.jcontrolsleft {
     float: left;
     min-width: 100px;
 }
+.dir-rtl div.jcontrolsleft {
+    float:right;
+    margin-right: 15px;
+}
 
 div.jcontrolsright {
     float: right;
@@ -199,6 +226,11 @@ div.jcontrolsright {
     margin-right: 15px;
 }
 
+.dir-rtl div.jcontrolsright {
+    float: left;
+    margin-left: 15px;
+}
+
 div.jcontrolsright div.singlebutton, div.jcontrolsright div.forumsearch {
     margin: 5px 0px 0px;
 }
@@ -243,6 +275,9 @@ div.johndocsleft {
     color: #333333;
     font-size: 11px;
 }
+.dir-rtl div.johndocsleft {
+    float: right;
+}
 
 /** Some breadcrumb style **/
 
@@ -410,7 +445,12 @@ div#jcontrols_button span.arrow.sep {
 
 /** inner block style for decent display of recent news, etc **/
 
-.block_recent_activity.block_docked div.content h2.main, .block_recent_activity.block_docked div.content h3.main, .side-pre .block div.content h2.main,.side-post .block div.content h2.main,.block div.content h3.main,.block div.content h2 {
+.block_recent_activity.block_docked div.content h2.main,
+.block_recent_activity.block_docked div.content h3.main,
+.side-pre .block div.content h2.main,
+.side-post .block div.content h2.main,
+.block div.content h3.main,
+.block div.content h2 {
     font-size: 13px;
     color: #333;
     font-weight: 800;
@@ -448,7 +488,7 @@ div.yui3-widget-bd h1.helpheading {
 
 .yui-module.yui-overlay.yui-panel div.hd {
     background: #eeeeee url([[pix:theme|bart5]]) repeat-x 0% 90%;
-    }
+}
 
 /**moodle dropdown css for yui menu **/
 
@@ -851,6 +891,10 @@ div.coursebox h3.name a {
     padding-left: 5px !important;
 }
 
+.dir-rtl .unlist ul.teachers {
+    padding-right: 5px;
+}
+
 .unlist ul.teachers li {
     font-size: 10px;
 }
@@ -893,6 +937,9 @@ div.course_category_tree div.category,div.course_category_tree div.category_labe
 div.course_category_tree div.category.with_children div.category_label {
     background-position: 0 55% !important;
 }
+.dir-rtl div.course_category_tree div.category.with_children div.category_label {
+    background-position: right center !important;
+}
 
 div.course_category_tree div.course.odd {
     background: #eee;
@@ -906,6 +953,23 @@ div.category.subcategory.with_children {
     margin-left: 20px;
 }
 
+.dir-rtl div.category.subcategory.with_children {
+    margin-right: 20px;
+}
+
+.dir-rtl .course_category_tree .category .course_info {
+    padding-right: 20px;
+}
+
+.dir-rtl.jsenabled .course_category_tree .category.with_children.collapsed .category_label {
+    backkground-position: right center !important;
+}
+
+.dir-rtl .course_category_tree .category_label,
+.dir-rtl .course_category_tree .category .course {
+    padding-right: 35px;
+}
+
 div.course_category_tree div.controls {
     font-size: 10px;
     color: #666;
@@ -1025,6 +1089,9 @@ table.glossarypost td.entry h3 {
     margin-bottom: 3px;
     margin-top: 2px;
 }
+#page-mod-wiki-view.dir-rtl h2.wiki_headingtitle {
+    text-align: right;
+}
 
 /**HR in content blocks **/
 
@@ -1126,4 +1193,4 @@ div.singlebutton.forumaddnew {
 
 #page-course-info div.generalbox ul, #page-course-info div.generalbox li {
     list-style-type: none;
-}
\ No newline at end of file
+}
-- 
1.7.9.5


From cd2ae155de61a4e477dadfba418fdc019a4f9e86 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 19 Oct 2012 23:39:01 +0100
Subject: [PATCH 847/903] MDL-36137 theme_magazine: changed forum and
 description info from center to left aligned.

---
 theme/magazine/style/core.css |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/theme/magazine/style/core.css b/theme/magazine/style/core.css
index a617287..242e021 100644
--- a/theme/magazine/style/core.css
+++ b/theme/magazine/style/core.css
@@ -1040,7 +1040,7 @@ table.glossarypost td.entry h3 {
 
 div#intro {
     border: none;
-    text-align: center;
+    text-align: left;
     font-size: 14px;
     color: #333333;
 }
-- 
1.7.9.5


From 691b9c81cb7eef2a9f7cc7902d1d87e660862306 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 20 Oct 2012 00:34:52 +0000
Subject: [PATCH 848/903] Automatically generated installer lang files

---
 install/lang/en_fix/langconfig.php |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 install/lang/en_fix/langconfig.php

diff --git a/install/lang/en_fix/langconfig.php b/install/lang/en_fix/langconfig.php
new file mode 100644
index 0000000..d563203
--- /dev/null
+++ b/install/lang/en_fix/langconfig.php
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'English (fixes)';
-- 
1.7.9.5


From db16ec27536057adee2af49d2c2a53fd7a157f8d Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Sun, 21 Oct 2012 01:39:30 +0100
Subject: [PATCH 849/903] MDL-31934 theme_base: Adds highlight color to unread
 forum posts.

---
 theme/base/style/core.css |   13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 4a5151b..481df9b 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -994,3 +994,16 @@ sup {vertical-align: super;}
     -webkit-box-shadow: 0px 0px 10px 0px #CCCCCC;
     -moz-box-shadow: 0px 0px 10px 0px #CCCCCC;
 }
+
+/* Forumpost unread
+-------------------------*/
+
+#page-mod-forum-view .unread,
+.forumpost.unread .row.header,
+.path-course-view .unread,
+span.unread {
+    background-color: #FFD;
+}
+.forumpost.unread .row.header {
+    border-bottom: 1px solid #DDD;
+}
-- 
1.7.9.5


From 8be3d5ab030ab215333ebba7af07fdf5b0c10d47 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Sun, 21 Oct 2012 15:56:01 +0800
Subject: [PATCH 850/903] MDL-35297 book: replay some steps lost when book
 landed to core

This commit replays, conditionally, all the upgrade steps from
MOODLE_19_STABLE to MOODLE_23_STABLE in the mod_book activity. That
guarentees that any site using the mod_book before landing to core,
no matter if it was the latest or an outdated one will upgrade
perfectly to the expected current version.

As a general rule, everytime one contrib plugin lands to core, its
complete upgrade code must be kept, at least until the core version
that introduced it, is out completely from the upgrade requirement
conditions.

In this case, with the missing upgrade code being added to 2.4, it
will be safe to delete the upgrade steps once 2.5 (or upwards) become
a requirement. Never always.

Conflicts:
	mod/book/version.php
---
 mod/book/db/upgrade.php    |  146 ++++++++++++++++++++++++++++++++++++++
 mod/book/db/upgradelib.php |  168 ++++++++++++++++++++++++++++++++++++++++++++
 mod/book/version.php       |    2 +-
 3 files changed, 315 insertions(+), 1 deletion(-)
 create mode 100644 mod/book/db/upgradelib.php

diff --git a/mod/book/db/upgrade.php b/mod/book/db/upgrade.php
index 3fb1085..c4709f0 100644
--- a/mod/book/db/upgrade.php
+++ b/mod/book/db/upgrade.php
@@ -40,6 +40,152 @@ function xmldb_book_upgrade($oldversion) {
     // Moodle v2.3.0 release upgrade line
     // Put any upgrade step following this
 
+    // Note: The next steps (up to 2012061710 included, are a "replay" of old upgrade steps,
+    // because some sites updated to Moodle 2.3 didn't have the latest contrib mod_book
+    // installed, so some required changes were missing.
+    //
+    // All the steps are run conditionally so sites upgraded from latest contrib mod_book or
+    // new (2.3 and upwards) sites won't get affected.
+    //
+    // See MDL-35297 and commit msg for more information.
+
+    if ($oldversion < 2012061703) {
+        // Rename field summary on table book to intro
+        $table = new xmldb_table('book');
+        $field = new xmldb_field('summary', XMLDB_TYPE_TEXT, null, null, null, null, null, 'name');
+
+        // Launch rename field summary
+        if ($dbman->field_exists($table, $field)) {
+            $dbman->rename_field($table, $field, 'intro');
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061703, 'book');
+    }
+
+    if ($oldversion < 2012061704) {
+        // Define field introformat to be added to book
+        $table = new xmldb_table('book');
+        $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'intro');
+
+        // Launch add field introformat
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+            // Conditionally migrate to html format in intro
+            // Si está activo el htmleditor!!!!!
+            if ($CFG->texteditors !== 'textarea') {
+                $rs = $DB->get_recordset('book', array('introformat'=>FORMAT_MOODLE), '', 'id,intro,introformat');
+                foreach ($rs as $b) {
+                    $b->intro       = text_to_html($b->intro, false, false, true);
+                    $b->introformat = FORMAT_HTML;
+                    $DB->update_record('book', $b);
+                    upgrade_set_timeout();
+                }
+                unset($b);
+                $rs->close();
+            }
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061704, 'book');
+    }
+
+    if ($oldversion < 2012061705) {
+        // Define field introformat to be added to book
+        $table = new xmldb_table('book_chapters');
+        $field = new xmldb_field('contentformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'content');
+
+        // Launch add field introformat
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+
+            $DB->set_field('book_chapters', 'contentformat', FORMAT_HTML, array());
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061705, 'book');
+    }
+
+    if ($oldversion < 2012061706) {
+        require_once("$CFG->dirroot/mod/book/db/upgradelib.php");
+
+        $sqlfrom = "FROM {book} b
+                    JOIN {modules} m ON m.name = 'book'
+                    JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = b.id)";
+
+        $count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom");
+
+        if ($rs = $DB->get_recordset_sql("SELECT b.id, b.course, cm.id AS cmid $sqlfrom ORDER BY b.course, b.id")) {
+
+            $pbar = new progress_bar('migratebookfiles', 500, true);
+
+            $i = 0;
+            foreach ($rs as $book) {
+                $i++;
+                upgrade_set_timeout(360); // set up timeout, may also abort execution
+                $pbar->update($i, $count, "Migrating book files - $i/$count.");
+
+                $context = context_module::instance($book->cmid);
+
+                mod_book_migrate_moddata_dir_to_legacy($book, $context, '/');
+
+                // remove dirs if empty
+                @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id/");
+                @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/");
+                @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/");
+                @rmdir("$CFG->dataroot/$book->course/");
+            }
+            $rs->close();
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061706, 'book');
+    }
+
+    if ($oldversion < 2012061707) {
+        // Define field disableprinting to be dropped from book
+        $table = new xmldb_table('book');
+        $field = new xmldb_field('disableprinting');
+
+        // Conditionally launch drop field disableprinting
+        if ($dbman->field_exists($table, $field)) {
+            $dbman->drop_field($table, $field);
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061707, 'book');
+    }
+
+    if ($oldversion < 2012061708) {
+        unset_config('book_tocwidth');
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061708, 'book');
+    }
+
+    if ($oldversion < 2012061709) {
+        require_once("$CFG->dirroot/mod/book/db/upgradelib.php");
+
+        mod_book_migrate_all_areas();
+
+        upgrade_mod_savepoint(true, 2012061709, 'book');
+    }
+
+    if ($oldversion < 2012061710) {
+
+        // Define field revision to be added to book
+        $table = new xmldb_table('book');
+        $field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'customtitles');
+
+        // Conditionally launch add field revision
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+        // book savepoint reached
+        upgrade_mod_savepoint(true, 2012061710, 'book');
+    }
+    // End of MDL-35297 "replayed" steps.
 
     return true;
 }
diff --git a/mod/book/db/upgradelib.php b/mod/book/db/upgradelib.php
new file mode 100644
index 0000000..5411930
--- /dev/null
+++ b/mod/book/db/upgradelib.php
@@ -0,0 +1,168 @@
+<?php
+// This file is part of Book module for Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Book module upgrade related helper functions
+ *
+ * @package    mod_book
+ * @copyright  2010 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * Migrate book files stored in moddata folders.
+ *
+ * Please note it was a big mistake to store the files there in the first place!
+ *
+ * @param stdClass $book
+ * @param stdClass $context
+ * @param string $path
+ * @return void
+ */
+function mod_book_migrate_moddata_dir_to_legacy($book, $context, $path) {
+    global $OUTPUT, $CFG;
+
+    $base = "$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id";
+    $fulldir = $base.$path;
+
+    if (!is_dir($fulldir)) {
+        // does not exist
+        return;
+    }
+
+    $fs      = get_file_storage();
+    $items   = new DirectoryIterator($fulldir);
+
+    foreach ($items as $item) {
+        if ($item->isDot()) {
+            unset($item); // release file handle
+            continue;
+        }
+
+        if ($item->isLink()) {
+            // do not follow symlinks - they were never supported in moddata, sorry
+            unset($item); // release file handle
+            continue;
+        }
+
+        if ($item->isFile()) {
+            if (!$item->isReadable()) {
+                echo $OUTPUT->notification(" File not readable, skipping: ".$fulldir.$item->getFilename());
+                unset($item); // release file handle
+                continue;
+            }
+
+            $filepath = clean_param("/$CFG->moddata/book/$book->id".$path, PARAM_PATH);
+            $filename = clean_param($item->getFilename(), PARAM_FILE);
+
+            if ($filename === '') {
+                // unsupported chars, sorry
+                unset($item); // release file handle
+                continue;
+            }
+
+            if (textlib::strlen($filepath) > 255) {
+                echo $OUTPUT->notification(" File path longer than 255 chars, skipping: ".$fulldir.$item->getFilename());
+                unset($item); // release file handle
+                continue;
+            }
+
+            if (!$fs->file_exists($context->id, 'course', 'legacy', '0', $filepath, $filename)) {
+                $file_record = array('contextid'=>$context->id, 'component'=>'course', 'filearea'=>'legacy', 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
+                                     'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
+                $fs->create_file_from_pathname($file_record, $fulldir.$item->getFilename());
+            }
+            $oldpathname = $fulldir.$item->getFilename();
+            unset($item); // release file handle
+            @unlink($oldpathname);
+
+        } else {
+            // migrate recursively all subdirectories
+            $oldpathname = $base.$item->getFilename().'/';
+            $subpath     = $path.$item->getFilename().'/';
+            unset($item);  // release file handle
+            mod_book_migrate_moddata_dir_to_legacy($book, $context, $subpath);
+            @rmdir($oldpathname); // deletes dir if empty
+        }
+    }
+    unset($items); // release file handles
+}
+
+/**
+ * Migrate legacy files in intro and chapters
+ * @return void
+ */
+function mod_book_migrate_all_areas() {
+    global $DB;
+
+    $rsbooks = $DB->get_recordset('book');
+    foreach($rsbooks as $book) {
+        upgrade_set_timeout(360); // set up timeout, may also abort execution
+        $cm = get_coursemodule_from_instance('book', $book->id);
+        $context = context_module::instance($cm->id);
+        mod_book_migrate_area($book, 'intro', 'book', $book->course, $context, 'mod_book', 'intro', 0);
+
+        $rschapters = $DB->get_recordset('book_chapters', array('bookid'=>$book->id));
+        foreach ($rschapters as $chapter) {
+            mod_book_migrate_area($chapter, 'content', 'book_chapters', $book->course, $context, 'mod_book', 'chapter', $chapter->id);
+        }
+        $rschapters->close();
+    }
+    $rsbooks->close();
+}
+
+/**
+ * Migrate one area, this should be probably part of moodle core...
+ *
+ * @param stdClass $record object to migrate files (book, chapter)
+ * @param string $field field in the record we are going to migrate
+ * @param string $table DB table containing the information to migrate
+ * @param int $courseid id of the course the book module belongs to
+ * @param context_module $context context of the book module
+ * @param string $component component to be used for the migrated files
+ * @param string $filearea filearea to be used for the migrated files
+ * @param int $itemid id to be used for the migrated files
+ * @return void
+ */
+function mod_book_migrate_area($record, $field, $table, $courseid, $context, $component, $filearea, $itemid) {
+    global $CFG, $DB;
+
+    $fs = get_file_storage();
+
+    foreach(array(get_site()->id, $courseid) as $cid) {
+        $matches = null;
+        $ooldcontext = context_course::instance($cid);
+        if (preg_match_all("|$CFG->wwwroot/file.php(\?file=)?/$cid(/[^\s'\"&\?#]+)|", $record->$field, $matches)) {
+            $file_record = array('contextid'=>$context->id, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid);
+            foreach ($matches[2] as $i=>$filepath) {
+                if (!$file = $fs->get_file_by_hash(sha1("/$ooldcontext->id/course/legacy/0".$filepath))) {
+                    continue;
+                }
+                try {
+                    if (!$newfile = $fs->get_file_by_hash(sha1("/$context->id/$component/$filearea/$itemid".$filepath))) {
+                        $fs->create_file_from_storedfile($file_record, $file);
+                    }
+                    $record->$field = str_replace($matches[0][$i], '@@PLUGINFILE@@'.$filepath, $record->$field);
+                } catch (Exception $ex) {
+                    // ignore problems
+                }
+                $DB->set_field($table, $field, $record->$field, array('id'=>$record->id));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/mod/book/version.php b/mod/book/version.php
index e187cb3..f37c00d 100644
--- a/mod/book/version.php
+++ b/mod/book/version.php
@@ -25,6 +25,6 @@
 defined('MOODLE_INTERNAL') || die;
 
 $module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version   = 2012061702; // The current module version (Date: YYYYMMDDXX)
+$module->version   = 2012061710; // The current module version (Date: YYYYMMDDXX)
 $module->requires  = 2012061700; // Requires this Moodle version
 $module->cron      = 0;          // Period for cron to check this module (secs)
-- 
1.7.9.5


From 9b5de362cfaeb3fe7a1a6c13e1c0be32f29fa940 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 25 Oct 2012 00:34:52 +0000
Subject: [PATCH 851/903] Automatically generated installer lang files

---
 install/lang/zh_tw/error.php   |    2 +-
 install/lang/zh_tw/install.php |   12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/install/lang/zh_tw/error.php b/install/lang/zh_tw/error.php
index e678417..0bedb5f 100644
--- a/install/lang/zh_tw/error.php
+++ b/install/lang/zh_tw/error.php
@@ -39,7 +39,7 @@ $string['cannotsavemd5file'] = '無法儲存 md5 檔案。';
 $string['cannotsavezipfile'] = '無法儲存 ZIP 檔案。';
 $string['cannotunzipfile'] = '無法解壓縮檔案。';
 $string['componentisuptodate'] = '元件已經是最新的了。';
-$string['downloadedfilecheckfailed'] = '下載檔案檢查錯誤。';
+$string['downloadedfilecheckfailed'] = '下載的檔案檢查失敗';
 $string['invalidmd5'] = '無效的 md5';
 $string['missingrequiredfield'] = '缺少部份必填欄位';
 $string['remotedownloaderror'] = '下載元件至伺服器失敗，檢查代理伺服器的設定、高度建議安裝PHP cURL，您必須手動下載<a href="{$a->url}">{$a->url}</a>，並且複製到伺服器"{$a->dest}" 解壓縮';
diff --git a/install/lang/zh_tw/install.php b/install/lang/zh_tw/install.php
index c63fa29..0b79132 100644
--- a/install/lang/zh_tw/install.php
+++ b/install/lang/zh_tw/install.php
@@ -33,7 +33,7 @@ defined('MOODLE_INTERNAL') || die();
 $string['admindirname'] = '管理目錄';
 $string['availablelangs'] = '可使用的語言包';
 $string['chooselanguagehead'] = '選擇一種語言';
-$string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。稍後您可以根據需要重新選擇用於網站和使用者的語言。';
+$string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。這語言將成為此網站預設的語言。稍後您可以根據需要重新選擇。';
 $string['clialreadyconfigured'] = '檔案 config.php  已經存在，若你要安裝這一網站，請使用dmin/cli/install_database.php';
 $string['clialreadyinstalled'] = '檔案 config.php  已經存在，若你要升級這一網站，請使用admin/cli/upgrade.php';
 $string['cliinstallheader'] = 'Moodle {$a} 指令行安裝程式';
@@ -45,6 +45,8 @@ $string['datarootpermission'] = '資料目錄存取授權';
 $string['dbprefix'] = '資料表名稱的前置字元';
 $string['dirroot'] = 'Moodle目錄';
 $string['environmenthead'] = '檢查您的環境中...';
+$string['environmentsub2'] = '每一個Moodle版本都有一些PHP版本的最低要求和一堆強制開啟的PHP擴展。在進行安裝或升級之前都需要作完整的環境檢查。<br />
+若你不知道要怎樣新的PHP版本或啟用PHP擴展，請聯絡伺服器管理員。';
 $string['errorsinenvironment'] = '環境檢查失敗';
 $string['installation'] = '安裝';
 $string['langdownloaderror'] = '很不幸地，語言“{$a}”並未安裝。安裝過程將以英文繼續。';
@@ -53,15 +55,17 @@ $string['memorylimithelp'] = '<p>PHP記憶體上限目前設定為{$a}。</p>
 <p>建議您儘可能將PHP的上限設得高一點，比如16M。
 以下有幾種方式您可以試試:
 <ol>
-<li>如果可以的話，用<i>--enable-memory-limit</i>重新編譯PHP。讓Moodle自己設定記憶體上限.
-<li>如果您要使用php.ini檔, 您可以改變<b>memory_limit</b>這個設定值，例如到16M。如果您無法使用這個檔，您可以請您的管理者幫您做
-<li>在一些PHP伺服器上，您可以在Moodle目錄下，建立.htaccess檔，包含這行:<p><blockquote>php_value memory_limit 16M</blockquote></p>
+<li>如果可以的話，用<i>--enable-memory-limit</i>重新編譯PHP。讓 Moodle 自己設定記憶體上限。
+<li>如果您要使用 php.ini 檔，您可以改變<b>memory_limit</b>這個設定值，例如到16M。如果您無法使用這個檔，您可以請您的管理者幫您做
+<li>在一些PHP伺服器上，您可以在Moodle目錄下，建立 .htaccess 檔，包含這行:<p><blockquote>php_value memory_limit 16M</blockquote></p>
 <p>然而，在一些伺服器上，這將造成<b>所有的</b> PHP 網頁無法運作(當您看這些網頁時，您就會看到錯誤) 因此，您就必須將 .htaccess 檔案移除。
 </ol>';
 $string['paths'] = '路徑';
 $string['pathserrcreatedataroot'] = '資料目錄 ({$a->dataroot})無法由這安裝程式建立';
 $string['pathshead'] = '確認路徑';
 $string['pathsrodataroot'] = '資料根目錄是無法寫入的';
+$string['pathsroparentdataroot'] = '上層目錄({$a->parent})是不可寫入的。安裝程式無法建立資料目錄({$a->dataroot})。';
+$string['pathssubdataroot'] = '你需要有一個地方讓Moodle可以儲存上傳的檔案。這一目錄對於網頁伺服器用戶(通常是"nobody"或"apache")而言，應該是可讀的和<b>可寫的</b>。但是它必須不能經由網頁直接存取。若此目錄不存在，這安裝程式將會試著建立它。';
 $string['pathssubdirroot'] = 'Moodle安裝的完整目錄徑路';
 $string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全';
 $string['pathswrongadmindir'] = '管理目錄不存在';
-- 
1.7.9.5


From 1754dc2cb6cd98d64b417cf374ba082b8d65db41 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Sun, 7 Oct 2012 09:55:08 +0100
Subject: [PATCH 852/903] MDL-35836 Rewrite doctonewwindow handling to use
 delegation instead of individual events

---
 course/lib.php                      |    2 +-
 course/yui/modchooser/modchooser.js |   30 -----------------------------
 lib/javascript-static.js            |   36 +++++++++++++++++++++++++++++++++++
 lib/outputrenderers.php             |   10 +++++++---
 4 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index f799b0d..c047c89 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1972,7 +1972,7 @@ function get_module_metadata($course, $modnames, $sectionreturn = 0) {
                 if ($sm->string_exists('modulename_link', $modname)) {  // Link to further info in Moodle docs
                     $link = get_string('modulename_link', $modname);
                     $linktext = get_string('morehelp');
-                    $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext), array('class' => 'helpdoclink'));
+                    $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink'));
                 }
             }
             $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
diff --git a/course/yui/modchooser/modchooser.js b/course/yui/modchooser/modchooser.js
index aea4040..f87a5ec 100644
--- a/course/yui/modchooser/modchooser.js
+++ b/course/yui/modchooser/modchooser.js
@@ -36,36 +36,6 @@ YUI.add('moodle-course-modchooser', function(Y) {
 
             // Catch the page toggle
             Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
-
-            // Ensure that help links are opened in an appropriate popup
-            this.container.all('div.helpdoclink a').on('click', function(e) {
-                var anchor = e.target.ancestor('a', true);
-
-                var args = {
-                    'name'          : 'popup',
-                    'url'           : anchor.getAttribute('href'),
-                    'option'        : ''
-                };
-                var options = [
-                    'height=600',
-                    'width=800',
-                    'top=0',
-                    'left=0',
-                    'menubar=0',
-                    'location=0',
-                    'scrollbars',
-                    'resizable',
-                    'toolbar',
-                    'status',
-                    'directories=0',
-                    'fullscreen=0',
-                    'dependent'
-                ]
-                args.options = options.join(',');
-
-                // Note: openpopup is provided by lib/javascript-static.js
-                openpopup(e, args);
-            });
         },
         /**
          * Update any section areas within the scope of the specified
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 6e7042d..25159f6 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1350,6 +1350,42 @@ function hide_item(itemid) {
     }
 }
 
+M.util.help_popups = {
+    setup : function(Y) {
+        Y.one('body').delegate('click', this.open_popup, 'a.helplinkpopup', this);
+    },
+    open_popup : function(e) {
+        // Prevent the default page action
+        e.preventDefault();
+
+        // Grab the anchor that was clicked
+        var anchor = e.target.ancestor('a', true);
+        var args = {
+            'name'          : 'popup',
+            'url'           : anchor.getAttribute('href'),
+            'options'       : ''
+        };
+        var options = [
+            'height=600',
+            'width=800',
+            'top=0',
+            'left=0',
+            'menubar=0',
+            'location=0',
+            'scrollbars',
+            'resizable',
+            'toolbar',
+            'status',
+            'directories=0',
+            'fullscreen=0',
+            'dependent'
+        ]
+        args.options = options.join(',');
+
+        openpopup(e, args);
+    }
+}
+
 M.util.help_icon = {
     Y : null,
     instance : null,
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 717ad00..0c6c16a 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -372,6 +372,9 @@ class core_renderer extends renderer_base {
         // flow player embedding support
         $this->page->requires->js_function_call('M.util.load_flowplayer');
 
+        // Set up help link popups for all links with the helplinkpopup class
+        $this->page->requires->js_init_call('M.util.help_popups.setup');
+
         $this->page->requires->js_function_call('setTimeout', array('fix_column_widths()', 20));
 
         $focus = $this->page->focuscontrol;
@@ -1495,9 +1498,10 @@ class core_renderer extends renderer_base {
      *
      * @param string $path The page link after doc root and language, no leading slash.
      * @param string $text The text to be displayed for the link
+     * @param boolean $forcepopup Whether to force a popup regardless of the value of $CFG->doctonewwindow
      * @return string
      */
-    public function doc_link($path, $text = '') {
+    public function doc_link($path, $text = '', $forcepopup = false) {
         global $CFG;
 
         $icon = $this->pix_icon('docs', $text, 'moodle', array('class'=>'iconhelp'));
@@ -1505,8 +1509,8 @@ class core_renderer extends renderer_base {
         $url = new moodle_url(get_docs_url($path));
 
         $attributes = array('href'=>$url);
-        if (!empty($CFG->doctonewwindow)) {
-            $attributes['id'] = $this->add_action_handler(new popup_action('click', $url));
+        if (!empty($CFG->doctonewwindow) || $forcepopup) {
+            $attributes['class'] = 'helplinkpopup';
         }
 
         return html_writer::tag('a', $icon.$text, $attributes);
-- 
1.7.9.5


From 8516492cc4725c3da7e05f4bc826b312475ec735 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Fri, 12 Oct 2012 10:41:33 +0100
Subject: [PATCH 853/903] MDL-36023 AJAX Move the instantiation of the
 dialogue to display time

---
 lib/yui/chooserdialogue/chooserdialogue.js |   28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/lib/yui/chooserdialogue/chooserdialogue.js b/lib/yui/chooserdialogue/chooserdialogue.js
index e67af29..9044c6a 100644
--- a/lib/yui/chooserdialogue/chooserdialogue.js
+++ b/lib/yui/chooserdialogue/chooserdialogue.js
@@ -20,11 +20,25 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
         // The initial overflow setting
         initialoverflow : '',
 
+        bodycontent : null,
+        headercontent : null,
+        instanceconfig : null,
+
         setup_chooser_dialogue : function(bodycontent, headercontent, config) {
+            this.bodycontent = bodycontent;
+            this.headercontent = headercontent;
+            this.instanceconfig = config;
+        },
+
+        prepare_chooser : function () {
+            if (this.overlay) {
+                return;
+            }
+
             // Set Default options
             var params = {
-                bodyContent : bodycontent.get('innerHTML'),
-                headerContent : headercontent.get('innerHTML'),
+                bodyContent : this.bodycontent.get('innerHTML'),
+                headerContent : this.headercontent.get('innerHTML'),
                 draggable : true,
                 visible : false, // Hide by default
                 zindex : 100, // Display in front of other items
@@ -33,16 +47,16 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
             }
 
             // Override with additional options
-            for (paramkey in config) {
-              params[paramkey] = config[paramkey];
+            for (paramkey in this.instanceconfig) {
+              params[paramkey] = this.instanceconfig[paramkey];
             }
 
             // Create the overlay
             this.overlay = new M.core.dialogue(params);
 
             // Remove the template for the chooser
-            bodycontent.remove();
-            headercontent.remove();
+            this.bodycontent.remove();
+            this.headercontent.remove();
 
             // Hide and then render the overlay
             this.overlay.hide();
@@ -63,6 +77,8 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
          * @return void
          */
         display_chooser : function (e) {
+            this.prepare_chooser();
+
             // Stop the default event actions before we proceed
             e.preventDefault();
 
-- 
1.7.9.5


From 238d0ca1cda2489f5637fa2fefcaa89fbbaa530d Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Sun, 7 Oct 2012 09:55:08 +0100
Subject: [PATCH 854/903] MDL-35836 Rewrite doctonewwindow handling to use
 delegation instead of individual events

---
 course/lib.php                      |    2 +-
 course/yui/modchooser/modchooser.js |   30 -----------------------------
 lib/javascript-static.js            |   36 +++++++++++++++++++++++++++++++++++
 lib/outputrenderers.php             |   10 +++++++---
 4 files changed, 44 insertions(+), 34 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index ef150d0..7dad564 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1970,7 +1970,7 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) {
                 if ($sm->string_exists('modulename_link', $modname)) {  // Link to further info in Moodle docs
                     $link = get_string('modulename_link', $modname);
                     $linktext = get_string('morehelp');
-                    $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext), array('class' => 'helpdoclink'));
+                    $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink'));
                 }
             }
             $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
diff --git a/course/yui/modchooser/modchooser.js b/course/yui/modchooser/modchooser.js
index aea4040..f87a5ec 100644
--- a/course/yui/modchooser/modchooser.js
+++ b/course/yui/modchooser/modchooser.js
@@ -36,36 +36,6 @@ YUI.add('moodle-course-modchooser', function(Y) {
 
             // Catch the page toggle
             Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
-
-            // Ensure that help links are opened in an appropriate popup
-            this.container.all('div.helpdoclink a').on('click', function(e) {
-                var anchor = e.target.ancestor('a', true);
-
-                var args = {
-                    'name'          : 'popup',
-                    'url'           : anchor.getAttribute('href'),
-                    'option'        : ''
-                };
-                var options = [
-                    'height=600',
-                    'width=800',
-                    'top=0',
-                    'left=0',
-                    'menubar=0',
-                    'location=0',
-                    'scrollbars',
-                    'resizable',
-                    'toolbar',
-                    'status',
-                    'directories=0',
-                    'fullscreen=0',
-                    'dependent'
-                ]
-                args.options = options.join(',');
-
-                // Note: openpopup is provided by lib/javascript-static.js
-                openpopup(e, args);
-            });
         },
         /**
          * Update any section areas within the scope of the specified
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 4189c37..5d9db5d 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1374,6 +1374,42 @@ function hide_item(itemid) {
     }
 }
 
+M.util.help_popups = {
+    setup : function(Y) {
+        Y.one('body').delegate('click', this.open_popup, 'a.helplinkpopup', this);
+    },
+    open_popup : function(e) {
+        // Prevent the default page action
+        e.preventDefault();
+
+        // Grab the anchor that was clicked
+        var anchor = e.target.ancestor('a', true);
+        var args = {
+            'name'          : 'popup',
+            'url'           : anchor.getAttribute('href'),
+            'options'       : ''
+        };
+        var options = [
+            'height=600',
+            'width=800',
+            'top=0',
+            'left=0',
+            'menubar=0',
+            'location=0',
+            'scrollbars',
+            'resizable',
+            'toolbar',
+            'status',
+            'directories=0',
+            'fullscreen=0',
+            'dependent'
+        ]
+        args.options = options.join(',');
+
+        openpopup(e, args);
+    }
+}
+
 M.util.help_icon = {
     Y : null,
     instance : null,
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index dd03dc8..8e3ff2a 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -372,6 +372,9 @@ class core_renderer extends renderer_base {
         // flow player embedding support
         $this->page->requires->js_function_call('M.util.load_flowplayer');
 
+        // Set up help link popups for all links with the helplinkpopup class
+        $this->page->requires->js_init_call('M.util.help_popups.setup');
+
         $this->page->requires->js_function_call('setTimeout', array('fix_column_widths()', 20));
 
         $focus = $this->page->focuscontrol;
@@ -1495,9 +1498,10 @@ class core_renderer extends renderer_base {
      *
      * @param string $path The page link after doc root and language, no leading slash.
      * @param string $text The text to be displayed for the link
+     * @param boolean $forcepopup Whether to force a popup regardless of the value of $CFG->doctonewwindow
      * @return string
      */
-    public function doc_link($path, $text = '') {
+    public function doc_link($path, $text = '', $forcepopup = false) {
         global $CFG;
 
         $icon = $this->pix_icon('docs', $text, 'moodle', array('class'=>'iconhelp'));
@@ -1505,8 +1509,8 @@ class core_renderer extends renderer_base {
         $url = new moodle_url(get_docs_url($path));
 
         $attributes = array('href'=>$url);
-        if (!empty($CFG->doctonewwindow)) {
-            $attributes['id'] = $this->add_action_handler(new popup_action('click', $url));
+        if (!empty($CFG->doctonewwindow) || $forcepopup) {
+            $attributes['class'] = 'helplinkpopup';
         }
 
         return html_writer::tag('a', $icon.$text, $attributes);
-- 
1.7.9.5


From 502821bbccbb6e3fb65b19549d0013336f9d56c7 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sat, 27 Oct 2012 00:34:37 +0000
Subject: [PATCH 855/903] Automatically generated installer lang files

---
 install/lang/fi/install.php    |    6 +++---
 install/lang/zh_tw/error.php   |    2 +-
 install/lang/zh_tw/install.php |   10 ++++++----
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/install/lang/fi/install.php b/install/lang/fi/install.php
index 57673d4..006fcb9 100644
--- a/install/lang/fi/install.php
+++ b/install/lang/fi/install.php
@@ -54,14 +54,14 @@ $string['memorylimithelp'] = '<p>PHP muistiraja palvelimellesi on tällä hetkel
 
 <p>Tämä saattaa aiheuttaa Moodlelle muistiongelmia myöhemmin, varsinkin jos sinulla on paljon mahdollisia moduuleita ja/tai paljon käyttäjiä.</p>
 
-<p>Suosittelemme, että valitset asetuksiksi PHP:n korkeimmalla mahdollisella raja-arvolla, esimerkiksi 16M.
+<p>Suosittelemme, että valitset asetuksiksi PHP:n korkeimmalla mahdollisella raja-arvolla, esimerkiksi 40M.
 On olemassa monia tapoja joilla voit yrittää tehdä tämän:</p>
 <ol>
 <li>Jos pystyt, uudelleenkäännä PHP <i>--enable-memory-limit</i>. :llä.
 Tämä sallii Moodlen asettaa muistirajan itse.</li>
-<li>Jos sinulla on pääsy php.ini tiedostoosi, voit muuttaa <b>memory_limit</b> asetuksen siellä johonkin kuten 16M. Jos sinulla ei ole pääsyoikeutta, voit kenties pyytää ylläpitäjää tekemään tämän puolestasi.</li>
+<li>Jos sinulla on pääsy php.ini tiedostoosi, voit muuttaa <b>memory_limit</b> asetuksen siellä johonkin kuten 40M. Jos sinulla ei ole pääsyoikeutta, voit kenties pyytää ylläpitäjää tekemään tämän puolestasi.</li>
 <li>Joillain PHP palvelimilla voit luoda a .htaccess tiedoston Moodle hakemistossa, sisältäen tämän rivin:
-<p><blockquote>php_value memory_limit 16M</blockquote></p>
+<p><blockquote>php_value memory_limit 40M</blockquote></p>
 <p>Kuitenkin, joillain palvelimilla tämä estää  <b>kaikkia</b> PHP sivuja toimimasta (näet virheet, kun katsot sivuja), joten sinun täytyy poistaa .htaccess tiedosto.</p></li>
 </ol>';
 $string['paths'] = 'Polut';
diff --git a/install/lang/zh_tw/error.php b/install/lang/zh_tw/error.php
index 0bedb5f..64144e6 100644
--- a/install/lang/zh_tw/error.php
+++ b/install/lang/zh_tw/error.php
@@ -44,5 +44,5 @@ $string['invalidmd5'] = '無效的 md5';
 $string['missingrequiredfield'] = '缺少部份必填欄位';
 $string['remotedownloaderror'] = '下載元件至伺服器失敗，檢查代理伺服器的設定、高度建議安裝PHP cURL，您必須手動下載<a href="{$a->url}">{$a->url}</a>，並且複製到伺服器"{$a->dest}" 解壓縮';
 $string['wrongdestpath'] = '錯誤的目的路徑。';
-$string['wrongsourcebase'] = '錯誤的來源網址基礎。';
+$string['wrongsourcebase'] = '錯誤的來源基礎網址。';
 $string['wrongzipfilename'] = '錯誤的 ZIP 檔名。';
diff --git a/install/lang/zh_tw/install.php b/install/lang/zh_tw/install.php
index 0b79132..32415de 100644
--- a/install/lang/zh_tw/install.php
+++ b/install/lang/zh_tw/install.php
@@ -36,10 +36,10 @@ $string['chooselanguagehead'] = '選擇一種語言';
 $string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。這語言將成為此網站預設的語言。稍後您可以根據需要重新選擇。';
 $string['clialreadyconfigured'] = '檔案 config.php  已經存在，若你要安裝這一網站，請使用dmin/cli/install_database.php';
 $string['clialreadyinstalled'] = '檔案 config.php  已經存在，若你要升級這一網站，請使用admin/cli/upgrade.php';
-$string['cliinstallheader'] = 'Moodle {$a} 指令行安裝程式';
+$string['cliinstallheader'] = 'Moodle {$a} 命令列安裝程式';
 $string['databasehost'] = '資料庫主機';
 $string['databasename'] = '資料庫名稱';
-$string['databasetypehead'] = '選擇資料庫磁碟機';
+$string['databasetypehead'] = '選擇資料庫裝置';
 $string['dataroot'] = '資料目錄';
 $string['datarootpermission'] = '資料目錄存取授權';
 $string['dbprefix'] = '資料表名稱的前置字元';
@@ -47,7 +47,7 @@ $string['dirroot'] = 'Moodle目錄';
 $string['environmenthead'] = '檢查您的環境中...';
 $string['environmentsub2'] = '每一個Moodle版本都有一些PHP版本的最低要求和一堆強制開啟的PHP擴展。在進行安裝或升級之前都需要作完整的環境檢查。<br />
 若你不知道要怎樣新的PHP版本或啟用PHP擴展，請聯絡伺服器管理員。';
-$string['errorsinenvironment'] = '環境檢查失敗';
+$string['errorsinenvironment'] = '環境檢查失敗!';
 $string['installation'] = '安裝';
 $string['langdownloaderror'] = '很不幸地，語言“{$a}”並未安裝。安裝過程將以英文繼續。';
 $string['memorylimithelp'] = '<p>PHP記憶體上限目前設定為{$a}。</p>
@@ -65,8 +65,10 @@ $string['pathserrcreatedataroot'] = '資料目錄 ({$a->dataroot})無法由這
 $string['pathshead'] = '確認路徑';
 $string['pathsrodataroot'] = '資料根目錄是無法寫入的';
 $string['pathsroparentdataroot'] = '上層目錄({$a->parent})是不可寫入的。安裝程式無法建立資料目錄({$a->dataroot})。';
+$string['pathssubadmindir'] = '有些網站主機使用/admin這個網址來瀏覽控制面版或其他功能。很不幸，這個設定和Moodle管理頁面的標準路徑產生衝突。這個問題可以解決，只需在您的安裝目錄中把admin更換名稱，然後把新名稱輸入到這裡。例如<em>moodleadmin</em>這麼做會改變Moodle中的管理連接。';
 $string['pathssubdataroot'] = '你需要有一個地方讓Moodle可以儲存上傳的檔案。這一目錄對於網頁伺服器用戶(通常是"nobody"或"apache")而言，應該是可讀的和<b>可寫的</b>。但是它必須不能經由網頁直接存取。若此目錄不存在，這安裝程式將會試著建立它。';
-$string['pathssubdirroot'] = 'Moodle安裝的完整目錄徑路';
+$string['pathssubdirroot'] = 'Moodle安裝的完整目錄路徑。';
+$string['pathssubwwwroot'] = '可以瀏覽到Moodle的完整網址。Moodle不支援透過多個網址瀏覽，如果您的往佔有多個公開網址，您必須把這個網址以外的網址都設定為永久重新導向。如果您的網站可以透過內部網址瀏覽，有可以透過這個公開網址瀏覽，那麼請設定DNS內部使網路使用者也能使用的空該網址。如果此網址不正確，請在瀏覽器中修改URL來重新安裝，並設定另一個網址。';
 $string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全';
 $string['pathswrongadmindir'] = '管理目錄不存在';
 $string['phpextension'] = '{$a} PHP擴展';
-- 
1.7.9.5


From c777ad2785201187705087a84211db33649303fb Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Sun, 28 Oct 2012 00:34:02 +0000
Subject: [PATCH 856/903] Automatically generated installer lang files

---
 install/lang/zh_tw/error.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install/lang/zh_tw/error.php b/install/lang/zh_tw/error.php
index 64144e6..28af033 100644
--- a/install/lang/zh_tw/error.php
+++ b/install/lang/zh_tw/error.php
@@ -40,7 +40,7 @@ $string['cannotsavezipfile'] = '無法儲存 ZIP 檔案。';
 $string['cannotunzipfile'] = '無法解壓縮檔案。';
 $string['componentisuptodate'] = '元件已經是最新的了。';
 $string['downloadedfilecheckfailed'] = '下載的檔案檢查失敗';
-$string['invalidmd5'] = '無效的 md5';
+$string['invalidmd5'] = '這檢查變項是錯的，再試一次。';
 $string['missingrequiredfield'] = '缺少部份必填欄位';
 $string['remotedownloaderror'] = '下載元件至伺服器失敗，檢查代理伺服器的設定、高度建議安裝PHP cURL，您必須手動下載<a href="{$a->url}">{$a->url}</a>，並且複製到伺服器"{$a->dest}" 解壓縮';
 $string['wrongdestpath'] = '錯誤的目的路徑。';
-- 
1.7.9.5


From 33407de5b691c579b0e6a8b0c53387cb60cfca9e Mon Sep 17 00:00:00 2001
From: Charles Fulton <mackensen@gmail.com>
Date: Wed, 17 Oct 2012 11:07:12 -0700
Subject: [PATCH 857/903] MDL-36105 grades: use consistent icon classs

---
 grade/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grade/lib.php b/grade/lib.php
index d7d3b5b..a1e634b 100644
--- a/grade/lib.php
+++ b/grade/lib.php
@@ -1503,7 +1503,7 @@ class grade_structure {
 
             $url->param('action', 'show');
 
-            $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'iconsmall')));
+            $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'smallicon')));
 
         } else {
             $url->param('action', 'hide');
-- 
1.7.9.5


From 41db2a5afc47e12cb1dc9157918201ad0aa476cb Mon Sep 17 00:00:00 2001
From: Michael Aherne <Michael Aherne>
Date: Wed, 17 Oct 2012 12:37:43 +0100
Subject: [PATCH 858/903] MDL-36101 auth_shibboleth Show appropriate error
 message for suspended accounts

---
 auth/shibboleth/index.php                   |    7 ++++---
 auth/shibboleth/lang/en/auth_shibboleth.php |    1 +
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/auth/shibboleth/index.php b/auth/shibboleth/index.php
index a1e4a1c..49b510f 100644
--- a/auth/shibboleth/index.php
+++ b/auth/shibboleth/index.php
@@ -38,9 +38,9 @@
 
     /// Check if the user has actually submitted login data to us
 
-        if ($shibbolethauth->user_login($frm->username, $frm->password)) {
+        if ($shibbolethauth->user_login($frm->username, $frm->password)
+                && $user = authenticate_user_login($frm->username, $frm->password)) {
 
-            $user = authenticate_user_login($frm->username, $frm->password);
             enrol_check_plugins($user);
             session_set_user($user);
 
@@ -84,7 +84,8 @@
         }
 
         else {
-            // For some weird reason the Shibboleth user couldn't be authenticated
+            // The Shibboleth user couldn't be mapped to a valid Moodle user
+            print_error('shib_invalid_account_error', 'auth_shibboleth');
         }
     }
 
diff --git a/auth/shibboleth/lang/en/auth_shibboleth.php b/auth/shibboleth/lang/en/auth_shibboleth.php
index ca0f251..aace9a1 100644
--- a/auth/shibboleth/lang/en/auth_shibboleth.php
+++ b/auth/shibboleth/lang/en/auth_shibboleth.php
@@ -51,6 +51,7 @@ $string['auth_shib_no_organizations_warning'] = 'If you want to use the integrat
 $string['auth_shib_only'] = 'Shibboleth only';
 $string['auth_shib_only_description'] = 'Check this option if a Shibboleth authentication shall be enforced';
 $string['auth_shib_username_description'] = 'Name of the webserver Shibboleth environment variable that shall be used as Moodle username';
+$string['shib_invalid_account_error'] = 'You seem to be Shibboleth authenticated but Moodle has no valid account for your username. Your account may not exist or it may have been suspended.';
 $string['shib_no_attributes_error'] = 'You seem to be Shibboleth authenticated but Moodle didn\'t receive any user attributes. Please check that your Identity Provider releases the necessary attributes ({$a}) to the Service Provider Moodle is running on or inform the webmaster of this server.';
 $string['shib_not_all_attributes_error'] = 'Moodle needs certain Shibboleth attributes which are not present in your case. The attributes are: {$a}<br />Please contact the webmaster of this server or your Identity Provider.';
 $string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="README.txt">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
-- 
1.7.9.5


From 272dfda3cfc421ca7ce001be1404f4b19ef451e2 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Wed, 10 Oct 2012 11:01:52 +0100
Subject: [PATCH 859/903] MDL-35959 Correct footer for M.core.dialogue

---
 .../notification/assets/skins/sam/notification.css |    2 +-
 enrol/yui/notification/notification.js             |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/enrol/yui/notification/assets/skins/sam/notification.css b/enrol/yui/notification/assets/skins/sam/notification.css
index f49a799..66cddda 100644
--- a/enrol/yui/notification/assets/skins/sam/notification.css
+++ b/enrol/yui/notification/assets/skins/sam/notification.css
@@ -6,7 +6,7 @@
 .moodle-dialogue-base .moodle-dialogue-hd {font-size:110%;color:inherit;font-weight:bold;text-align:left;padding:5px 6px;margin:0;border-bottom:1px solid #ccc;background-color:#f6f6f6;}
 .moodle-dialogue-base .closebutton {background-image:url(sprite.png);width:25px;height:15px;background-repeat:no-repeat;float:right;vertical-align:middle;display:inline-block;cursor:pointer;}
 .moodle-dialogue-base .moodle-dialogue-bd {padding:5px; overflow: auto;}
-.moodle-dialogue-base .moodle-dialogue-fd {}
+.moodle-dialogue-base .moodle-dialogue-ft {}
 
 .moodle-dialogue-confirm .confirmation-dialogue {text-align:center;}
 .moodle-dialogue-confirm .confirmation-message {margin:0.5em 1em;}
diff --git a/enrol/yui/notification/notification.js b/enrol/yui/notification/notification.js
index 8b91443..2ed9af0 100644
--- a/enrol/yui/notification/notification.js
+++ b/enrol/yui/notification/notification.js
@@ -21,7 +21,7 @@ var DIALOGUE_NAME = 'Moodle dialogue',
         HEADER : 'moodle-dialogue-hd',
         BODY : 'moodle-dialogue-bd',
         CONTENT : 'moodle-dialogue-content',
-        FOOTER : 'moodle-dialogue-fd',
+        FOOTER : 'moodle-dialogue-ft',
         HIDDEN : 'hidden',
         LIGHTBOX : 'moodle-dialogue-lightbox'
     };
@@ -35,7 +35,7 @@ var DIALOGUE = function(config) {
             .append(C('<div id="'+id+'" class="'+CSS.WRAP+'"></div>')
                 .append(C('<div class="'+CSS.HEADER+' yui3-widget-hd"></div>'))
                 .append(C('<div class="'+CSS.BODY+' yui3-widget-bd"></div>'))
-                .append(C('<div class="'+CSS.CONTENT+' yui3-widget-ft"></div>')));
+                .append(C('<div class="'+CSS.FOOTER+' yui3-widget-ft"></div>')));
     Y.one(document.body).append(config.notificationBase);
     config.srcNode =    '#'+id;
     config.width =      config.width || '400px';
-- 
1.7.9.5


From 3fd76b3de5be382b45efbf5ac8a60d9fc90ba11c Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Tue, 30 Oct 2012 11:43:09 +0000
Subject: [PATCH 860/903] MDL-31934 mod/forum: Added CSS fix to
 mod/forum/styles.css for unread forumposts also
 reversed a previous commit in theme/base/core.css.

---
 mod/forum/styles.css      |   13 +++++++++++++
 theme/base/style/core.css |   13 -------------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/mod/forum/styles.css b/mod/forum/styles.css
index fe824c4..0e544df 100644
--- a/mod/forum/styles.css
+++ b/mod/forum/styles.css
@@ -91,3 +91,16 @@
 
 /** Unknown Styles ??? */
 #email .unsubscribelink {margin-top:20px;}
+
+
+/* Forumpost unread
+-------------------------*/
+#page-mod-forum-view .unread,
+.forumpost.unread .row.header,
+.path-course-view .unread,
+span.unread {
+    background-color: #FFD;
+}
+.forumpost.unread .row.header {
+    border-bottom: 1px solid #DDD;
+}
\ No newline at end of file
diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 481df9b..4a5151b 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -994,16 +994,3 @@ sup {vertical-align: super;}
     -webkit-box-shadow: 0px 0px 10px 0px #CCCCCC;
     -moz-box-shadow: 0px 0px 10px 0px #CCCCCC;
 }
-
-/* Forumpost unread
--------------------------*/
-
-#page-mod-forum-view .unread,
-.forumpost.unread .row.header,
-.path-course-view .unread,
-span.unread {
-    background-color: #FFD;
-}
-.forumpost.unread .row.header {
-    border-bottom: 1px solid #DDD;
-}
-- 
1.7.9.5


From edf170c34194e21144df4eb5b598ddfcdc3daecd Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 31 Oct 2012 00:36:35 +0000
Subject: [PATCH 861/903] Automatically generated installer lang files

---
 install/lang/zh_tw/admin.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/install/lang/zh_tw/admin.php b/install/lang/zh_tw/admin.php
index 5eb6cc3..43f6dd0 100644
--- a/install/lang/zh_tw/admin.php
+++ b/install/lang/zh_tw/admin.php
@@ -34,8 +34,8 @@ $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 'y';
 $string['cliincorrectvalueerror'] = '錯誤，不正確的值 "{$a->value}" 用於 "{$a->option}"';
 $string['cliincorrectvalueretry'] = '不正確的值，請再試一次';
-$string['clitypevalue'] = '打入一值';
-$string['clitypevaluedefault'] = '打入一值，按Enter可使用預設值({$a})';
+$string['clitypevalue'] = '輸入值';
+$string['clitypevaluedefault'] = '輸入值，按Enter可使用預設值({$a})';
 $string['cliunknowoption'] = '不認得的選項：  {$a}
 請使用 --幫助 選項。';
 $string['cliyesnoprompt'] = '輸入y(是) 或n(否)';
-- 
1.7.9.5


From d0d6d5fc72a0fe40e786a2aa42047efe69f918d5 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 2 Oct 2012 14:28:55 +0800
Subject: [PATCH 862/903] MDL-28235 form: Help button popup close
 accessibility improved

AMOS BEGIN
 CPY [close,editor],[close,form]
AMOS END
---
 lang/en/form.php          |    1 +
 lib/javascript-static.js  |    8 ++++++--
 lib/outputrenderers.php   |    2 ++
 theme/base/style/core.css |    2 ++
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/lang/en/form.php b/lang/en/form.php
index d55667d..d926cd2 100644
--- a/lang/en/form.php
+++ b/lang/en/form.php
@@ -25,6 +25,7 @@
 
 $string['addfields'] = 'Add {$a} fields to form';
 $string['advancedelement'] = 'Advanced element';
+$string['close'] = 'Close';
 $string['day'] = 'Day';
 $string['display'] = 'Display';
 $string['err_alphanumeric'] = 'You must enter only letters or numbers here.';
diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 4189c37..158e5ff 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1388,16 +1388,19 @@ M.util.help_icon = {
         event.preventDefault();
         if (M.util.help_icon.instance === null) {
             var Y = M.util.help_icon.Y;
-            Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', function(Y) {
+            Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', 'escape', function(Y) {
                 var help_content_overlay = {
                     helplink : null,
                     overlay : null,
                     init : function() {
 
-                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img  src="'+M.util.image_url('t/delete', 'moodle')+'" /></a>');
+                        var strclose = Y.Escape.html(M.str.form.close);
+                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img src="'+M.util.image_url('t/delete', 'moodle')+'" alt="'+strclose+'" /></a>');
+                        var footerbtn = Y.Node.create('<button class="closebtn">'+strclose+'</button>');
                         // Create an overlay from markup
                         this.overlay = new Y.Overlay({
                             headerContent: closebtn,
+                            footerContent: footerbtn,
                             bodyContent: '',
                             id: 'helppopupbox',
                             width:'400px',
@@ -1407,6 +1410,7 @@ M.util.help_icon = {
                         this.overlay.render(Y.one(document.body));
 
                         closebtn.on('click', this.overlay.hide, this.overlay);
+                        footerbtn.on('click', this.overlay.hide, this.overlay);
 
                         var boundingBox = this.overlay.get("boundingBox");
 
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index dd03dc8..b49c69b 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -1733,6 +1733,7 @@ class core_renderer extends renderer_base {
         $output = html_writer::tag('a', $output, $attributes);
 
         $this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+        $this->page->requires->string_for_js('close', 'form');
 
         // and finally span
         return html_writer::tag('span', $output, array('class' => 'helplink'));
@@ -1798,6 +1799,7 @@ class core_renderer extends renderer_base {
         $output = html_writer::tag('a', $output, $attributes);
 
         $this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+        $this->page->requires->string_for_js('close', 'form');
 
         // and finally span
         return html_writer::tag('span', $output, array('class' => 'helplink'));
diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 4a5151b..ee93c4f 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -477,6 +477,8 @@ body.tag .managelink {padding: 5px;}
 #helppopupbox {background-color: #eee; border: 1px solid #848484;z-index: 10000 !important;}
 #helppopupbox .yui3-widget-hd {float:right;margin:3px 3px 0 0;}
 #helppopupbox .yui3-widget-bd {margin:0 1em 1em 1em;border-top:1px solid #eee;}
+#helppopupbox .yui3-widget-ft {text-align: center;}
+#helppopupbox .yui3-widget-ft .closebtn {margin:0 1em 1em 1em;}
 #helppopupbox .helpheading {font-size: 1em;}
 #helppopupbox .spinner {margin:1em;}
 
-- 
1.7.9.5


From b27daf9e736e9bc1a482f4e12017cbcbe82edc0a Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Tue, 2 Oct 2012 14:34:15 +0800
Subject: [PATCH 863/903] MDL-28235 form: Removed close icon of help icon
 popups

---
 lib/javascript-static.js |    6 ------
 1 file changed, 6 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 158e5ff..2b6cefd 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1395,11 +1395,9 @@ M.util.help_icon = {
                     init : function() {
 
                         var strclose = Y.Escape.html(M.str.form.close);
-                        var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img src="'+M.util.image_url('t/delete', 'moodle')+'" alt="'+strclose+'" /></a>');
                         var footerbtn = Y.Node.create('<button class="closebtn">'+strclose+'</button>');
                         // Create an overlay from markup
                         this.overlay = new Y.Overlay({
-                            headerContent: closebtn,
                             footerContent: footerbtn,
                             bodyContent: '',
                             id: 'helppopupbox',
@@ -1409,7 +1407,6 @@ M.util.help_icon = {
                         });
                         this.overlay.render(Y.one(document.body));
 
-                        closebtn.on('click', this.overlay.hide, this.overlay);
                         footerbtn.on('click', this.overlay.hide, this.overlay);
 
                         var boundingBox = this.overlay.get("boundingBox");
@@ -1426,9 +1423,6 @@ M.util.help_icon = {
                                 this.overlay.hide();
                             }
                         }, this);
-
-                        Y.on("key", this.close, closebtn , "down:13", this);
-                        closebtn.on('click', this.close, this);
                     },
 
                     close : function(e) {
-- 
1.7.9.5


From 9740e053f2806635404d3b1275166d56fd402ef6 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Wed, 31 Oct 2012 12:59:07 +0800
Subject: [PATCH 864/903] MDL-28235 form: Removed reference to unexisting
 close button in help popup

---
 lib/javascript-static.js |    2 --
 1 file changed, 2 deletions(-)

diff --git a/lib/javascript-static.js b/lib/javascript-static.js
index 2b6cefd..ba1651b 100644
--- a/lib/javascript-static.js
+++ b/lib/javascript-static.js
@@ -1462,8 +1462,6 @@ M.util.help_icon = {
 
                         Y.io(ajaxurl, cfg);
                         this.overlay.show();
-
-                        Y.one('#closehelpbox').focus();
                     },
 
                     display_callback : function(content) {
-- 
1.7.9.5


From 93efeb53529ce5797db81e92bcde5f86e81e33ab Mon Sep 17 00:00:00 2001
From: Adam Olley <adam.olley@netspot.com.au>
Date: Fri, 19 Oct 2012 13:43:30 +1030
Subject: [PATCH 865/903] MDL-36130: mod_assign: migrate logs when migrating
 from mod_assignment

---
 mod/assign/upgradelib.php |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mod/assign/upgradelib.php b/mod/assign/upgradelib.php
index 92d59a0..e9a7f0f 100644
--- a/mod/assign/upgradelib.php
+++ b/mod/assign/upgradelib.php
@@ -162,6 +162,11 @@ class assign_upgrade_manager {
             }
             $completiondone = true;
 
+            // Migrate log entries so we don't lose them.
+            $logparams = array('cmid' => $oldcoursemodule->id, 'course' => $oldcoursemodule->course);
+            $DB->set_field('log', 'module', 'assign', $logparams);
+            $DB->set_field('log', 'cmid', $newcoursemodule->id, $logparams);
+
 
             // copy all the submission data (and get plugins to do their bit)
             $oldsubmissions = $DB->get_records('assignment_submissions', array('assignment'=>$oldassignmentid));
@@ -260,6 +265,10 @@ class assign_upgrade_manager {
                     $DB->update_record('course_completion_criteria', $criteria);
                 }
             }
+            // Roll back the log changes
+            $logparams = array('cmid' => $newcoursemodule->id, 'course' => $newcoursemodule->course);
+            $DB->set_field('log', 'module', 'assignment', $logparams);
+            $DB->set_field('log', 'cmid', $oldcoursemodule->id, $logparams);
             // roll back the advanced grading update
             if ($gradingarea) {
                 foreach ($gradeidmap as $newgradeid => $oldsubmissionid) {
-- 
1.7.9.5


From b5b882df60bede68c7688e274847902a30267dd1 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 31 Oct 2012 19:30:08 +0100
Subject: [PATCH 866/903] MDL-36304 - Left align "marked out of" in RTL Q
 preview

Credit goes to Nadav Kavalerchik for fixing it @ MDL-36033
---
 mod/quiz/styles.css |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/quiz/styles.css b/mod/quiz/styles.css
index 6efbdbc..23fe7d5 100644
--- a/mod/quiz/styles.css
+++ b/mod/quiz/styles.css
@@ -415,5 +415,6 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl div.quizcontents {clear: right;float: right;}
 #page-mod-quiz-edit.dir-rtl .questionbankwindow.block {float: left;}
 #page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
+.path-question.dir-rtl input[name="maxmark"],
 .path-question-type.dir-rtl input[name="defaultmark"],
 #page-mod-quiz-edit.dir-rtl div.points input {direction: ltr;text-align: left;}
-- 
1.7.9.5


From f1c3b5b3b39af05796b7eef3419cc6e6dfc42c88 Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Thu, 1 Nov 2012 00:36:39 +0000
Subject: [PATCH 867/903] Automatically generated installer lang files

---
 install/lang/en_kids/langconfig.php |   33 +++++++++++++++++++++++++++++++++
 install/lang/ja_kids/langconfig.php |   35 +++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
 create mode 100644 install/lang/en_kids/langconfig.php
 create mode 100644 install/lang/ja_kids/langconfig.php

diff --git a/install/lang/en_kids/langconfig.php b/install/lang/en_kids/langconfig.php
new file mode 100644
index 0000000..7a195a4
--- /dev/null
+++ b/install/lang/en_kids/langconfig.php
@@ -0,0 +1,33 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'English for kids';
diff --git a/install/lang/ja_kids/langconfig.php b/install/lang/ja_kids/langconfig.php
new file mode 100644
index 0000000..6eb3957
--- /dev/null
+++ b/install/lang/ja_kids/langconfig.php
@@ -0,0 +1,35 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'ja';
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = '日本語 小学生';
-- 
1.7.9.5


From 391f8b395a3f02a6ee25b09fbeb1c95deb04e702 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Thu, 1 Nov 2012 00:28:59 +0100
Subject: [PATCH 868/903] MDL-36315 backup: reduce the DST tests
 failing-window

This reduces the period of time that some of the unit tests
for calculate_next_automated_backup() are failing right now
(from 1week to just some hours around the DST changes).

Note it's not the final solution because they will still fail
when New_York or Brussels DST changes are about to happen, but
to get this completely fixed we'll need to wait to switch from
current custom TZ/DST support to PHP built-in one.
---
 backup/util/helper/tests/cronhelper_test.php |   26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/backup/util/helper/tests/cronhelper_test.php b/backup/util/helper/tests/cronhelper_test.php
index 7afd1be..d0e92af 100644
--- a/backup/util/helper/tests/cronhelper_test.php
+++ b/backup/util/helper/tests/cronhelper_test.php
@@ -281,9 +281,13 @@ class backup_cron_helper_testcase extends advanced_testcase {
         $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
 
         // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+        // Warning: Some of these tests will fail if executed "around"
+        // 'Europe/Brussels' DST changes (last Sunday in March and
+        // last Sunday in October right now - 2012). Once Moodle
+        // moves to PHP TZ support this could be fixed properly.
         date_default_timezone_set('Europe/Brussels');
         $now = strtotime('18:00:00');
-        $dst = date('I');
+        $dst = date('I', $now);
 
         $timezone = -10.0; // 7am for the user.
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
@@ -321,9 +325,13 @@ class backup_cron_helper_testcase extends advanced_testcase {
         $this->assertEquals($expected, date('w-H:i', $next));
 
         // The big apple! (UTC-5 / UTC-4 DST).
+        // Warning: Some of these tests will fail if executed "around"
+        // 'America/New_York' DST changes (2nd Sunday in March and
+        // 1st Sunday in November right now - 2012). Once Moodle
+        // moves to PHP TZ support this could be fixed properly.
         date_default_timezone_set('America/New_York');
         $now = strtotime('18:00:00');
-        $dst = date('I');
+        $dst = date('I', $now);
 
         $timezone = -10.0; // 1pm for the user.
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
@@ -365,9 +373,14 @@ class backup_cron_helper_testcase extends advanced_testcase {
         set_config('backup_auto_hour', '20', 'backup');
         set_config('backup_auto_minute', '00', 'backup');
 
+        // Note: These tests should not fail because they are "unnafected"
+        // by DST changes, as far as execution always happens on Monday and
+        // Saturday and those week days are not, right now, the ones rulez
+        // to peform the DST changes (Sunday is). This may change if rules
+        // are modified in the future.
         date_default_timezone_set('Europe/Brussels');
         $now = strtotime('next Monday 18:00:00');
-        $dst = date('I');
+        $dst = date('I', $now);
 
         $timezone = -12.0;  // 1pm for the user.
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
@@ -404,9 +417,14 @@ class backup_cron_helper_testcase extends advanced_testcase {
         set_config('backup_auto_hour', '02', 'backup');
         set_config('backup_auto_minute', '00', 'backup');
 
+        // Note: These tests should not fail because they are "unnafected"
+        // by DST changes, as far as execution always happens on Monday and
+        // Saturday and those week days are not, right now, the ones rulez
+        // to peform the DST changes (Sunday is). This may change if rules
+        // are modified in the future.
         date_default_timezone_set('America/New_York');
         $now = strtotime('next Monday 04:00:00');
-        $dst = date('I');
+        $dst = date('I', $now);
 
         $timezone = -12.0;  // 8pm for the user.
         $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
-- 
1.7.9.5


From d402e05ba7bdd88482e58aeab5225329855db891 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Thu, 1 Nov 2012 14:16:33 +0800
Subject: [PATCH 869/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 6ccbfde..083bdd1 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.09;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.10;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121018)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121101)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 1139dff6ef1e6c55c3b8394feede20bef621df51 Mon Sep 17 00:00:00 2001
From: Mark Nelson <markn@moodle.com>
Date: Tue, 30 Oct 2012 15:24:09 +0800
Subject: [PATCH 870/903] MDL-36271 feedback: Fixed variable typo

---
 mod/feedback/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/feedback/lib.php b/mod/feedback/lib.php
index 8c6dd59..e4a0b8a 100644
--- a/mod/feedback/lib.php
+++ b/mod/feedback/lib.php
@@ -400,7 +400,7 @@ function feedback_get_recent_mod_activity(&$activities, &$index,
 
     $sql .= " WHERE fc.timemodified > ? AND fk.id = ? ";
     $sqlargs[] = $timemodified;
-    $sqlargs[] = $cm->instace;
+    $sqlargs[] = $cm->instance;
 
     if ($userid) {
         $sql .= " AND u.id = ? ";
-- 
1.7.9.5


From 37ceb6cbed3eb68671a504649cd0d8a9b48788c8 Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Fri, 26 Oct 2012 17:33:57 +0800
Subject: [PATCH 871/903] MDL-36092 Course/AJAX Ensure that dropdown resource
 pickers are shown when JS is disabled

---
 course/lib.php |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/course/lib.php b/course/lib.php
index 51b4b0c..7c05094 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1876,8 +1876,9 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
             $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown'));
             $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser'));
         } else {
-            $output = html_writer::tag('div', $output, array('class' => 'visibleifjs addresourcedropdown'));
-            $modchooser = html_writer::tag('div', $modchooser, array('class' => 'hiddenifjs addresourcemodchooser'));
+            // If the module chooser is disabled, we need to ensure that the dropdowns are shown even if javascript is disabled
+            $output = html_writer::tag('div', $output, array('class' => 'show addresourcedropdown'));
+            $modchooser = html_writer::tag('div', $modchooser, array('class' => 'hide addresourcemodchooser'));
         }
         $output = $modchooser . $output;
     }
-- 
1.7.9.5


From 152dbe5d5260bd2ec3a5333775989051c3441e1b Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 29 Sep 2012 12:33:21 +0200
Subject: [PATCH 872/903] MDL-35512 - Two left pointing arrows appear after
 clicking "left indent activity/resource" arrow,
 when in RTL mode

---
 course/yui/toolboxes/toolboxes.js |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
index db7dae8..b3eb066 100644
--- a/course/yui/toolboxes/toolboxes.js
+++ b/course/yui/toolboxes/toolboxes.js
@@ -459,10 +459,16 @@ YUI.add('moodle-course-toolboxes', function(Y) {
          */
         add_moveleft : function(target) {
             var left_string = M.util.get_string('moveleft', 'moodle');
+            var moveimage = 't/left'; // ltr mode
+            if ( Y.one(document.body).hasClass('dir-rtl') ) {
+                moveimage = 't/right';
+            } else {
+                moveimage = 't/left';
+            }
             var newicon = Y.Node.create('<img />')
                 .addClass(CSS.GENERICICONCLASS)
                 .setAttrs({
-                    'src'   : M.util.image_url('t/left', 'moodle'),
+                    'src'   : M.util.image_url(moveimage, 'moodle'),
                     'alt'   : left_string
                 });
             var moveright = target.one(CSS.MOVERIGHT);
-- 
1.7.9.5


From c4b521116facb89fa119f226cdf70ca03f55cad3 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Tue, 16 Oct 2012 10:19:31 +0200
Subject: [PATCH 873/903] MDL-36069 - Right align TEXTAREA "Format selector"
 listbox, when in RTL mode (theme/standard)

---
 theme/base/style/core.css |    1 -
 1 file changed, 1 deletion(-)

diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index 8748930..c19030e 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -667,7 +667,6 @@ body.tag .managelink {padding: 5px;}
 .dir-rtl .mod-indent-15,
 .dir-rtl .mod-indent-huge {margin-right:300px;margin-left:0;}
 
-.dir-rtl .felement.feditor select {margin-right:18.75%;margin-left:auto;}
 .dir-rtl .mform .fitem .felement {margin-right: 16%;margin-left:auto;text-align: right;}
 .dir-rtl .mform .fitem .felement input[name=email],
 .dir-rtl .mform .fitem .felement input[name=email2],
-- 
1.7.9.5


From 561bd396c19239917af65f2415b893dbd3d92209 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Thu, 4 Oct 2012 16:20:43 +1300
Subject: [PATCH 874/903] MDL-34527 forum: Fixed up a couple of SQL queries
 causing issues in Oracle.

---
 mod/forum/lib.php |   48 +++++++++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 7cfb638..5c55e0d 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -8032,29 +8032,37 @@ function forum_get_courses_user_posted_in($user, $discussionsonly = false, $incl
 function forum_get_forums_user_posted_in($user, array $courseids = null, $discussionsonly = false, $limitfrom = null, $limitnum = null) {
     global $DB;
 
-    $where = array("m.name = 'forum'");
-    $params = array();
     if (!is_null($courseids)) {
         list($coursewhere, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED, 'courseid');
-        $where[] = 'f.course '.$coursewhere;
-    }
-    if (!$discussionsonly) {
-        $joinsql = 'JOIN {forum_discussions} fd ON fd.forum = f.id
-                    JOIN {forum_posts} fp ON fp.discussion = fd.id';
-        $where[] = 'fp.userid = :userid';
+        $coursewhere = ' AND f.course '.$coursewhere;
     } else {
-        $joinsql = 'JOIN {forum_discussions} fd ON fd.forum = f.id';
-        $where[] = 'fd.userid = :userid';
+        $coursewhere = '';
+        $params = array();
     }
     $params['userid'] = $user->id;
-    $wheresql = join(' AND ', $where);
+    $params['forum'] = 'forum';
 
-    $sql = "SELECT DISTINCT f.*, cm.id AS cmid
-            FROM {forum} f
-            JOIN {course_modules} cm ON cm.instance = f.id
-            JOIN {modules} m ON m.id = cm.module
-            $joinsql
-            WHERE $wheresql";
+    if ($discussionsonly) {
+        $join = 'JOIN {forum_discussions} ff ON ff.forum = f.id';
+    } else {
+        $join = 'JOIN {forum_discussions} fd ON fd.forum = f.id
+                 JOIN {forum_posts} ff ON ff.discussion = fd.id';
+    }
+
+    $sql = "SELECT f.*, cm.id AS cmid
+              FROM {forum} f
+              JOIN {course_modules} cm ON cm.instance = f.id
+              JOIN {modules} m ON m.id = cm.module
+              JOIN (
+                  SELECT f.id
+                    FROM {forum} f
+                    {$join}
+                   WHERE ff.userid = :userid
+                GROUP BY f.id
+                   ) j ON j.id = f.id
+             WHERE m.name = :forum
+                 {$coursewhere}";
+    
     $courseforums = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
     return $courseforums;
 }
@@ -8309,8 +8317,10 @@ function forum_get_posts_by_user($user, array $courses, $musthaveaccess = false,
         $forumsearchwhere[] = "(d.forum $fullidsql)";
     }
 
-    // Prepare SQL to both count and search
-    $userfields = user_picture::fields('u', null, 'userid');
+    // Prepare SQL to both count and search.
+    // We alias user.id to useridx because we forum_posts already has a userid field and not aliasing this would break
+    // oracle and mssql.
+    $userfields = user_picture::fields('u', null, 'useridx');
     $countsql = 'SELECT COUNT(*) ';
     $selectsql = 'SELECT p.*, d.forum, d.name AS discussionname, '.$userfields.' ';
     $wheresql = implode(" OR ", $forumsearchwhere);
-- 
1.7.9.5


From 4aaac325f204100c3dbbfd60cde436acd794afd9 Mon Sep 17 00:00:00 2001
From: Mark Nelson <markn@moodle.com>
Date: Fri, 2 Nov 2012 15:32:36 +0800
Subject: [PATCH 875/903] MDL-35349 paypal: Fixing return page so that it now
 declares page context

---
 enrol/paypal/return.php |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/enrol/paypal/return.php b/enrol/paypal/return.php
index a8a6557..d65b83d 100644
--- a/enrol/paypal/return.php
+++ b/enrol/paypal/return.php
@@ -35,10 +35,11 @@ if (!$course = $DB->get_record("course", array("id"=>$id))) {
 }
 
 $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
+$PAGE->set_context($context);
 
 require_login();
 
-if ($SESSION->wantsurl) {
+if (!empty($SESSION->wantsurl)) {
     $destination = $SESSION->wantsurl;
     unset($SESSION->wantsurl);
 } else {
-- 
1.7.9.5


From 917cea604caf663ea6e796e732e01b63a7cfe133 Mon Sep 17 00:00:00 2001
From: Tim Hunt <T.J.Hunt@open.ac.uk>
Date: Sat, 3 Nov 2012 18:36:13 +1100
Subject: [PATCH 876/903] MDL-36347 quiz: formchangechecker should not
 obstruct auto-submit.

When the quiz time limit runs out, the quiz should be submitted
automatically, withouth formchangechecker popping up a dialogue.
---
 mod/quiz/module.js |    1 +
 1 file changed, 1 insertion(+)

diff --git a/mod/quiz/module.js b/mod/quiz/module.js
index ce0d359..70332fa 100644
--- a/mod/quiz/module.js
+++ b/mod/quiz/module.js
@@ -101,6 +101,7 @@ M.mod_quiz.timer = {
             if (form.one('input[name=finishattempt]')) {
                 form.one('input[name=finishattempt]').set('value', 0);
             }
+            M.core_formchangechecker.set_form_submitted();
             form.submit();
             return;
         }
-- 
1.7.9.5


From f9e009a744a642f2a4908169a3b4474517e19145 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Mon, 5 Nov 2012 16:29:28 +1300
Subject: [PATCH 877/903] MDL-21625 question: Fixed phpdocs

---
 question/editlib.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/question/editlib.php b/question/editlib.php
index e4f811e..5b9c894 100644
--- a/question/editlib.php
+++ b/question/editlib.php
@@ -317,8 +317,8 @@ abstract class question_bank_column_base {
     /**
      * Output the closing column tag
      *
-     * @param type $question
-     * @param type $rowclasses
+     * @param object $question
+     * @param string $rowclasses
      */
     protected function display_end($question, $rowclasses) {
         $tag = 'td';
-- 
1.7.9.5


From a7e956b40350f2afe91f7ec00ad9dd6972cc13b6 Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Mon, 5 Nov 2012 13:27:35 +0800
Subject: [PATCH 878/903] MDL-34527 - fix trailing whitespace

---
 mod/forum/lib.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mod/forum/lib.php b/mod/forum/lib.php
index 5c55e0d..a706571 100644
--- a/mod/forum/lib.php
+++ b/mod/forum/lib.php
@@ -8062,7 +8062,7 @@ function forum_get_forums_user_posted_in($user, array $courseids = null, $discus
                    ) j ON j.id = f.id
              WHERE m.name = :forum
                  {$coursewhere}";
-    
+
     $courseforums = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
     return $courseforums;
 }
-- 
1.7.9.5


From 89fbf2e874d01c4912e624bc69895fff9282ef81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20S=CC=8Ckoda?= <commits@skodak.org>
Date: Sat, 15 Sep 2012 20:54:40 +0200
Subject: [PATCH 879/903] MDL-35381 limit teachers to do permissions checks of
 enrolled users only

---
 admin/roles/check.php |   15 ++----
 admin/roles/lib.php   |  128 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+), 10 deletions(-)

diff --git a/admin/roles/check.php b/admin/roles/check.php
index 470159e..d3917b0 100644
--- a/admin/roles/check.php
+++ b/admin/roles/check.php
@@ -59,16 +59,11 @@ $courseid = $course->id;
 $contextname = print_context_name($context);
 
 // Get the user_selector we will need.
-// Teachers within a course just get to see the same list of people they can
-// assign roles to. Admins (people with moodle/role:manage) can run this report for any user.
-$options = array('context' => $context, 'roleid' => 0);
-if (has_capability('moodle/role:manage', $context)) {
-    $userselector = new potential_assignees_course_and_above('reportuser', $options);
-} else {
-    $userselector = roles_get_potential_user_selector($context, 'reportuser', $options);
-}
-$userselector->set_multiselect(false);
-$userselector->set_rows(10);
+// Teachers within a course just get to see the same list of enrolled users.
+// Admins (people with moodle/role:manage) can run this report for any user.
+$options = array('accesscontext' => $context);
+$userselector = new role_check_users_selector('reportuser', $options);
+$userselector->set_rows(20);
 
 // Work out an appropriate page title.
 $title = get_string('checkpermissionsin', 'role', $contextname);
diff --git a/admin/roles/lib.php b/admin/roles/lib.php
index 93703c8..c201d35 100644
--- a/admin/roles/lib.php
+++ b/admin/roles/lib.php
@@ -1077,6 +1077,134 @@ class potential_assignees_below_course extends role_assign_user_selector_base {
 }
 
 /**
+ * User selector subclass for the selection of users in the check permissions page.
+ *
+ * @copyright 2012 Petr Skoda {@link http://skodak.org}
+ */
+class role_check_users_selector extends user_selector_base {
+    const MAX_ENROLLED_PER_PAGE = 100;
+    const MAX_POTENTIAL_PER_PAGE = 100;
+
+    /** @var bool limit listing of users to enrolled only */
+    var $onlyenrolled;
+
+    /**
+     * Constructor.
+     *
+     * @param string $name the control name/id for use in the HTML.
+     * @param array $options other options needed to construct this selector.
+     * You must be able to clone a userselector by doing new get_class($us)($us->get_name(), $us->get_options());
+     */
+    public function __construct($name, $options) {
+        if (!isset($options['multiselect'])) {
+            $options['multiselect'] = false;
+        }
+        parent::__construct($name, $options);
+
+        $coursecontext = $this->accesscontext->get_course_context(false);
+        if ($coursecontext and $coursecontext->id != SITEID and !has_capability('moodle/role:manage', $coursecontext)) {
+            // Prevent normal teachers from looking up all users.
+            $this->onlyenrolled = true;
+        } else {
+            $this->onlyenrolled = false;
+        }
+    }
+
+    public function find_users($search) {
+        global $DB;
+
+        list($wherecondition, $params) = $this->search_sql($search, 'u');
+
+        $fields      = 'SELECT ' . $this->required_fields_sql('u');
+        $countfields = 'SELECT COUNT(1)';
+
+        $coursecontext = $this->accesscontext->get_course_context(false);
+
+        if ($coursecontext and $coursecontext != SITEID) {
+            $sql1 = " FROM {user} u
+                      JOIN {user_enrolments} ue ON (ue.userid = u.id)
+                      JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid1)
+                     WHERE $wherecondition";
+            $params['courseid1'] = $coursecontext->instanceid;
+
+            if ($this->onlyenrolled) {
+                $sql2 = null;
+            } else {
+                $sql2 = " FROM {user} u
+                     LEFT JOIN ({user_enrolments} ue
+                                JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid2)) ON (ue.userid = u.id)
+                         WHERE $wherecondition
+                               AND ue.id IS NULL";
+                $params['courseid2'] = $coursecontext->instanceid;
+            }
+
+        } else {
+            if ($this->onlyenrolled) {
+                // Bad luck, current user may not view only enrolled users.
+                return array();
+            }
+            $sql1 = null;
+            $sql2 = " FROM {user} u
+                     WHERE $wherecondition";
+        }
+
+        $order = " ORDER BY lastname ASC, firstname ASC";
+
+        $params['contextid'] = $this->accesscontext->id;
+
+        $result = array();
+
+        if ($search) {
+            $groupname1 = get_string('enrolledusersmatching', 'enrol', $search);
+            $groupname2 = get_string('potusersmatching', 'role', $search);
+        } else {
+            $groupname1 = get_string('enrolledusers', 'enrol');
+            $groupname2 = get_string('potusers', 'role');
+        }
+
+        if ($sql1) {
+            $enrolleduserscount = $DB->count_records_sql($countfields . $sql1, $params);
+            if (!$this->is_validating() and $enrolleduserscount > $this::MAX_ENROLLED_PER_PAGE) {
+                $result[$groupname1] = array();
+                $toomany = $this->too_many_results($search, $enrolleduserscount);
+                $result[implode(' - ', array_keys($toomany))] = array();
+
+            } else {
+                $enrolledusers = $DB->get_records_sql($fields . $sql1 . $order, $params);
+                if ($enrolledusers) {
+                    $result[$groupname1] = $enrolledusers;
+                }
+            }
+            if ($sql2) {
+                $result[''] = array();
+            }
+        }
+        if ($sql2) {
+            $otheruserscount = $DB->count_records_sql($countfields . $sql2, $params);
+            if (!$this->is_validating() and $otheruserscount > $this::MAX_POTENTIAL_PER_PAGE) {
+                $result[$groupname2] = array();
+                $toomany = $this->too_many_results($search, $otheruserscount);
+                $result[implode(' - ', array_keys($toomany))] = array();
+            } else {
+                $otherusers = $DB->get_records_sql($fields . $sql2 . $order, $params);
+                if ($otherusers) {
+                    $result[$groupname2] = $otherusers;
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    protected function get_options() {
+        global $CFG;
+        $options = parent::get_options();
+        $options['file'] = $CFG->admin . '/roles/lib.php';
+        return $options;
+    }
+}
+
+/**
  * User selector subclass for the list of potential users on the assign roles page,
  * when we are assigning in a context at or above the course level. In this case we
  * show all the users in the system who do not already have the role.
-- 
1.7.9.5


From e3ac1261618842be3465551cf4960cd5b5e31fd6 Mon Sep 17 00:00:00 2001
From: Sam Hemelryk <sam@moodle.com>
Date: Tue, 6 Nov 2012 14:01:14 +1300
Subject: [PATCH 880/903] MDL-36379 user_view: fixed issue with page layout
 when editing was on

---
 user/view.php |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/user/view.php b/user/view.php
index 68d36ac..83792d4 100644
--- a/user/view.php
+++ b/user/view.php
@@ -148,9 +148,12 @@ if ($currentuser) {
     }
 }
 
+$PAGE->set_title("$course->fullname: $strpersonalprofile: $fullname");
+$PAGE->set_heading($course->fullname);
+$PAGE->set_pagelayout('standard');
 
-/// We've established they can see the user's name at least, so what about the rest?
-
+// Locate the users settings in the settings navigation and force it open.
+// This MUST be done after we've set up the page as it is going to cause theme and output to initialise.
 if (!$currentuser) {
     $PAGE->navigation->extend_for_user($user);
     if ($node = $PAGE->settingsnav->get('userviewingsettings'.$user->id)) {
@@ -163,9 +166,6 @@ if ($node = $PAGE->settingsnav->get('courseadmin')) {
     $node->forceopen = false;
 }
 
-$PAGE->set_title("$course->fullname: $strpersonalprofile: $fullname");
-$PAGE->set_heading($course->fullname);
-$PAGE->set_pagelayout('standard');
 echo $OUTPUT->header();
 
 echo '<div class="userprofile">';
-- 
1.7.9.5


From c43e6006e7a873569746514bac9cacb0bc0d4d1b Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Tue, 6 Nov 2012 14:36:29 +1300
Subject: [PATCH 881/903] MDL-36346 - YUI2 SWF vulnerability

---
 lib/yui/2.9.0/build/charts/assets/charts.swf     |  Bin 81764 -> 81321 bytes
 lib/yui/2.9.0/build/uploader/assets/uploader.swf |  Bin 7175 -> 7117 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/lib/yui/2.9.0/build/charts/assets/charts.swf b/lib/yui/2.9.0/build/charts/assets/charts.swf
index 740b53126e7947751023b3b53b76d7f527e0d3f8..2dfc91874f7d8b7dcd903bc3623a20c3c587e972 100644
GIT binary patch
literal 81321
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
G5NsyKeI#lC

literal 81764
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

diff --git a/lib/yui/2.9.0/build/uploader/assets/uploader.swf b/lib/yui/2.9.0/build/uploader/assets/uploader.swf
index 389505d974021086c6a10822ede37b1cce60c2e6..dbf1fc78f2f1995ed139b974aeb31163953082ee 100644
GIT binary patch
literal 7117
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
D)*bjB

literal 7175
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
J`Csryt;pe={WJgo

-- 
1.7.9.5


From 77283f1812f125b31caff9cf4713f4fb6be8fa66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?David=20Mudr=C3=A1k?= <david@moodle.com>
Date: Tue, 30 Oct 2012 12:00:03 +0100
Subject: [PATCH 882/903] MDL-36266 Improve update notification message
 subject

---
 lang/en/admin.php |    2 +-
 lib/pluginlib.php |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lang/en/admin.php b/lang/en/admin.php
index 919a7a9..5f47b26 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -997,7 +997,7 @@ $string['updateavailable_version'] = 'Version {$a}';
 $string['updateavailablenot'] = 'Your Moodle code is up-to-date!';
 $string['updatenotifications'] = 'Update notifications';
 $string['updatenotificationfooter'] = 'Your Moodle site {$a->siteurl} is configured to automatically check for available updates. You are receiving this message as the administrator of the site. You can disable automatic checks for available updates in the Site administration section of the Settings block. You can customize the delivery of this message via your personal Messaging setting in the My profile settings section.';
-$string['updatenotificationsubject'] = 'There are available updates for your Moodle site';
+$string['updatenotificationsubject'] = 'Moodle updates are available ({$a->siteurl})';
 $string['updateautocheck'] = 'Automatically check for available updates';
 $string['updateautocheck_desc'] = 'If enabled, your site will automatically check for available updates for both Moodle code and all additional plugins. If there is a new update available, a notification will be sent to site admins.';
 $string['updateminmaturity'] = 'Required code maturity';
diff --git a/lib/pluginlib.php b/lib/pluginlib.php
index 470fa88..5c8417e 100644
--- a/lib/pluginlib.php
+++ b/lib/pluginlib.php
@@ -1302,7 +1302,7 @@ class available_update_checker {
             $message->name              = 'availableupdate';
             $message->userfrom          = $mainadmin;
             $message->userto            = $admin;
-            $message->subject           = get_string('updatenotifications', 'core_admin');
+            $message->subject           = get_string('updatenotificationsubject', 'core_admin', array('siteurl' => $CFG->wwwroot));
             $message->fullmessage       = $text;
             $message->fullmessageformat = FORMAT_PLAIN;
             $message->fullmessagehtml   = $html;
-- 
1.7.9.5


From 3a8714c3c62ceddbe5ede0e97c212c50d0b951bc Mon Sep 17 00:00:00 2001
From: Andrew Robert Nicols <andrew.nicols@luns.net.uk>
Date: Tue, 6 Nov 2012 10:16:28 +0000
Subject: [PATCH 883/903] MDL-36023 AJAX Fix reference to chooserdiaogue
 jumplink

---
 course/yui/modchooser/modchooser.js |    2 --
 1 file changed, 2 deletions(-)

diff --git a/course/yui/modchooser/modchooser.js b/course/yui/modchooser/modchooser.js
index f87a5ec..28b9081 100644
--- a/course/yui/modchooser/modchooser.js
+++ b/course/yui/modchooser/modchooser.js
@@ -28,8 +28,6 @@ YUI.add('moodle-course-modchooser', function(Y) {
             };
             this.setup_chooser_dialogue(dialogue, header, params);
 
-            this.jumplink = this.container.one('#jump');
-
             // Initialize existing sections and register for dynamically created sections
             this.setup_for_section();
             M.course.coursebase.register_module(this);
-- 
1.7.9.5


From 84fad57f1cd011983c1f3a1aa3fef84874df1535 Mon Sep 17 00:00:00 2001
From: Andrew Davis <andrew@moodle.com>
Date: Tue, 9 Oct 2012 11:22:54 +0800
Subject: [PATCH 884/903] MDL-35762 core_grade: altered the code that
 determines whether an activity is visible on the
 user report

---
 grade/report/user/lib.php |   12 ++++---
 lib/modinfolib.php        |   79 ++++++++++++++++++++++++++++++++++-----------
 2 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php
index cd2e951..1058c07 100644
--- a/grade/report/user/lib.php
+++ b/grade/report/user/lib.php
@@ -348,13 +348,17 @@ class grade_report_user extends grade_report {
                     ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) {
                 $hide = true;
             } else if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
-                // The grade object can be marked visible but still be hidden if "enablegroupmembersonly"
-                // is on and it's an activity assigned to a grouping the user is not in.
+                // The grade object can be marked visible but still be hidden if...
+                //  1) "enablegroupmembersonly" is on and the activity is assigned to a grouping the user is not in.
+                //  2) the student cannot see the activity due to conditional access and its set to be hidden entirely.
                 $instances = $this->gtree->modinfo->get_instances_of($grade_object->itemmodule);
                 if (!empty($instances[$grade_object->iteminstance])) {
                     $cm = $instances[$grade_object->iteminstance];
-                    if ($cm->is_user_access_restricted_by_group()) {
-                        $hide = true;
+                    if (!$cm->uservisible) {
+                        // Further checks are required to determine whether the activity is entirely hidden or just greyed out.
+                        if ($cm->is_user_access_restricted_by_group() || $cm->is_user_access_restricted_by_conditional_access()) {
+                            $hide = true;
+                        }
                     }
                 }
             }
diff --git a/lib/modinfolib.php b/lib/modinfolib.php
index c787896..5b8d3ef 100644
--- a/lib/modinfolib.php
+++ b/lib/modinfolib.php
@@ -1077,8 +1077,12 @@ class cm_info extends stdClass {
     }
 
     /**
-     * Works out whether activity is visible *for current user* - if this is false, they
-     * aren't allowed to access it.
+     * Works out whether activity is available to the current user
+     *
+     * If the activity is unavailable, additional checks are required to determine if its hidden or greyed out
+     *
+     * @see is_user_access_restricted_by_group()
+     * @see is_user_access_restricted_by_conditional_access()
      * @return void
      */
     private function update_user_visible() {
@@ -1086,39 +1090,76 @@ class cm_info extends stdClass {
         $modcontext = get_context_instance(CONTEXT_MODULE, $this->id);
         $userid = $this->modinfo->get_user_id();
         $this->uservisible = true;
-        // Check visibility/availability conditions.
+
+        // If the user cannot access the activity set the uservisible flag to false.
+        // Additional checks are required to determine whether the activity is entirely hidden or just greyed out.
         if ((!$this->visible or !$this->available) and
                 !has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
-            // If the activity is hidden or unavailable, and you don't have viewhiddenactivities,
-            // set it so that user can't see or access it.
+
             $this->uservisible = false;
         }
-        // Check group membership. The grouping option makes the activity
-        // completely invisible as it does not apply to the user at all.
+
+        // Check group membership.
         if ($this->is_user_access_restricted_by_group()) {
-            $this->uservisible = false;
-            // Ensure activity is completely hidden from user.
+
+             $this->uservisible = false;
+            // Ensure activity is completely hidden from the user.
             $this->showavailability = 0;
         }
     }
 
     /**
-     * Checks whether the module group settings restrict the user access.
-     * @return bool true if the user access is restricted
+     * Checks whether the module's group settings restrict the current user's access
+     *
+     * @return bool True if the user access is restricted
      */
     public function is_user_access_restricted_by_group() {
         global $CFG;
+
+        if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)) {
+            $modcontext = context_module::instance($this->id);
+            $userid = $this->modinfo->get_user_id();
+            if (!has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
+                // If the activity has 'group members only' and you don't have accessallgroups...
+                $groups = $this->modinfo->get_groups($this->groupingid);
+                if (empty($groups)) {
+                    // ...and you don't belong to a group, then set it so you can't see/access it
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether the module's conditional access settings mean that the user cannot see the activity at all
+     *
+     * @return bool True if the user cannot see the module. False if the activity is either available or should be greyed out.
+     */
+    public function is_user_access_restricted_by_conditional_access() {
+        global $CFG, $USER;
+
+        if (empty($CFG->enableavailability)) {
+            return false;
+        }
+
+        // If module will always be visible anyway (but greyed out), don't bother checking anything else
+        if ($this->showavailability == CONDITION_STUDENTVIEW_SHOW) {
+            return false;
+        }
+
+        // Can the user see hidden modules?
         $modcontext = context_module::instance($this->id);
         $userid = $this->modinfo->get_user_id();
-        if (!empty($CFG->enablegroupmembersonly) and !empty($this->groupmembersonly)
-                and !has_capability('moodle/site:accessallgroups', $modcontext, $userid)) {
-            // If the activity has 'group members only' and you don't have accessallgroups...
-            $groups = $this->modinfo->get_groups($this->groupingid);
-            if (empty($groups)) {
-                // ...and you don't belong to a group, then set it so you can't see/access it
-                return true;
-            }
+        if (has_capability('moodle/course:viewhiddenactivities', $modcontext, $userid)) {
+            return false;
         }
+
+        // Is the module hidden due to unmet conditions?
+        if (!$this->available) {
+            return true;
+        }
+
         return false;
     }
 
-- 
1.7.9.5


From 04678efd111a68c2098760c634b0f2bf6d53e4ad Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Wed, 7 Nov 2012 00:36:31 +0000
Subject: [PATCH 885/903] Automatically generated installer lang files

---
 install/lang/ms/moodle.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/install/lang/ms/moodle.php b/install/lang/ms/moodle.php
index 145ec13..44849c0 100644
--- a/install/lang/ms/moodle.php
+++ b/install/lang/ms/moodle.php
@@ -33,3 +33,4 @@ defined('MOODLE_INTERNAL') || die();
 $string['language'] = 'Bahasa';
 $string['next'] = 'Seterusnya';
 $string['previous'] = 'Sebelum';
+$string['reload'] = 'Muat semula';
-- 
1.7.9.5


From c4851e8085501d5fdb3b32a78356575e3f3d8ade Mon Sep 17 00:00:00 2001
From: Paul Nicholls <paul.nicholls@canterbury.ac.nz>
Date: Wed, 7 Nov 2012 13:45:34 +1300
Subject: [PATCH 886/903] MDL-36346 - YUI2 SWF vulnerability, part 2

---
 lib/yui/2.9.0/build/swfstore/swfstore.swf |  Bin 4897 -> 4841 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/lib/yui/2.9.0/build/swfstore/swfstore.swf b/lib/yui/2.9.0/build/swfstore/swfstore.swf
index a7b838dd95a3320669bb233942b8b21bafb81dc4..9c26ed13788c51ddd4b6d5bca27566289e18155b 100644
GIT binary patch
literal 4841
zcmV<F5*F=4S5pg(9smG%+I?BsdmG1*?;6aYF#t#cBt?<bHIhj25C|TUY>Sp@@q$R1
z5@a3{C7B`yzzhKkz`&RR56g)dZxknv9mjEOCvoD)j&nH9;lxgy%Xaq2?mD~K1;|h0
z`#$WqPx%+P)ja@6%GssdJ>AvS)zwwMs%m`B5|>WM#nYq_$cVp*5OTBb&p^njTwL#;
z90@7Q=~Tw-$Js+|3Cqg%cXux>Ed`g31&!Q7ckjuQC%b$4y8HUNkfY07$yn-gSH?Wt
zHoygpXl5*z%vwn!qp-OeHS*R&ZEYo~@mNJ@HlIszk?~l!meSH%#xlEmgS{vy9_!bQ
zTw1jT)ND4DjHygq_i~q+Fk;u2)J3gJPpM|&RQDDm+hZlIlr}IJH=>#nN@>f=ab<98
zKj*et7;}6}(SdE(RN3xe%t&`<b4ENLL!ERK#W!!?!bD{A(Nxk*Xt{xW=6c3hvX9uJ
zGM-pYQ!QgBN14XfQ)*@*uP$f<qv!crWzKa}Ep6buv8bE~D1AM>eYO^ic&hszW0xrC
zzX3Ah`ya<CGAwLvZeDRa(7{e@qI6-3@V~0pX4m`C;h(stE`_F05siFYKf9L@q!B%*
zrnO$;BS9kK{>_>VcoykvK<JQRq%<`nE*i<WbIQskGYgJn#*zkeIdw(M<4_zy-Mrj4
zL2Z#aR2pR;?|67LmosvFQah!^^0}n7vPE)+qmOGb%b~{O&hz<nRLfPL*Q_Z^welus
zsIq0olV&!hu1L7Dpt;K0JEyWJPOF+X6KYP2+p=VPM@F-}Q`^X{c{LYHBp0=s`MjwO
z8|iFLGflLg+un^AP`&fXOwvlKspOMdymo#mfx^+FRw$X$&ZBj9nRqHH&{bIpBDm$1
zd@`C##uv0|L{D%<O&CTnZzWUm<(cszzTjWbteG9B`ptVOUgVjoXku=gP@IfgTH1{q
z7u8f=3+t8Ppe5sQdL@g*^2nw!h3(OVmRYb8t_53)>CS0sV^L#c@78e8l49uOTzyPU
z#que1=WsrkLk~=$F_;GITT}AGlxA570<#Wfo-^V}y%cE-1x&T^Ok7(I>s2X3jbAF;
z%57xWbyJ$9d9tdNIHy{%gl1AB!|_mKWOm?#qMQrJR+H6oEYxQvC-{zrEgx<7ZxymX
zqOFvSBAS>hnAX$DwB|7~6;SO;sODf?dm@jTj^J8`nci&N>A3!i<DBy*L!6DNMKx!-
z=N~u6)J#03<#26DA0P1|c8AqeDyqh=o3g28;x=&4jh`PsH*;?O()h^qSao?eHadQ0
zZ2Dj+?`-9q!Kq{2eLX$*bw~5b6xz0a2k!fApttNKj@V!O{=)|5<77t59oWe<p0Tu?
z8nY1jHshZEN66mo5!}!3!PdE>auPR%$7W$>GUcHaOS6+eoZ++-VV)(XY$@zwC4@_Q
zDsLueDT1oe4dJECg`9!jwN{+@EK6=8QWIhp`5ajz>r8RnI!%_yHD_F7$Pq0BxM-sD
zt8i-uK{$d~FcwO=$6PTH%dRqzs>*{4YDP;{O@xOBC+4T7!;^z&M!i^5mdZe`PiE9l
zp@ODSZ&dd9bV5^Nb~GsLXvNSK3u%~#l%%OxhM|~ggaD3|l3kT+jKM64SF-H<pmG5t
z%+!=*h7|%FFdlVLO{UanN>i4SaVw!9xRivJTu4|<Twm{r?6R_~^d5TvzeY|;sksF$
z7xbm?2|Jp!V@}36nZU5qa<1X<xeF7c)1y8_DEH+AMxllfagB%PM<*x4lhsqB!!wiP
z)0ge3JH<DSXLQ4XHQE`&_!_jJTQZpkJZRx^WV`W{Nwk+{S|Z!zm_0Y)w3up^q_OC&
zE+J_d(U(zE{?XEa!%<gbTDzXl#F+B!9XE2CmCt4H{+YP36igZRt%8Z1ra$-@5ff6%
zkIh)>Qe!c6Ntd28(pBd6WbtU((F&jTbIVq;v=TQoQ^^>X!o?`I7-rrQ92F)J_n<S&
zr^_spa$yn=2X_nu48M3$X%VweoMv$&nn7f_%%Lq>qJ_70PHGFI%UNe@d$6;kmF6@A
zLrjB*UHJ@_Y&EN$W?+gNX^hn}jF=!Loku;>EYix*YBNiGLH7mZz$u>AuYlWQFY=kh
zRRqml!Y2}C?!`Ecs<(*qqf^6Gl?66)XH{15(H&+LH;Wb@;m3LS%pRZpKeVkFG=X_m
z!M7R)axRH5R4|^?NnX&*oqE$~&R8-rjTk5;Cs&HDXyx)+^*uG2E$|XQ&&t*W`XuE(
zKRS)EJ2*WvC1do&S?)322%^$9HzV3f$6NB%BvMvn=Ft?ZBn}+Om>#lxs}yBDt1_%c
z?A~5WLM&C;^@4^bW~RnQN5muxitE~n%Sgp}k#S|TB|eaN<k1VG=SRlRpP`tQ;u!PK
z!AyonHA5L1DX0vmlBiRcnT%@{++o5~qMDXrX@hac6)bf&5KF#SrVT~ok^+_7!rTyI
z@pVsv;kg4zids29O&j@)6_ip4;#BPudBajimt&fSIN-?fS1MyUa>SSs*N#t>_9JA~
z7>lc%9qp*0#`l}s5?AREYUX)hd3d21<2lUD$Cp@UtGTD1RP87|{!bOEhQD3k{FUNd
zuDULyOkpXG%N3Psu3a7Mx}tVH+0%70IM>+%3mBcIReufNYVBCIpIXo|9anJ?*F4(_
zxC_@fYW7_o91DkoOY9sghyiC8#Zu{SYJdj0!QWUXk%oqb1C2uxk;ravJ<?p)Jkflv
z`FwM@`9i~FgVwMLxNx9(Nc2h=xL&cUy2j_Pb;-~`cY9rpK>r971PTrcA_a+plLDpS
zqJo<W9x8Y#R8gp*f{!|CDb!I%J(YG*=WZ%BQmKhb%~aY$rM*<zPpLxTAcaE|4pV5M
z&`RM5g*FQ96gnt$QaDN>K%t95kU}?w9tyn_`Y0Tu(s3%CpwfL*x}Qo9Q0XLvekwgk
z#Zy##h>8PLe3*)-DGXA1n8FB^N2wg5aE8Jdg>edJ<s%>mKyCxM6Xc^H9|O4u<W`Wo
zKn{Z34RSBYeIU1k+yU|-kPm{~0`g&y2hjqL(z+=M)A9_CFH*QfVOG8j@)g(v@?#*+
zfqV_*d7$1oIf5)PTCdak1qulYNjU?u0o0kL@C1b%1(SkBAx~kE!aVgZQSS=%K1rQ7
zC_F{sGZa26Pot3Qbl2zb^LJ3ah@WS$-K3r`0`+_e+q2ldjO{sWi`4Tx9&J$g3NpQb
z!x!=U61G>deFHhZiS1k1Uc>fnq<shE*8#uZ1^EpC`Fq&D&*neG_9NVXg~Ho7{4ut7
zaLeo1ev0i4Y(K;Hb8PP-+b{4|zeJw*K#qd^K1%r&wqIlW0NZbv#NT3jALKva{9`u%
z2W<ZcRQM;Ljz3}hXKeohdk|rNMuC69)&B%padeRKAO6Gx0k#bUaPXOfbs}~SHgbri
zj*$@T1Q;8DXzye{H0@;p8^wv}uqPn6h#=TP1eta2l1yCX|G<O$BqVuo;F7%FYVhJ8
zI6&|+{;JXu6@{xA)l=&DpHSnIMFQ=9LTX7JAs$lC7<aL*fpxnHaqNReLYhc35Md8q
zZ!g|%9}sCj5a$8>k*ff49Rz~VB<{mNJS{-Htw5@d;DK#GYTAMLI)L~)fz%!aQWpSH
z--Txc@rZ6bp$AA~FOa4_AkD{s>^Tl(?+GCL?gO&_ejo=P0HT}(au9!jA8PW*F4F3J
zkl<ZTF?An8{m2089tLvcG>|qT3=;4Pjv*p=9gY?v9EKVZNINv)MLW=HF4<q`xi;9k
z0qWqjq1I<X9Xi7-E6DEGq0mzpCxvj3%#c;jonk>hpblf-s*Yf<sH4~)RzujgsAsSb
zsAJf7sN>l0SI=U9M12JNHgy8~cJ&<go$7h)kE&tp52_ciKcqg2{T_7^`(||t`+e#(
z_IuTt%D7*>SeR>yTsqqXiN=E7SPVZ5XBfypb~{l^y?zXDEjVQNaG^(8oxNKqCh7~i
zU%#whiOjzDN@p!1rK7l5dytU1*|W0*S=I`AUHB@jg&!lFb4|U1-|!qk!Qu|Vl7QCm
z;H;R~RS2J83{Hv4?lm-!aw{e(tDX%Mre7<D=ApKo5PPCW*6I<uZDWOE=m1oB*3?Mg
zYE1MYq5{=1u|i}6wHS^<p%@j{*FyJ;i=8papCkwvLS&n7U5)rIRc4PzI{2<|jQ9qT
z>O&Mn#h5d2HR^1}SZX1@W_C(x20n}g9~%iif%Puup1*8v3U6<2ez3WTqo{<prR=uN
z?C#|o$y+xXQ;@?Yh_btd*&}oqZrxq;qcCNRv#jY6yy&`3Sw~)(N!znsntMyy%UqnB
zvB+GU0xu)M!yLKG-lHO0<%l(0^fK4DON)9ODODn>a{?)$7GmDHNLHo0EyUXJVVufq
z{3y=5u1EApScCN!t&R2KuK(KHWa6rwlI*^pAKnG#-LhsCZ<S5F)&gN&C=>(gx`Muu
z&^ID(uVLGdmvmqC+_g<&?_DqNE!un61L~Sm+}i7t@ZN3gCjM|cDFiOhkicUX$&8Sw
z3q%70Gbry4$NFhFg6w`Mp%B5kVBIMqsn&sps%IcX#r?(BRo9!LIpz^ut7Fo6G@z7F
zKdIe^NQegF+r>r_k)-~3_&WG@^To#l*8{0Q`u2>l#e-n4XAY_>^vqE^q*7-otWvJQ
zF1F+?yDF3hq&0|6*_~%vZOmoPX2@#hPBG%rje_1C&I-kdtUpoEd->3<=L&is4kM;+
zq26nH{-w|&1eV`H6EUQ$wUCz0(2{^_Eo3dQ99jl8+gJ}Q-!AC8Z{LbZ#krNJban;8
zPcmJ1OOm_huNat@I`8&qpse0V3mUYg9rjql&#knRO+0C;K`{*)%-zr+1^QF^XU^UL
zw!wE8G1{}%bA@znboLxgL!=R{b2D&V6Oiw-GXmOWp9@7sZU&x)&?>;KwAey6P>c}x
zJm`_9F}`~cei~pXAGXiMMM?i0aykn*6tOu&Jpv0Z4UVK8J}h^AqQn2m=B7(zvQv&)
z7pj5z#<!R8pa!=99rOiY?n$FB8j*=I7s1hip{MZ)LO%}#T;vwkrW@o7Se<}8gZ0Tl
zzK9j-2Kf@!C<l2KtCWW{vKXr^^c2@ZUj}H|ti}L4GS-IfYhpN~=+f|Umg$;B2Tup3
z<BR%p{Cosl<C+bRJq(2nC@S(i1ilJGP|%Nsz5;@c!@W+2yXGT-Ipj_cw?6P*;Jt(Q
zqU{f9he4UaAn-LP>DR<;z(_4*+X4dv<J`7T#t0*GSh1tfFQ1Ym@D0LtNy3hWiX<e@
zy}-{1y}(p+l;?syXU=3E6YI+!3vTz=*ZJ1lftRtp0=L;d9%5<9_MwD!^ffWa6&d92
zmLSK##(^fBf!5o?Tf$f2MUcLRE_RTY(8Uh&b#$?Vyv$vUZk0S_pM=(a)lspwZB?v@
zHs)s;=Fupxfc`4n>h!a!sN5>qx)xtVkpvrszX7llbhqJNh09K~rG1l0!v|PL;7w+q
zg5KcYj~B8RzXgG};2o@;_VhJ-T949yfLPg8i^vba(>{qEm~uRQ8x2~B)Ruxo2z?ub
zgda0cq)Pt|@}I<X!ShgHCWOypKfcy><WAo$LbghOZJJ4~%%8C>QF;R~Yowekinzy}
zdOrMJaPX+QjqkL>pK{6H$N~b3W*T|}2p-L9Tj{JsUExTg0quo*egZSV<Mcz}Pr@hY
zM-0_BxgWpB{rDF5<M+4u@dp^Hv*d>us<UK2%dxEDg<1(K!Gs(TJ+k+&_UpriUX97@
zfrfQ|AV#BNEk1P%bM!1Fp&tPWKY+KduRT<G_;ki(`{fgr%TJ%EtX|=|vk5Npmr!Vq
zpmbjiGXk0*=H@oo=W<6~k+(trG1T|sYr`3(>N^m1uBku4zNr2b`*rna*hfY6=j<b?
z@1h2cQ75ls_U2ze{VrZ{eg~``#hhh^wlUkpf!}k$ZC`+^@dS$iq6k}s@N!X2VG26v
z#1wRn7rVPf{g<G>2Z5XQ?fi%jA@Du~J_1gEA4BkZ;Eyol*h*nOKj-^<uFAH&c1XaN
zMpL0Da!LOcM26n&WVyNnXTOHX;JfIC!}$JmVFA}j#M2Y`0D2<7!S-8hzr*Ik|7OWP
z{+FmZ!`@%`+Xh1uhpi4#l-^(tTzwwyvTlRDw2O%c5k3#<EKCxo3i_$Qzk>dISnRCD
zpC}z{{z++0nI<>&Kfq$`EXQ1lHSrKj!v6+=e}^G~$;JoJL!l2bOe7X2xL&A;NenRF
z|ETb8tQYiw?Ysl1=@C&9rD6WW;OEsIXV1!wBCBxt6G_JUwx2Dn71vN?_#+Tl5&Lhu
zh!xPRg%bAhAuI}_#O%rCAV@LU7ZDl*#qcUPkf9yz>G0t@<6~e3^~}P)L=)1h>evsr
P%KvOUjg$WcJEN_slRjcC

literal 4897
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
Tb?l3=@_#sw;NX7&K`y&j^{0*5

-- 
1.7.9.5


From f87d5a71ef0f3d06f666454eb39595777a3d2ebc Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Wed, 7 Nov 2012 11:49:56 +0100
Subject: [PATCH 887/903] NOBUG: Trivial whitespace fix to quickly fix ongoing
 CI status.

---
 comment/comment.js |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/comment/comment.js b/comment/comment.js
index f137299..37c44d4 100644
--- a/comment/comment.js
+++ b/comment/comment.js
@@ -309,16 +309,16 @@ bodyContent: '<div class="comment-delete-confirm"><a href="#" id="confirmdelete-
                             CommentHelper.confirmoverlay.set('xy', [e.pageX-width-5, e.pageY]);
                             CommentHelper.confirmoverlay.set('visible', true);
                             Y.one('#canceldelete-'+scope.client_id).on('click', function(e) {
-								e.preventDefault();
+                                e.preventDefault();
                                 scope.cancel_delete();
                                 });
                             Y.Event.purgeElement('#confirmdelete-'+scope.client_id, false, 'click');
                             Y.one('#confirmdelete-'+scope.client_id).on('click', function(e) {
-									e.preventDefault();
-                                    if (commentid[1]) {
-                                        scope.dodelete(commentid[1]);
-                                    }
-                                });
+                                e.preventDefault();
+                                if (commentid[1]) {
+                                    scope.dodelete(commentid[1]);
+                                }
+                            });
                         }, scope, node);
                     }
                 );
-- 
1.7.9.5


From da427d1e51e59a915b44c8712a69ac24c414d30f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20=C5=A0koda?= <commits@skodak.org>
Date: Wed, 24 Oct 2012 23:37:49 +0800
Subject: [PATCH 888/903] MDL-36196 hardcode the required PHP version in
 installer

---
 install.php |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/install.php b/install.php
index c737e63..69118df 100644
--- a/install.php
+++ b/install.php
@@ -56,10 +56,8 @@ if (function_exists('date_default_timezone_set') and function_exists('date_defau
 @error_reporting(E_ALL);
 @ini_set('display_errors', '1');
 
-// Check that PHP is of a sufficient version
-// PHP 5.2.0 is intentionally checked here even though a higher version is required by the environment
-// check. This is not a typo - see MDL-18112
-if (version_compare(phpversion(), "5.2.0") < 0) {
+// Check that PHP is of a sufficient version.
+if (version_compare(phpversion(), '5.3.2') < 0) {
     $phpversion = phpversion();
     // do NOT localise - lang strings would not work here and we CAN not move it after installib
     echo "Moodle 2.1 or later requires at least PHP 5.3.2 (currently using version $phpversion).<br />";
-- 
1.7.9.5


From 9b025da73261e80867458926b3ac22c9d5ce535b Mon Sep 17 00:00:00 2001
From: Adrian Greeve <adrian@moodle.com>
Date: Wed, 7 Nov 2012 19:50:15 +0100
Subject: [PATCH 889/903] MDL-35558 mod_data: Show only own entries while
 there are required pending.

---
 mod/data/lib.php  |   16 ++++++++++------
 mod/data/view.php |   39 ++++++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/mod/data/lib.php b/mod/data/lib.php
index 583ea73..d78acc5 100644
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -3514,7 +3514,7 @@ function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
  * @param int $sort            DATA_*
  * @param stdClass $data       Data module object
  * @param array $recordids     An array of record IDs.
- * @param string $selectdata   Information for the select part of the sql statement.
+ * @param string $selectdata   Information for the where and select part of the sql statement.
  * @param string $sortorder    Additional sort parameters
  * @return array sqlselect     sqlselect['sql'] has the sql string, sqlselect['params'] contains an array of parameters.
  */
@@ -3559,13 +3559,17 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
                                  {user} u ';
         $groupsql = ' GROUP BY r.id, r.approved, r.timecreated, r.timemodified, r.userid, u.firstname, u.lastname, ' .$sortcontentfull;
     }
-    $nestfromsql = 'WHERE c.recordid = r.id
-                      AND r.dataid = :dataid
-                      AND r.userid = u.id';
+
+    // Default to a standard Where statement if $selectdata is empty.
+    if ($selectdata == '') {
+        $selectdata = 'WHERE c.recordid = r.id
+                         AND r.dataid = :dataid
+                         AND r.userid = u.id ';
+    }
 
     // Find the field we are sorting on
     if ($sort > 0 or data_get_field_from_id($sort, $data)) {
-        $nestfromsql .= ' AND c.fieldid = :sort';
+        $selectdata .= ' AND c.fieldid = :sort';
     }
 
     // If there are no record IDs then return an sql statment that will return no rows.
@@ -3574,7 +3578,7 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
     } else {
         list($insql, $inparam) = $DB->get_in_or_equal(array('-1'), SQL_PARAMS_NAMED);
     }
-    $nestfromsql .= ' AND c.recordid ' . $insql . $selectdata . $groupsql;
+    $nestfromsql = $selectdata . ' AND c.recordid ' . $insql . $groupsql;
     $sqlselect['sql'] = "$nestselectsql $nestfromsql $sortorder";
     $sqlselect['params'] = $inparam;
     return $sqlselect;
diff --git a/mod/data/view.php b/mod/data/view.php
index 1b2d85b..0b76db0 100644
--- a/mod/data/view.php
+++ b/mod/data/view.php
@@ -456,11 +456,15 @@ if ($showactivity) {
             $requiredentries_allowed = false;
         }
 
+        // Initialise the first group of params for advanced searches.
+        $initialparams   = array();
+
     /// setup group and approve restrictions
         if (!$approvecap && $data->approval) {
             if (isloggedin()) {
                 $approveselect = ' AND (r.approved=1 OR r.userid=:myid1) ';
                 $params['myid1'] = $USER->id;
+                $initialparams['myid1'] = $params['myid1'];
             } else {
                 $approveselect = ' AND r.approved=1 ';
             }
@@ -471,6 +475,7 @@ if ($showactivity) {
         if ($currentgroup) {
             $groupselect = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
             $params['currentgroup'] = $currentgroup;
+            $initialparams['currentgroup'] = $params['currentgroup'];
         } else {
             if ($canviewallrecords) {
                 $groupselect = ' ';
@@ -486,6 +491,8 @@ if ($showactivity) {
         $advwhere        = '';
         $advtables       = '';
         $advparams       = array();
+        // This is used for the initial reduction of advanced search results with required entries.
+        $entrysql        = '';
 
     /// Find the field we are sorting on
         if ($sort <= 0 or !$sortfield = data_get_field_from_id($sort, $data)) {
@@ -514,8 +521,7 @@ if ($showactivity) {
             $tables = '{data_content} c,{data_records} r, {data_content} cs, {user} u ';
             $where =  'WHERE c.recordid = r.id
                          AND r.dataid = :dataid
-                         AND r.userid = u.id
-                         AND cs.recordid = r.id ';
+                         AND r.userid = u.id ';
             $params['dataid'] = $data->id;
             $sortorder = ' ORDER BY '.$ordering.', r.id ASC ';
             $searchselect = '';
@@ -523,7 +529,9 @@ if ($showactivity) {
             // If requiredentries is not reached, only show current user's entries
             if (!$requiredentries_allowed) {
                 $where .= ' AND u.id = :myid2 ';
+                $entrysql = ' AND r.userid = :myid3 ';
                 $params['myid2'] = $USER->id;
+                $initialparams['myid3'] = $params['myid2'];
             }
 
             if (!empty($advanced)) {                                                  //If advanced box is checked.
@@ -541,6 +549,7 @@ if ($showactivity) {
                     $advparams = array_merge($advparams, $val->params);
                 }
             } else if ($search) {
+                $where .= ' AND cs.recordid = r.id ';
                 $searchselect = " AND (".$DB->sql_like('cs.content', ':search1', false)." OR ".$DB->sql_like('u.firstname', ':search2', false)." OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
                 $params['search1'] = "%$search%";
                 $params['search2'] = "%$search%";
@@ -558,10 +567,11 @@ if ($showactivity) {
             $count = ' COUNT(DISTINCT c.recordid) ';
             $tables = '{data_content} c, {data_records} r, {data_content} cs, {user} u ';
             $where =  'WHERE c.recordid = r.id
-                         AND c.fieldid = :sort
                          AND r.dataid = :dataid
-                         AND r.userid = u.id
-                         AND cs.recordid = r.id ';
+                         AND r.userid = u.id ';
+            if (!$advanced) {
+                $where .=  'AND c.fieldid = :sort';
+            }
             $params['dataid'] = $data->id;
             $params['sort'] = $sort;
             $sortorder = ' ORDER BY sortorder '.$order.' , r.id ASC ';
@@ -569,8 +579,10 @@ if ($showactivity) {
 
             // If requiredentries is not reached, only show current user's entries
             if (!$requiredentries_allowed) {
-                $where .= ' AND u.id = ' . $USER->id;
+                $where .= ' AND u.id = :myid2';
+                $entrysql = ' AND r.userid = :myid3';
                 $params['myid2'] = $USER->id;
+                $initialparams['myid3'] = $params['myid2'];
             }
             $i = 0;
             if (!empty($advanced)) {                                                  //If advanced box is checked.
@@ -587,6 +599,7 @@ if ($showactivity) {
                     $advparams = array_merge($advparams, $val->params);
                 }
             } else if ($search) {
+                $where .= ' AND cs.recordid = r.id ';
                 $searchselect = " AND (".$DB->sql_like('cs.content', ':search1', false)." OR ".$DB->sql_like('u.firstname', ':search2', false)." OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
                 $params['search1'] = "%$search%";
                 $params['search2'] = "%$search%";
@@ -599,23 +612,15 @@ if ($showactivity) {
     /// To actually fetch the records
 
         $fromsql    = "FROM $tables $advtables $where $advwhere $groupselect $approveselect $searchselect $advsearchselect";
-        $sqlcount   = "SELECT $count $fromsql";   // Total number of records when searching
-        $sqlmax     = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
         $allparams  = array_merge($params, $advparams);
 
         // Provide initial sql statements and parameters to reduce the number of total records.
-        $selectdata = $groupselect . $approveselect;
-        $initialparams = array();
-        if ($currentgroup) {
-            $initialparams['currentgroup'] = $params['currentgroup'];
-        }
-        if (!$approvecap && $data->approval && isloggedin()) {
-            $initialparams['myid1'] = $params['myid1'];
-        }
+        $initialselect = $groupselect . $approveselect . $entrysql;
 
-        $recordids = data_get_all_recordids($data->id, $selectdata, $initialparams);
+        $recordids = data_get_all_recordids($data->id, $initialselect, $initialparams);
         $newrecordids = data_get_advance_search_ids($recordids, $search_array, $data->id);
         $totalcount = count($newrecordids);
+        $selectdata = $where . $groupselect . $approveselect;
 
         if (!empty($advanced)) {
             $advancedsearchsql = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
-- 
1.7.9.5


From a5b62b8f313a60c3b80666cce2cc37f3fad11583 Mon Sep 17 00:00:00 2001
From: Nadav Kavalerchik <nadavkav@gmail.com>
Date: Sat, 29 Sep 2012 16:09:51 +0200
Subject: [PATCH 890/903] MDL-35249 - Move Grading popmenu "userid" column
 after "scale" column (workaround)

Conflicts:

	mod/assign/gradingtable.php
---
 mod/assign/gradingtable.php |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/mod/assign/gradingtable.php b/mod/assign/gradingtable.php
index fce13ea..29be4ee 100644
--- a/mod/assign/gradingtable.php
+++ b/mod/assign/gradingtable.php
@@ -121,10 +121,6 @@ class assign_grading_table extends table_sql implements renderable {
         if (!$this->is_downloading()) {
             $columns[] = 'select';
             $headers[] = get_string('select') . '<div class="selectall"><input type="checkbox" name="selectall" title="' . get_string('selectall') . '"/></div>';
-
-            // We have to call this column userid so we can use userid as a default sortable column.
-            $columns[] = 'userid';
-            $headers[] = get_string('edit');
         }
 
         // User picture
@@ -145,6 +141,11 @@ class assign_grading_table extends table_sql implements renderable {
         // Grade
         $columns[] = 'grade';
         $headers[] = get_string('grade');
+        if (!$this->is_downloading()) {
+            // We have to call this column userid so we can use userid as a default sortable column.
+            $columns[] = 'userid';
+            $headers[] = get_string('edit');
+        }
 
         // Submission plugins
         if ($assignment->is_any_submission_plugin_enabled()) {
-- 
1.7.9.5


From 845cfc33898922d94aa5aec1969d5a4f90ad8e64 Mon Sep 17 00:00:00 2001
From: Mary Evans <lazydaisy@visible-expression.co.uk>
Date: Fri, 26 Oct 2012 01:18:17 +0100
Subject: [PATCH 891/903] MDL-36197 theme_fusion: Fix for "Your progress"
 overlaps completion tracking checkbox

---
 theme/fusion/style/core.css |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/theme/fusion/style/core.css b/theme/fusion/style/core.css
index bc31d35..7e94997 100644
--- a/theme/fusion/style/core.css
+++ b/theme/fusion/style/core.css
@@ -390,3 +390,8 @@ h2.headingblock {
 #page-mod-assignment-submissions #attempts th.header {
     font-size: 80%;
 }
+
+.course-content ul.topics,
+.course-content ul.weeks {
+    clear: both;
+}
\ No newline at end of file
-- 
1.7.9.5


From d8e550e4ac5b3847cf34b3e3e7dc02d894c964ce Mon Sep 17 00:00:00 2001
From: Mark Nelson <markn@moodle.com>
Date: Wed, 7 Nov 2012 16:39:01 +0800
Subject: [PATCH 892/903] MDL-33791 Portfolio: Fixed security issue with
 passing file paths.

---
 lib/portfoliolib.php |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++
 portfolio/add.php    |   11 +++-----
 2 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/lib/portfoliolib.php b/lib/portfoliolib.php
index 8405102..be531b1 100644
--- a/lib/portfoliolib.php
+++ b/lib/portfoliolib.php
@@ -1271,6 +1271,74 @@ function portfolio_rewrite_pluginfile_url_callback($contextid, $component, $file
     return $format->file_output($file, $options);
 }
 
+/**
+* Function to require any potential callback files, throwing exceptions
+* if an issue occurs.
+*
+* @param string $callbackfile This is the location of the callback file '/mod/forum/locallib.php'
+* @param string $class Name of the class containing the callback functions
+* activity components should ALWAYS use their name_portfolio_caller
+* other locations must use something unique
+*/
+function portfolio_include_callback_file($callbackfile, $class = null) {
+    global $CFG;
+    require_once($CFG->libdir . '/adminlib.php');
+
+    // Get the last occurrence of '/' in the file path.
+    $pos = strrpos($callbackfile, '/');
+    // Get rid of the first slash (if it exists).
+    $callbackfile = ltrim($callbackfile, '/');
+    // Get a list of valid plugin types.
+    $plugintypes = get_plugin_types(false);
+    // Assume it is not valid for now.
+    $isvalid = false;
+    // Go through the plugin types.
+    foreach ($plugintypes as $type => $path) {
+        if (strrpos($callbackfile, $path) === 0) {
+            // Found the plugin type.
+            $isvalid = true;
+            $plugintype = $type;
+            $pluginpath = $path;
+        }
+    }
+    // Throw exception if not a valid component.
+    if (!$isvalid) {
+        throw new coding_exception('Somehow a non-valid plugin path was passed, could be a hackz0r attempt, exiting.');
+    }
+    // Keep record of the filename.
+    $filename = substr($callbackfile, $pos);
+    // Remove the file name.
+    $component = trim(substr($callbackfile, 0, $pos), '/');
+    // Replace the path with the type.
+    $component = str_replace($pluginpath, $plugintype, $component);
+    // Ok, replace '/' with '_'.
+    $component = str_replace('/', '_', $component);
+    // Check that it is a valid component.
+    if (!get_component_version($component)) {
+        throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component);
+    }
+
+    // Obtain the component's location.
+    if (!$componentloc = get_component_directory($component)) {
+        throw new portfolio_button_exception('nocallbackcomponent', 'portfolio', '', $component);
+    }
+
+    // Check if the filename does not meet any of the expected names.
+    if (($filename != 'locallib.php') && ($filename != 'portfoliolib.php') && ($filename != 'portfolio_callback.php')) {
+        debugging('Please standardise your plugin by keeping your portfolio callback functionality in the file locallib.php.', DEBUG_DEVELOPER);
+    }
+
+    // Throw error if file does not exist.
+    if (!file_exists($componentloc . '/' . $filename)) {
+        throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $callbackfile);
+    }
+
+    require_once($componentloc . '/' . $filename);
+
+    if (!is_null($class) && !class_exists($class)) {
+        throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
+    }
+}
 
 /**
  * Go through all the @@PLUGINFILE@@ matches in some text,
diff --git a/portfolio/add.php b/portfolio/add.php
index b5a1c4a..cb2aff1 100644
--- a/portfolio/add.php
+++ b/portfolio/add.php
@@ -173,13 +173,10 @@ if (!empty($dataid)) {
             $callbackargs[substr($key, 3)] = $value;
         }
     }
-    // righto, now we have the callback args set up
-    // load up the caller file and class and tell it to set up all the data
-    // it needs
-    require_once($CFG->dirroot . $callbackfile);
-    if (!class_exists($callbackclass) || !is_subclass_of($callbackclass, 'portfolio_caller_base')) {
-        throw new portfolio_caller_exception('callbackclassinvalid', 'portfolio');
-    }
+
+    // Ensure that we found a file we can use, if not throw an exception.
+    portfolio_include_callback_file($callbackfile, $callbackclass);
+
     $caller = new $callbackclass($callbackargs);
     $caller->set('user', $USER);
     if ($formats = explode(',', $callerformats)) {
-- 
1.7.9.5


From 3bcff380158e81506b210b3004b865fe39cf6917 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rex@oid.ucla.edu>
Date: Wed, 7 Nov 2012 16:26:26 -0800
Subject: [PATCH 893/903] MDL-36051 - Quick Grading in Assignment module does
 not turn on in some circumstances * Fixed bug with
 quick grading when file submission is turned off

---
 mod/assign/locallib.php |    4 +++-
 mod/assign/module.js    |   10 ++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/mod/assign/locallib.php b/mod/assign/locallib.php
index 7238b70..1e24886 100644
--- a/mod/assign/locallib.php
+++ b/mod/assign/locallib.php
@@ -2760,7 +2760,9 @@ class assign {
                                                                  'showquickgrading'=>false));
         if ($formdata = $mform->get_data()) {
             set_user_preference('assign_perpage', $formdata->perpage);
-            set_user_preference('assign_filter', $formdata->filter);
+            if (isset($formdata->filter)) {
+                set_user_preference('assign_filter', $formdata->filter);
+            }
         }
     }
 
diff --git a/mod/assign/module.js b/mod/assign/module.js
index a1cbe07..ec5e071 100644
--- a/mod/assign/module.js
+++ b/mod/assign/module.js
@@ -117,9 +117,11 @@ M.mod_assign.init_grading_options = function(Y) {
             Y.one('form.gradingoptionsform').submit();
         });
         var filterelement = Y.one('#id_filter');
-        filterelement.on('change', function(e) {
-            Y.one('form.gradingoptionsform').submit();
-        });
+        if (filterelement) {
+            filterelement.on('change', function(e) {
+                Y.one('form.gradingoptionsform').submit();
+            });
+        }
         var quickgradingelement = Y.one('#id_quickgrading');
         if (quickgradingelement) {
             quickgradingelement.on('change', function(e) {
@@ -139,4 +141,4 @@ M.mod_assign.init_grade_change = function(Y) {
             }
         });
     }
-};
\ No newline at end of file
+};
-- 
1.7.9.5


From 8a73556f8da98e3779eb4c217dff2ac0baebc297 Mon Sep 17 00:00:00 2001
From: Frederic Massart <fred@moodle.com>
Date: Thu, 8 Nov 2012 10:20:22 +0800
Subject: [PATCH 894/903] MDL-36422 question: Fixed malformed HTML in manual
 marking

---
 question/behaviour/rendererbase.php |    1 -
 1 file changed, 1 deletion(-)

diff --git a/question/behaviour/rendererbase.php b/question/behaviour/rendererbase.php
index e04a638..6a24e38 100644
--- a/question/behaviour/rendererbase.php
+++ b/question/behaviour/rendererbase.php
@@ -86,7 +86,6 @@ abstract class qbehaviour_renderer extends plugin_renderer_base {
 
         $commenteditor = html_writer::tag('div', html_writer::tag('textarea', s($commenttext),
                 array('id' => $id, 'name' => $inputname, 'rows' => 10, 'cols' => 60)));
-        $commenteditor .= html_writer::end_tag('div');
 
         $editorformat = '';
         if (count($formats) == 1) {
-- 
1.7.9.5


From eabdc81c403d41babcb653b673f352a04750161e Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 30 Aug 2012 12:23:18 +0800
Subject: [PATCH 895/903] MDL-27824 - course category: add check test for
 ->coursesperpage value.

---
 course/category.php |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/course/category.php b/course/category.php
index a04e499..7eb71c2 100644
--- a/course/category.php
+++ b/course/category.php
@@ -31,7 +31,6 @@ require_once($CFG->libdir.'/textlib.class.php');
 
 $id = required_param('id', PARAM_INT); // Category id
 $page = optional_param('page', 0, PARAM_INT); // which page to show
-$perpage = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); // how many per page
 $categoryedit = optional_param('categoryedit', -1, PARAM_BOOL);
 $hide = optional_param('hide', 0, PARAM_INT);
 $show = optional_param('show', 0, PARAM_INT);
@@ -41,6 +40,15 @@ $moveto = optional_param('moveto', 0, PARAM_INT);
 $resort = optional_param('resort', 0, PARAM_BOOL);
 $sesskey = optional_param('sesskey', '', PARAM_RAW);
 
+// MDL-27824 - This is a temporary fix until we have the proper 
+// way to check/initialize $CFG value.
+if (isset($CFG->coursesperpage)) {
+    $defaultperpage =  $CFG->coursesperpage;
+} else {
+    $defaultperpage = 20;
+}
+$perpage = optional_param('perpage', $defaultperpage, PARAM_INT); // how many per page
+
 if (empty($id)) {
     print_error("unknowcategory");
 }
-- 
1.7.9.5


From 74b266a332231797bdd4b154b0404e3c1d2ec194 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Tue, 11 Sep 2012 16:17:22 +0800
Subject: [PATCH 896/903] MDL-27824 course categories: Added @todo comments to
 remove the temporary fix

---
 course/category.php |    1 +
 1 file changed, 1 insertion(+)

diff --git a/course/category.php b/course/category.php
index 7eb71c2..e910119 100644
--- a/course/category.php
+++ b/course/category.php
@@ -42,6 +42,7 @@ $sesskey = optional_param('sesskey', '', PARAM_RAW);
 
 // MDL-27824 - This is a temporary fix until we have the proper 
 // way to check/initialize $CFG value.
+// @todo MDL-35138 remove this temporary solution
 if (isset($CFG->coursesperpage)) {
     $defaultperpage =  $CFG->coursesperpage;
 } else {
-- 
1.7.9.5


From 9bc298d28751b16663fc135dd31f07aa132fa1d0 Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Fri, 12 Oct 2012 15:24:55 +0800
Subject: [PATCH 897/903] MDL-27824 course categories: change isset() to
 empty()

---
 course/category.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/category.php b/course/category.php
index e910119..6f48269 100644
--- a/course/category.php
+++ b/course/category.php
@@ -43,7 +43,7 @@ $sesskey = optional_param('sesskey', '', PARAM_RAW);
 // MDL-27824 - This is a temporary fix until we have the proper 
 // way to check/initialize $CFG value.
 // @todo MDL-35138 remove this temporary solution
-if (isset($CFG->coursesperpage)) {
+if (!empty($CFG->coursesperpage)) {
     $defaultperpage =  $CFG->coursesperpage;
 } else {
     $defaultperpage = 20;
-- 
1.7.9.5


From a46405df3a930739e7d641a18c00725e5b792ecc Mon Sep 17 00:00:00 2001
From: Rossiani Wijaya <rwijaya@moodle.com>
Date: Thu, 8 Nov 2012 12:29:42 +0800
Subject: [PATCH 898/903] MDL-27824 course categories: remove trailing
 whitespace

---
 course/category.php |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/course/category.php b/course/category.php
index 6f48269..cb1d0c7 100644
--- a/course/category.php
+++ b/course/category.php
@@ -40,7 +40,7 @@ $moveto = optional_param('moveto', 0, PARAM_INT);
 $resort = optional_param('resort', 0, PARAM_BOOL);
 $sesskey = optional_param('sesskey', '', PARAM_RAW);
 
-// MDL-27824 - This is a temporary fix until we have the proper 
+// MDL-27824 - This is a temporary fix until we have the proper
 // way to check/initialize $CFG value.
 // @todo MDL-35138 remove this temporary solution
 if (!empty($CFG->coursesperpage)) {
-- 
1.7.9.5


From c4d19c8789ba1ac8695553fe2ce6a6e4ae9e1aba Mon Sep 17 00:00:00 2001
From: AMOS bot <amos@moodle.org>
Date: Fri, 9 Nov 2012 00:38:56 +0000
Subject: [PATCH 899/903] Automatically generated installer lang files

---
 install/lang/no/error.php   |    2 +-
 install/lang/no/install.php |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/install/lang/no/error.php b/install/lang/no/error.php
index 26b9927..8d39a3c 100644
--- a/install/lang/no/error.php
+++ b/install/lang/no/error.php
@@ -42,7 +42,7 @@ $string['componentisuptodate'] = 'Komponenten er oppdatert';
 $string['downloadedfilecheckfailed'] = 'Sjekk av nedlastet fil mislykkes.';
 $string['invalidmd5'] = 'Ugyldig md5, prøv igjen';
 $string['missingrequiredfield'] = 'Noen påkrevde felt mangler';
-$string['remotedownloaderror'] = 'Mislykkes i å laste ned komponenten til din server, vennligst sjekk proxy-innstillingene. PHP cURL tillegget er sterkt anbefalt. <br /><br />Du må laste ned <a href="{$a->url}">{$a->url}</a> filen manuelt, kopiere den til "{$a->dest}" på serveren din og pakke den ut der.';
+$string['remotedownloaderror'] = 'Mislykkes i å laste ned komponenten til din server, vennligst sjekk proxy-innstillingene. PHP cURL-tillegget er sterkt anbefalt. <br /><br />Du må laste ned <a href="{$a->url}">{$a->url}</a> filen manuelt, kopiere den til "{$a->dest}" på serveren din og pakke den ut der.';
 $string['wrongdestpath'] = 'Gal målmappe';
 $string['wrongsourcebase'] = 'Feil kilde URL base';
 $string['wrongzipfilename'] = 'Galt ZIP-filnavn.';
diff --git a/install/lang/no/install.php b/install/lang/no/install.php
index bd29cd8..e414a2a 100644
--- a/install/lang/no/install.php
+++ b/install/lang/no/install.php
@@ -72,7 +72,7 @@ $string['pathssubwwwroot'] = 'Full webadresse til der hvor Moodle skal vises. De
 Dersom adressen ikke er korrekt, vennligst endre URL i nettleseren slik at at installasjonen restartes med andre verdier.';
 $string['pathsunsecuredataroot'] = 'Dataroot plassering er ikke sikker';
 $string['pathswrongadmindir'] = 'Adminkatalog finnes ikke';
-$string['phpextension'] = '{$a} PHP etternavn';
+$string['phpextension'] = '{$a} PHP-tillegg';
 $string['phpversion'] = 'PHP versjon';
 $string['phpversionhelp'] = '<p>Moodle trenger en PHP versjon minst 4.3.0 eller 5.1.0 (5.0.x har rekke kjente problem).</p>
 <Du kjører nå versjon {$a}</p>
-- 
1.7.9.5


From ce44bf44411b2486dcf93756603f0c148ea3771c Mon Sep 17 00:00:00 2001
From: Dan Poltawski <dan@moodle.com>
Date: Fri, 9 Nov 2012 17:58:34 +0800
Subject: [PATCH 900/903] weekly release 2.3.2+

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 083bdd1..1324d61 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.10;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.11;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121101)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121109)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From ff63a3ad58dd985e27279e3495b0d85b23584a54 Mon Sep 17 00:00:00 2001
From: "Eloy Lafuente (stronk7)" <stronk7@moodle.org>
Date: Fri, 9 Nov 2012 19:35:55 +0100
Subject: [PATCH 901/903] Moodle release 2.3.3

---
 version.php |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/version.php b/version.php
index 1324d61..295fdcc 100644
--- a/version.php
+++ b/version.php
@@ -30,11 +30,11 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.11;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062503.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121109)'; // Human-friendly version name
+$release  = '2.3.3 (Build: 20121112)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
-- 
1.7.9.5


From 15e90e20fe9410dae1e1dfe2b91690322fff3fef Mon Sep 17 00:00:00 2001
From: root <root@ELPortatilU.(none)>
Date: Thu, 3 Jan 2013 13:59:47 +0100
Subject: [PATCH 902/903] f1 upload

---
 0 files changed
 create mode 100644 f1

diff --git a/f1 b/f1
new file mode 100644
index 0000000..e69de29
-- 
1.7.9.5


From 99c707af74243675733be9e7ada8ba266780a5f1 Mon Sep 17 00:00:00 2001
From: root <root@ELPortatilU.(none)>
Date: Thu, 3 Jan 2013 16:13:03 +0100
Subject: [PATCH 903/903] Subida EvaluateMe

---
 course/modedit.php                  |   10 +-
 mod/feedback/edit.php               |   54 +-
 mod/feedback/import4.php            |  922 +++++++++++++++++++++++++++++++++++
 mod/feedback/mod_formEvaluateMe.php |  236 +++++++++
 mod/feedback/pix/icon.gif           |  Bin 107 -> 107 bytes
 mod/feedback/pix/multichoice/0.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/1.gif  |  Bin 43 -> 43 bytes
 mod/feedback/pix/multichoice/2.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/3.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/4.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/5.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/6.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/7.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/8.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/multichoice/9.gif  |  Bin 35 -> 35 bytes
 mod/feedback/pix/notrequired.gif    |  Bin 143 -> 143 bytes
 mod/feedback/pix/required.gif       |  Bin 217 -> 217 bytes
 17 files changed, 1219 insertions(+), 3 deletions(-)
 mode change 100644 => 100755 course/category.php
 mode change 100644 => 100755 course/changenumsections.php
 mode change 100644 => 100755 course/completion.js
 mode change 100644 => 100755 course/completion.php
 mode change 100644 => 100755 course/completion_form.php
 mode change 100644 => 100755 course/delete.php
 mode change 100644 => 100755 course/delete_category_form.php
 mode change 100644 => 100755 course/dndupload.js
 mode change 100644 => 100755 course/dndupload.php
 mode change 100644 => 100755 course/dnduploadlib.php
 mode change 100644 => 100755 course/edit.php
 mode change 100644 => 100755 course/edit_form.php
 mode change 100644 => 100755 course/editcategory.php
 mode change 100644 => 100755 course/editcategory_form.php
 mode change 100644 => 100755 course/editsection.php
 mode change 100644 => 100755 course/editsection_form.php
 mode change 100644 => 100755 course/enrol.php
 mode change 100644 => 100755 course/externallib.php
 mode change 100644 => 100755 course/format/README.txt
 mode change 100644 => 100755 course/format/renderer.php
 mode change 100644 => 100755 course/format/scorm/config.php
 mode change 100644 => 100755 course/format/scorm/format.php
 mode change 100644 => 100755 course/format/scorm/lang/en/format_scorm.php
 mode change 100644 => 100755 course/format/scorm/lib.php
 mode change 100644 => 100755 course/format/scorm/version.php
 mode change 100644 => 100755 course/format/social/config.php
 mode change 100644 => 100755 course/format/social/format.php
 mode change 100644 => 100755 course/format/social/lang/en/format_social.php
 mode change 100644 => 100755 course/format/social/lib.php
 mode change 100644 => 100755 course/format/social/version.php
 mode change 100644 => 100755 course/format/topics/config.php
 mode change 100644 => 100755 course/format/topics/format.js
 mode change 100644 => 100755 course/format/topics/format.php
 mode change 100644 => 100755 course/format/topics/lang/en/format_topics.php
 mode change 100644 => 100755 course/format/topics/lib.php
 mode change 100644 => 100755 course/format/topics/renderer.php
 mode change 100644 => 100755 course/format/topics/styles.css
 mode change 100644 => 100755 course/format/topics/version.php
 mode change 100644 => 100755 course/format/upgrade.txt
 mode change 100644 => 100755 course/format/weeks/config.php
 mode change 100644 => 100755 course/format/weeks/format.js
 mode change 100644 => 100755 course/format/weeks/format.php
 mode change 100644 => 100755 course/format/weeks/lang/en/format_weeks.php
 mode change 100644 => 100755 course/format/weeks/lib.php
 mode change 100644 => 100755 course/format/weeks/renderer.php
 mode change 100644 => 100755 course/format/weeks/styles.css
 mode change 100644 => 100755 course/format/weeks/version.php
 mode change 100644 => 100755 course/index.php
 mode change 100644 => 100755 course/info.php
 mode change 100644 => 100755 course/jumpto.php
 mode change 100644 => 100755 course/lib.php
 mode change 100644 => 100755 course/loginas.php
 mode change 100644 => 100755 course/mod.php
 mode change 100644 => 100755 course/modduplicate.php
 mode change 100644 => 100755 course/modedit.php
 mode change 100644 => 100755 course/moodleform_mod.php
 mode change 100644 => 100755 course/pending.php
 mode change 100644 => 100755 course/publish/backup.php
 mode change 100644 => 100755 course/publish/forms.php
 mode change 100644 => 100755 course/publish/hubselector.php
 mode change 100644 => 100755 course/publish/index.php
 mode change 100644 => 100755 course/publish/lib.php
 mode change 100644 => 100755 course/publish/metadata.php
 mode change 100644 => 100755 course/publish/renderer.php
 mode change 100644 => 100755 course/recent.php
 mode change 100644 => 100755 course/recent_form.php
 mode change 100644 => 100755 course/renderer.php
 mode change 100644 => 100755 course/report.php
 mode change 100644 => 100755 course/report/lib.php
 mode change 100644 => 100755 course/request.php
 mode change 100644 => 100755 course/request_form.php
 mode change 100644 => 100755 course/reset.php
 mode change 100644 => 100755 course/reset_form.php
 mode change 100644 => 100755 course/resources.php
 mode change 100644 => 100755 course/rest.php
 mode change 100644 => 100755 course/scales.php
 mode change 100644 => 100755 course/search.php
 mode change 100644 => 100755 course/style.css
 mode change 100644 => 100755 course/switchrole.php
 mode change 100644 => 100755 course/tests/courselib_test.php
 mode change 100644 => 100755 course/tests/externallib_test.php
 mode change 100644 => 100755 course/togglecompletion.php
 mode change 100644 => 100755 course/user.php
 mode change 100644 => 100755 course/view.php
 mode change 100644 => 100755 course/yui/coursebase/coursebase.js
 mode change 100644 => 100755 course/yui/dragdrop/dragdrop.js
 mode change 100644 => 100755 course/yui/modchooser/modchooser.js
 mode change 100644 => 100755 course/yui/toolboxes/toolboxes.js
 mode change 100644 => 100755 mod/feedback/README.txt
 mode change 100644 => 100755 mod/feedback/TODO.txt
 mode change 100644 => 100755 mod/feedback/analysis.php
 mode change 100644 => 100755 mod/feedback/analysis_course.php
 mode change 100644 => 100755 mod/feedback/analysis_to_excel.php
 mode change 100644 => 100755 mod/feedback/backup/moodle1/lib.php
 mode change 100644 => 100755 mod/feedback/backup/moodle2/backup_feedback_activity_task.class.php
 mode change 100644 => 100755 mod/feedback/backup/moodle2/backup_feedback_settingslib.php
 mode change 100644 => 100755 mod/feedback/backup/moodle2/backup_feedback_stepslib.php
 mode change 100644 => 100755 mod/feedback/backup/moodle2/restore_feedback_activity_task.class.php
 mode change 100644 => 100755 mod/feedback/backup/moodle2/restore_feedback_stepslib.php
 mode change 100644 => 100755 mod/feedback/choose_group_form.php
 mode change 100644 => 100755 mod/feedback/complete.php
 mode change 100644 => 100755 mod/feedback/complete_guest.php
 mode change 100644 => 100755 mod/feedback/db/access.php
 mode change 100644 => 100755 mod/feedback/db/install.php
 mode change 100644 => 100755 mod/feedback/db/install.xml
 mode change 100644 => 100755 mod/feedback/db/log.php
 mode change 100644 => 100755 mod/feedback/db/messages.php
 mode change 100644 => 100755 mod/feedback/db/upgrade.php
 mode change 100644 => 100755 mod/feedback/delete_completed.php
 mode change 100644 => 100755 mod/feedback/delete_completed_form.php
 mode change 100644 => 100755 mod/feedback/delete_item.php
 mode change 100644 => 100755 mod/feedback/delete_item_form.php
 mode change 100644 => 100755 mod/feedback/delete_template.php
 mode change 100644 => 100755 mod/feedback/delete_template_form.php
 mode change 100644 => 100755 mod/feedback/edit.php
 mode change 100644 => 100755 mod/feedback/edit_form.php
 mode change 100644 => 100755 mod/feedback/edit_item.php
 mode change 100644 => 100755 mod/feedback/export.php
 mode change 100644 => 100755 mod/feedback/feedback.js
 mode change 100644 => 100755 mod/feedback/import.php
 create mode 100755 mod/feedback/import4.php
 mode change 100644 => 100755 mod/feedback/import_form.php
 mode change 100644 => 100755 mod/feedback/index.php
 mode change 100644 => 100755 mod/feedback/item/captcha/captcha_form.php
 mode change 100644 => 100755 mod/feedback/item/captcha/lib.php
 mode change 100644 => 100755 mod/feedback/item/captcha/print_captcha.php
 mode change 100644 => 100755 mod/feedback/item/feedback_item_class.php
 mode change 100644 => 100755 mod/feedback/item/feedback_item_form_class.php
 mode change 100644 => 100755 mod/feedback/item/info/info_form.php
 mode change 100644 => 100755 mod/feedback/item/info/lib.php
 mode change 100644 => 100755 mod/feedback/item/label/label_form.php
 mode change 100644 => 100755 mod/feedback/item/label/lib.php
 mode change 100644 => 100755 mod/feedback/item/multichoice/lib.php
 mode change 100644 => 100755 mod/feedback/item/multichoice/multichoice_form.php
 mode change 100644 => 100755 mod/feedback/item/multichoicerated/lib.php
 mode change 100644 => 100755 mod/feedback/item/multichoicerated/multichoicerated_form.php
 mode change 100644 => 100755 mod/feedback/item/numeric/lib.php
 mode change 100644 => 100755 mod/feedback/item/numeric/numeric_form.php
 mode change 100644 => 100755 mod/feedback/item/textarea/lib.php
 mode change 100644 => 100755 mod/feedback/item/textarea/textarea_form.php
 mode change 100644 => 100755 mod/feedback/item/textfield/lib.php
 mode change 100644 => 100755 mod/feedback/item/textfield/textfield_form.php
 mode change 100644 => 100755 mod/feedback/lang/en/feedback.php
 mode change 100644 => 100755 mod/feedback/lib.php
 mode change 100644 => 100755 mod/feedback/mapcourse.php
 mode change 100644 => 100755 mod/feedback/mod_form.php
 create mode 100755 mod/feedback/mod_formEvaluateMe.php
 mode change 100644 => 100755 mod/feedback/pix/icon.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/0.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/1.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/2.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/3.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/4.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/5.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/6.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/7.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/8.gif
 mode change 100644 => 100755 mod/feedback/pix/multichoice/9.gif
 mode change 100644 => 100755 mod/feedback/pix/notrequired.gif
 mode change 100644 => 100755 mod/feedback/pix/required.gif
 mode change 100644 => 100755 mod/feedback/print.php
 mode change 100644 => 100755 mod/feedback/settings.php
 mode change 100644 => 100755 mod/feedback/show_entries.php
 mode change 100644 => 100755 mod/feedback/show_entries_anonym.php
 mode change 100644 => 100755 mod/feedback/show_nonrespondents.php
 mode change 100644 => 100755 mod/feedback/styles.css
 mode change 100644 => 100755 mod/feedback/tabs.php
 mode change 100644 => 100755 mod/feedback/unmapcourse.php
 mode change 100644 => 100755 mod/feedback/use_templ.php
 mode change 100644 => 100755 mod/feedback/use_templ_form.php
 mode change 100644 => 100755 mod/feedback/version.php
 mode change 100644 => 100755 mod/feedback/view.php

diff --git a/course/category.php b/course/category.php
old mode 100644
new mode 100755
diff --git a/course/changenumsections.php b/course/changenumsections.php
old mode 100644
new mode 100755
diff --git a/course/completion.js b/course/completion.js
old mode 100644
new mode 100755
diff --git a/course/completion.php b/course/completion.php
old mode 100644
new mode 100755
diff --git a/course/completion_form.php b/course/completion_form.php
old mode 100644
new mode 100755
diff --git a/course/delete.php b/course/delete.php
old mode 100644
new mode 100755
diff --git a/course/delete_category_form.php b/course/delete_category_form.php
old mode 100644
new mode 100755
diff --git a/course/dndupload.js b/course/dndupload.js
old mode 100644
new mode 100755
diff --git a/course/dndupload.php b/course/dndupload.php
old mode 100644
new mode 100755
diff --git a/course/dnduploadlib.php b/course/dnduploadlib.php
old mode 100644
new mode 100755
diff --git a/course/edit.php b/course/edit.php
old mode 100644
new mode 100755
diff --git a/course/edit_form.php b/course/edit_form.php
old mode 100644
new mode 100755
diff --git a/course/editcategory.php b/course/editcategory.php
old mode 100644
new mode 100755
diff --git a/course/editcategory_form.php b/course/editcategory_form.php
old mode 100644
new mode 100755
diff --git a/course/editsection.php b/course/editsection.php
old mode 100644
new mode 100755
diff --git a/course/editsection_form.php b/course/editsection_form.php
old mode 100644
new mode 100755
diff --git a/course/enrol.php b/course/enrol.php
old mode 100644
new mode 100755
diff --git a/course/externallib.php b/course/externallib.php
old mode 100644
new mode 100755
diff --git a/course/format/README.txt b/course/format/README.txt
old mode 100644
new mode 100755
diff --git a/course/format/renderer.php b/course/format/renderer.php
old mode 100644
new mode 100755
diff --git a/course/format/scorm/config.php b/course/format/scorm/config.php
old mode 100644
new mode 100755
diff --git a/course/format/scorm/format.php b/course/format/scorm/format.php
old mode 100644
new mode 100755
diff --git a/course/format/scorm/lang/en/format_scorm.php b/course/format/scorm/lang/en/format_scorm.php
old mode 100644
new mode 100755
diff --git a/course/format/scorm/lib.php b/course/format/scorm/lib.php
old mode 100644
new mode 100755
diff --git a/course/format/scorm/version.php b/course/format/scorm/version.php
old mode 100644
new mode 100755
diff --git a/course/format/social/config.php b/course/format/social/config.php
old mode 100644
new mode 100755
diff --git a/course/format/social/format.php b/course/format/social/format.php
old mode 100644
new mode 100755
diff --git a/course/format/social/lang/en/format_social.php b/course/format/social/lang/en/format_social.php
old mode 100644
new mode 100755
diff --git a/course/format/social/lib.php b/course/format/social/lib.php
old mode 100644
new mode 100755
diff --git a/course/format/social/version.php b/course/format/social/version.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/config.php b/course/format/topics/config.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/format.js b/course/format/topics/format.js
old mode 100644
new mode 100755
diff --git a/course/format/topics/format.php b/course/format/topics/format.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/lang/en/format_topics.php b/course/format/topics/lang/en/format_topics.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/lib.php b/course/format/topics/lib.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/renderer.php b/course/format/topics/renderer.php
old mode 100644
new mode 100755
diff --git a/course/format/topics/styles.css b/course/format/topics/styles.css
old mode 100644
new mode 100755
diff --git a/course/format/topics/version.php b/course/format/topics/version.php
old mode 100644
new mode 100755
diff --git a/course/format/upgrade.txt b/course/format/upgrade.txt
old mode 100644
new mode 100755
diff --git a/course/format/weeks/config.php b/course/format/weeks/config.php
old mode 100644
new mode 100755
diff --git a/course/format/weeks/format.js b/course/format/weeks/format.js
old mode 100644
new mode 100755
diff --git a/course/format/weeks/format.php b/course/format/weeks/format.php
old mode 100644
new mode 100755
diff --git a/course/format/weeks/lang/en/format_weeks.php b/course/format/weeks/lang/en/format_weeks.php
old mode 100644
new mode 100755
diff --git a/course/format/weeks/lib.php b/course/format/weeks/lib.php
old mode 100644
new mode 100755
diff --git a/course/format/weeks/renderer.php b/course/format/weeks/renderer.php
old mode 100644
new mode 100755
diff --git a/course/format/weeks/styles.css b/course/format/weeks/styles.css
old mode 100644
new mode 100755
diff --git a/course/format/weeks/version.php b/course/format/weeks/version.php
old mode 100644
new mode 100755
diff --git a/course/index.php b/course/index.php
old mode 100644
new mode 100755
diff --git a/course/info.php b/course/info.php
old mode 100644
new mode 100755
diff --git a/course/jumpto.php b/course/jumpto.php
old mode 100644
new mode 100755
diff --git a/course/lib.php b/course/lib.php
old mode 100644
new mode 100755
diff --git a/course/loginas.php b/course/loginas.php
old mode 100644
new mode 100755
diff --git a/course/mod.php b/course/mod.php
old mode 100644
new mode 100755
diff --git a/course/modduplicate.php b/course/modduplicate.php
old mode 100644
new mode 100755
diff --git a/course/modedit.php b/course/modedit.php
old mode 100644
new mode 100755
index 7aa8667..72773f8
--- a/course/modedit.php
+++ b/course/modedit.php
@@ -36,6 +36,7 @@ $update = optional_param('update', 0, PARAM_INT);
 $return = optional_param('return', 0, PARAM_BOOL);    //return to course/view.php if false or mod/modname/view.php if true
 $type   = optional_param('type', '', PARAM_ALPHANUM); //TODO: hopefully will be removed in 2.0
 $sectionreturn = optional_param('sr', null, PARAM_INT);
+$nameEvaluateMe  = optional_param('name', '', PARAM_TEXT);
 
 $url = new moodle_url('/course/modedit.php');
 $url->param('sr', $sectionreturn);
@@ -82,11 +83,13 @@ if (!empty($add)) {
     $data->add              = $add;
     $data->return           = 0; //must be false if this is an add, go back to course view on cancel
     $data->sr               = $sectionreturn;
+	    if (!empty($nameEvaluateMe)) $data->name = $nameEvaluateMe;    
 
     if (plugin_supports('mod', $data->modulename, FEATURE_MOD_INTRO, true)) {
         $draftid_editor = file_get_submitted_draft_itemid('introeditor');
         file_prepare_draft_area($draftid_editor, null, null, null, null);
-        $data->introeditor = array('text'=>'', 'format'=>FORMAT_HTML, 'itemid'=>$draftid_editor); // TODO: add better default
+       if (!empty($nameEvaluateMe))  $data->introeditor = array('text'=>'Introduce una descripcion', 'format'=>FORMAT_HTML, 'itemid'=>$draftid_editor); // TODO: add better default
+        else $data->introeditor = array('text'=>'', 'format'=>FORMAT_HTML, 'itemid'=>$draftid_editor); // TODO: add better default
     }
 
     if (plugin_supports('mod', $data->modulename, FEATURE_ADVANCED_GRADING, false)
@@ -242,7 +245,10 @@ if (!empty($type)) { //TODO: hopefully will be removed in 2.0
 $PAGE->set_pagetype($pagepath);
 $PAGE->set_pagelayout('admin');
 
-$modmoodleform = "$CFG->dirroot/mod/$module->name/mod_form.php";
+//Cambio de formulario para que no aparezca el nombre
+if (!empty($nameEvaluateMe) and $add == 'feedback' ) $modmoodleform = "$CFG->dirroot/mod/$module->name/mod_formEvaluateMe.php";
+else $modmoodleform = "$CFG->dirroot/mod/$module->name/mod_form.php";
+
 if (file_exists($modmoodleform)) {
     require_once($modmoodleform);
 } else {
diff --git a/course/moodleform_mod.php b/course/moodleform_mod.php
old mode 100644
new mode 100755
diff --git a/course/pending.php b/course/pending.php
old mode 100644
new mode 100755
diff --git a/course/publish/backup.php b/course/publish/backup.php
old mode 100644
new mode 100755
diff --git a/course/publish/forms.php b/course/publish/forms.php
old mode 100644
new mode 100755
diff --git a/course/publish/hubselector.php b/course/publish/hubselector.php
old mode 100644
new mode 100755
diff --git a/course/publish/index.php b/course/publish/index.php
old mode 100644
new mode 100755
diff --git a/course/publish/lib.php b/course/publish/lib.php
old mode 100644
new mode 100755
diff --git a/course/publish/metadata.php b/course/publish/metadata.php
old mode 100644
new mode 100755
diff --git a/course/publish/renderer.php b/course/publish/renderer.php
old mode 100644
new mode 100755
diff --git a/course/recent.php b/course/recent.php
old mode 100644
new mode 100755
diff --git a/course/recent_form.php b/course/recent_form.php
old mode 100644
new mode 100755
diff --git a/course/renderer.php b/course/renderer.php
old mode 100644
new mode 100755
diff --git a/course/report.php b/course/report.php
old mode 100644
new mode 100755
diff --git a/course/report/lib.php b/course/report/lib.php
old mode 100644
new mode 100755
diff --git a/course/request.php b/course/request.php
old mode 100644
new mode 100755
diff --git a/course/request_form.php b/course/request_form.php
old mode 100644
new mode 100755
diff --git a/course/reset.php b/course/reset.php
old mode 100644
new mode 100755
diff --git a/course/reset_form.php b/course/reset_form.php
old mode 100644
new mode 100755
diff --git a/course/resources.php b/course/resources.php
old mode 100644
new mode 100755
diff --git a/course/rest.php b/course/rest.php
old mode 100644
new mode 100755
diff --git a/course/scales.php b/course/scales.php
old mode 100644
new mode 100755
diff --git a/course/search.php b/course/search.php
old mode 100644
new mode 100755
diff --git a/course/style.css b/course/style.css
old mode 100644
new mode 100755
diff --git a/course/switchrole.php b/course/switchrole.php
old mode 100644
new mode 100755
diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php
old mode 100644
new mode 100755
diff --git a/course/tests/externallib_test.php b/course/tests/externallib_test.php
old mode 100644
new mode 100755
diff --git a/course/togglecompletion.php b/course/togglecompletion.php
old mode 100644
new mode 100755
diff --git a/course/user.php b/course/user.php
old mode 100644
new mode 100755
diff --git a/course/view.php b/course/view.php
old mode 100644
new mode 100755
diff --git a/course/yui/coursebase/coursebase.js b/course/yui/coursebase/coursebase.js
old mode 100644
new mode 100755
diff --git a/course/yui/dragdrop/dragdrop.js b/course/yui/dragdrop/dragdrop.js
old mode 100644
new mode 100755
diff --git a/course/yui/modchooser/modchooser.js b/course/yui/modchooser/modchooser.js
old mode 100644
new mode 100755
diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js
old mode 100644
new mode 100755
diff --git a/mod/feedback/README.txt b/mod/feedback/README.txt
old mode 100644
new mode 100755
diff --git a/mod/feedback/TODO.txt b/mod/feedback/TODO.txt
old mode 100644
new mode 100755
diff --git a/mod/feedback/analysis.php b/mod/feedback/analysis.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/analysis_course.php b/mod/feedback/analysis_course.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/analysis_to_excel.php b/mod/feedback/analysis_to_excel.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle1/lib.php b/mod/feedback/backup/moodle1/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle2/backup_feedback_activity_task.class.php b/mod/feedback/backup/moodle2/backup_feedback_activity_task.class.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle2/backup_feedback_settingslib.php b/mod/feedback/backup/moodle2/backup_feedback_settingslib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle2/backup_feedback_stepslib.php b/mod/feedback/backup/moodle2/backup_feedback_stepslib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle2/restore_feedback_activity_task.class.php b/mod/feedback/backup/moodle2/restore_feedback_activity_task.class.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/backup/moodle2/restore_feedback_stepslib.php b/mod/feedback/backup/moodle2/restore_feedback_stepslib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/choose_group_form.php b/mod/feedback/choose_group_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/complete.php b/mod/feedback/complete.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/complete_guest.php b/mod/feedback/complete_guest.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/access.php b/mod/feedback/db/access.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/install.php b/mod/feedback/db/install.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/install.xml b/mod/feedback/db/install.xml
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/log.php b/mod/feedback/db/log.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/messages.php b/mod/feedback/db/messages.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/db/upgrade.php b/mod/feedback/db/upgrade.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_completed.php b/mod/feedback/delete_completed.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_completed_form.php b/mod/feedback/delete_completed_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_item.php b/mod/feedback/delete_item.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_item_form.php b/mod/feedback/delete_item_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_template.php b/mod/feedback/delete_template.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/delete_template_form.php b/mod/feedback/delete_template_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/edit.php b/mod/feedback/edit.php
old mode 100644
new mode 100755
index ce0e245..9a88d5e
--- a/mod/feedback/edit.php
+++ b/mod/feedback/edit.php
@@ -208,13 +208,65 @@ if ($do_show == 'templates') {
         echo '&nbsp;';
     }
 
+//////
+
+            $idcourse = $COURSE->id;
+            
+            $feedbackNameTeachers = 'evaluation teachers';
+            $feedbackNameActivities = 'evaluation activities';
+            $feedbackNameSubject = 'evaluation subject';
+            
+            $existFeedbackTeachers = FALSE;
+            $existFeedbackActivities = FALSE;
+            $existFeedbackSubject = FALSE;
+            
+
+	    $feedbacks = get_all_instances_in_course("feedback", $COURSE);
+            foreach ($feedbacks as $feedback){
+		$viewurl = new moodle_url('/mod/feedback/view.php', array('id'=>$feedback->coursemodule));
+
+
+                
+                if ($feedbackNameTeachers == $feedback->name){
+                    $existFeedbackTeachers = TRUE;
+		    $preid= (explode("=", $viewurl->out()));
+		    $idTeachers = $preid[1];
+		    if ($idTeachers == $id){
+			$TipoDeForm=3;
+		     }
+
+                }
+                
+                if ($feedbackNameActivities == $feedback->name){
+                    $existFeedbackActivities = TRUE;
+		    $preid= (explode("=", $viewurl->out()));
+		    $idActivities = $preid[1];
+		    if ($idActivities == $id){
+			$TipoDeForm=1;
+		     }
+                }
+                
+                if ($feedbackNameSubject == $feedback->name){
+                    $existFeedbackSubject = TRUE;
+		    $preid= (explode("=", $viewurl->out()));
+		    $idNameSubject= $preid[1];
+		    if ($idNameSubject == $id){
+			$TipoDeForm=2;
+		     }
+                }
+            }
+///////
+
     if (has_capability('mod/feedback:edititems', $context)) {
         $urlparams = array('action'=>'exportfile', 'id'=>$id);
         $exporturl = new moodle_url('/mod/feedback/export.php', $urlparams);
         $importurl = new moodle_url('/mod/feedback/import.php', array('id'=>$id));
+        $alexguapourl = new moodle_url('/mod/feedback/import4.php?id='.$id.'&TipoDeForm='.$TipoDeForm, $urlparams);
+/////http://localhost/moodle/mod/feedback/import4.php?id=40
         echo '<p>
             <a href="'.$exporturl->out().'">'.get_string('export_questions', 'feedback').'</a>/
-            <a href="'.$importurl->out().'">'.get_string('import_questions', 'feedback').'</a>
+            <a href="'.$importurl->out().'">'.get_string('import_questions', 'feedback').'</a>/ 
+            <a href="'.$alexguapourl->out().'">Import EvaluateMe</a>
         </p>';
     }
     echo $OUTPUT->box_end();
diff --git a/mod/feedback/edit_form.php b/mod/feedback/edit_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/edit_item.php b/mod/feedback/edit_item.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/export.php b/mod/feedback/export.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/feedback.js b/mod/feedback/feedback.js
old mode 100644
new mode 100755
diff --git a/mod/feedback/import.php b/mod/feedback/import.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/import4.php b/mod/feedback/import4.php
new file mode 100755
index 0000000..1b3a3c7
--- /dev/null
+++ b/mod/feedback/import4.php
@@ -0,0 +1,922 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * prints the form to import items from xml-file
+ *
+ * @author Andreas Grabs
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package feedback
+ */
+
+require_once("../../config.php");
+require_once("lib.php");
+require_once('import_form.php');
+
+
+// get parameters
+$id = required_param('id', PARAM_INT);
+$choosefile = optional_param('choosefile', false, PARAM_PATH);
+$action = optional_param('action', false, PARAM_ALPHA);
+
+$TipoDeForm = required_param('TipoDeForm', PARAM_INT); // Cual de los 3 forms es?
+
+
+$url = new moodle_url('/mod/feedback/import.php', array('id'=>$id));
+if ($choosefile !== false) {
+    $url->param('choosefile', $choosefile);
+}
+if ($action !== false) {
+    $url->param('action', $action);
+}
+$PAGE->set_url($url);
+
+if (! $cm = get_coursemodule_from_id('feedback', $id)) {
+    print_error('invalidcoursemodule');
+}
+
+if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
+    print_error('coursemisconf');
+}
+
+if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
+    print_error('invalidcoursemodule');
+}
+
+if (!$context = get_context_instance(CONTEXT_MODULE, $cm->id)) {
+    print_error('badcontext');
+}
+
+require_login($course, true, $cm);
+
+require_capability('mod/feedback:edititems', $context);
+/////////////////////////////////////  
+    require_once($CFG->libdir.'/tablelib.php');
+    require_once($CFG->libdir.'/filelib.php');
+
+    define('USER_SMALL_CLASS', 20);   // Below this is considered small
+    define('USER_LARGE_CLASS', 200);  // Above this is considered large
+    define('DEFAULT_PAGE_SIZE', 20);
+    define('SHOW_ALL_PAGE_SIZE', 5000);
+    define('MODE_BRIEF', 0);
+    define('MODE_USERDETAILS', 1);
+
+    $page         = optional_param('page', 0, PARAM_INT);                     // which page to show
+    $perpage      = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT);  // how many per page
+    $mode         = optional_param('mode', NULL, PARAM_INT);                  // use the MODE_ constants
+    $accesssince  = optional_param('accesssince',0,PARAM_INT);                // filter by last access. -1 = never
+    $search       = optional_param('search','',PARAM_RAW);                    // make sure it is processed with p() or s() when sending to output!
+    $roleid       = 3;
+
+    $contextid    = optional_param('contextid', 0, PARAM_INT);                // one of this or
+    $courseid     = optional_param('id', 0, PARAM_INT);                       // this are required
+
+    $PAGE->set_url('/user/index.php', array(
+            'page' => $page,
+            'perpage' => $perpage,
+            'mode' => $mode,
+            'accesssince' => $accesssince,
+            'search' => $search,
+            'roleid' => $roleid,
+            'contextid' => $contextid,
+            'id' => $courseid));
+
+    if ($contextid) {
+        $context = get_context_instance_by_id($contextid, MUST_EXIST);
+        if ($context->contextlevel != CONTEXT_COURSE) {
+            print_error('invalidcontext');
+        }
+        $course = $DB->get_record('course', array('id'=>$context->instanceid), '*', MUST_EXIST);
+    } else {
+        $course2 = $course;
+        $context2 = get_context_instance(CONTEXT_COURSE, $course2->id, MUST_EXIST);
+    }
+    // not needed anymore
+    unset($contextid);
+    unset($courseid);
+
+    require_login($course);
+
+    $systemcontext = get_context_instance(CONTEXT_SYSTEM);
+    $isfrontpage = ($course->id == SITEID);
+
+    $frontpagectx = get_context_instance(CONTEXT_COURSE, SITEID);
+
+    if ($isfrontpage) {
+        $PAGE->set_pagelayout('admin');
+        require_capability('moodle/site:viewparticipants', $systemcontext);
+    } else {
+        $PAGE->set_pagelayout('incourse');
+        require_capability('moodle/course:viewparticipants', $context);
+    }
+
+    $rolenamesurl = new moodle_url("$CFG->wwwroot/user/index.php?contextid=$context->id&sifirst=&silast=");
+
+    $allroles = get_all_roles();
+    $roles = get_profile_roles($context);
+    $allrolenames = array();
+    if ($isfrontpage) {
+        $rolenames = array(0=>get_string('allsiteusers', 'role'));
+    } else {
+        $rolenames = array(0=>get_string('allparticipants'));
+    }
+
+    foreach ($allroles as $role) {
+        $allrolenames[$role->id] = strip_tags(role_get_name($role, $context2));   // Used in menus etc later on
+        if (isset($roles[$role->id])) {
+            $rolenames[$role->id] = $allrolenames[$role->id];
+        }
+    }
+
+    // make sure other roles may not be selected by any means
+    if (empty($rolenames[$roleid])) {
+        print_error('noparticipants');
+    }
+
+    // no roles to display yet?
+    // frontpage course is an exception, on the front page course we should display all users
+    if (empty($rolenames) && !$isfrontpage) {
+        if (has_capability('moodle/role:assign', $context)) {
+            redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id);
+        } else {
+            print_error('noparticipants');
+        }
+    }
+
+    add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, '');
+
+    $bulkoperations = has_capability('moodle/course:bulkmessaging', $context);
+
+    $countries = get_string_manager()->get_list_of_countries();
+
+    $strnever = get_string('never');
+
+    $datestring = new stdClass();
+    $datestring->year  = get_string('year');
+    $datestring->years = get_string('years');
+    $datestring->day   = get_string('day');
+    $datestring->days  = get_string('days');
+    $datestring->hour  = get_string('hour');
+    $datestring->hours = get_string('hours');
+    $datestring->min   = get_string('min');
+    $datestring->mins  = get_string('mins');
+    $datestring->sec   = get_string('sec');
+    $datestring->secs  = get_string('secs');
+
+    if ($mode !== NULL) {
+        $mode = (int)$mode;
+        $SESSION->userindexmode = $mode;
+    } else if (isset($SESSION->userindexmode)) {
+        $mode = (int)$SESSION->userindexmode;
+    } else {
+        $mode = MODE_BRIEF;
+    }
+
+/// Check to see if groups are being used in this course
+/// and if so, set $currentgroup to reflect the current group
+
+    $groupmode    = groups_get_course_groupmode($course);   // Groups are being used
+    $currentgroup = groups_get_course_group($course, true);
+
+    if (!$currentgroup) {      // To make some other functions work better later
+        $currentgroup  = NULL;
+    }
+
+    $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
+
+    $PAGE->set_title("$course->shortname: ".get_string('participants'));
+    $PAGE->set_heading($course->fullname);
+    $PAGE->set_pagetype('course-view-' . $course->format);
+    $PAGE->add_body_class('path-user');                     // So we can style it independently
+    $PAGE->set_other_editing_capability('moodle/course:manageactivities');
+
+//    echo $OUTPUT->header();
+
+  //  echo '<div class="userlist">';
+
+    if ($isseparategroups and (!$currentgroup) ) {
+        // The user is not in the group so show message and exit
+      //  echo $OUTPUT->heading(get_string("notingroup"));
+       // echo $OUTPUT->footer();
+        exit;
+    }
+
+
+    // Should use this variable so that we don't break stuff every time a variable is added or changed.
+    $baseurl = new moodle_url('/user/index.php', array(
+            'contextid' => $context->id,
+            'roleid' => $roleid,
+            'id' => $course->id,
+            'perpage' => $perpage,
+            'accesssince' => $accesssince,
+            'search' => s($search)));
+
+/// setting up tags
+    if ($course->id == SITEID) {
+        $filtertype = 'site';
+    } else if ($course->id && !$currentgroup) {
+        $filtertype = 'course';
+        $filterselect = $course->id;
+    } else {
+        $filtertype = 'group';
+        $filterselect = $currentgroup;
+    }
+
+
+
+/// Get the hidden field list
+    if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
+        $hiddenfields = array();  // teachers and admins are allowed to see everything
+    } else {
+        $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
+    }
+
+    if (isset($hiddenfields['lastaccess'])) {
+        // do not allow access since filtering
+        $accesssince = 0;
+    }
+
+/// Print settings and things in a table across the top
+    $controlstable = new html_table();
+    $controlstable->attributes['class'] = 'controls';
+    $controlstable->cellspacing = 0;
+    $controlstable->data[] = new html_table_row();
+
+/// Print my course menus
+    if ($mycourses = enrol_get_my_courses()) {
+        $courselist = array();
+        $popupurl = new moodle_url('/user/index.php?roleid='.$roleid.'&sifirst=&silast=');
+        foreach ($mycourses as $mycourse) {
+            $coursecontext = get_context_instance(CONTEXT_COURSE, $mycourse->id);
+            $courselist[$mycourse->id] = format_string($mycourse->shortname, true, array('context' => $coursecontext));
+        }
+        if (has_capability('moodle/site:viewparticipants', $systemcontext)) {
+            unset($courselist[SITEID]);
+            $courselist = array(SITEID => format_string($SITE->shortname, true, array('context' => $systemcontext))) + $courselist;
+        }
+        $select = new single_select($popupurl, 'id', $courselist, $course->id, array(''=>'choosedots'), 'courseform');
+        $select->set_label(get_string('mycourses'));
+        $controlstable->data[0]->cells[] = $OUTPUT->render($select);
+    }
+
+    $controlstable->data[0]->cells[] = groups_print_course_menu($course, $baseurl->out(), true);
+
+    if (!isset($hiddenfields['lastaccess'])) {
+        // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far.
+        // we need to make it diferently for normal courses and site course
+        if (!$isfrontpage) {
+            $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess)
+                                                   FROM {user_lastaccess}
+                                                  WHERE courseid = ?
+                                                        AND timeaccess != 0', array($course->id));
+            $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid'=>$course->id, 'timeaccess'=>0));
+        } else {
+            $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess)
+                                                   FROM {user}
+                                                  WHERE lastaccess != 0');
+            $lastaccess0exists = $DB->record_exists('user', array('lastaccess'=>0));
+        }
+
+        $now = usergetmidnight(time());
+        $timeaccess = array();
+        $baseurl->remove_params('accesssince');
+
+        // makes sense for this to go first.
+        $timeoptions[0] = get_string('selectperiod');
+
+        // days
+        for ($i = 1; $i < 7; $i++) {
+            if (strtotime('-'.$i.' days',$now) >= $minlastaccess) {
+                $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i);
+            }
+        }
+        // weeks
+        for ($i = 1; $i < 10; $i++) {
+            if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) {
+                $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i);
+            }
+        }
+        // months
+        for ($i = 2; $i < 12; $i++) {
+            if (strtotime('-'.$i.' months',$now) >= $minlastaccess) {
+                $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i);
+            }
+        }
+        // try a year
+        if (strtotime('-1 year',$now) >= $minlastaccess) {
+            $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear');
+        }
+
+        if (!empty($lastaccess0exists)) {
+            $timeoptions[-1] = get_string('never');
+        }
+
+        if (count($timeoptions) > 1) {
+            $select = new single_select($baseurl, 'accesssince', $timeoptions, $accesssince, null, 'timeoptions');
+            $select->set_label(get_string('usersnoaccesssince'));
+            $controlstable->data[0]->cells[] = $OUTPUT->render($select);
+        }
+    }
+
+    $formatmenu = array( '0' => get_string('brief'),
+                         '1' => get_string('userdetails'));
+    $select = new single_select($baseurl, 'mode', $formatmenu, $mode, null, 'formatmenu');
+    $select->set_label(get_string('userlist'));
+    $userlistcell = new html_table_cell();
+    $userlistcell->attributes['class'] = 'right';
+    $userlistcell->text = $OUTPUT->render($select);
+    $controlstable->data[0]->cells[] = $userlistcell;
+
+ //   echo html_writer::table($controlstable);
+
+    if ($currentgroup and (!$isseparategroups or has_capability('moodle/site:accessallgroups', $context))) {    /// Display info about the group
+        if ($group = groups_get_group($currentgroup)) {
+            if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) {
+                $groupinfotable = new html_table();
+                $groupinfotable->attributes['class'] = 'groupinfobox';
+                $picturecell = new html_table_cell();
+                $picturecell->attributes['class'] = 'left side picture';
+                $picturecell->text = print_group_picture($group, $course->id, true, true, false);
+
+                $contentcell = new html_table_cell();
+                $contentcell->attributes['class'] = 'content';
+
+                $contentheading = $group->name;
+                if (has_capability('moodle/course:managegroups', $context)) {
+                    $aurl = new moodle_url('/group/group.php', array('id' => $group->id, 'courseid' => $group->courseid));
+                    $contentheading .= '&nbsp;' . $OUTPUT->action_icon($aurl, new pix_icon('t/edit', get_string('editgroupprofile')));
+                }
+
+                $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id);
+                if (!isset($group->descriptionformat)) {
+                    $group->descriptionformat = FORMAT_MOODLE;
+                }
+                $options = array('overflowdiv'=>true);
+                $contentcell->text = $OUTPUT->heading($contentheading, 3) . format_text($group->description, $group->descriptionformat, $options);
+                $groupinfotable->data[] = new html_table_row(array($picturecell, $contentcell));
+                //echo html_writer::table($groupinfotable);
+            }
+        }
+    }
+
+    /// Define a table showing a list of users in the current role selection
+
+    $tablecolumns = array('userpic', 'fullname');
+    $extrafields = get_extra_user_fields($context);
+    $tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
+    if ($mode === MODE_BRIEF) {
+        foreach ($extrafields as $field) {
+            $tablecolumns[] = $field;
+            $tableheaders[] = get_user_field_name($field);
+        }
+    }
+    if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
+        $tablecolumns[] = 'city';
+        $tableheaders[] = get_string('city');
+    }
+    if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
+        $tablecolumns[] = 'country';
+        $tableheaders[] = get_string('country');
+    }
+    if (!isset($hiddenfields['lastaccess'])) {
+        $tablecolumns[] = 'lastaccess';
+        $tableheaders[] = get_string('lastaccess');
+    }
+
+    if ($bulkoperations) {
+        $tablecolumns[] = 'select';
+        $tableheaders[] = get_string('select');
+    }
+
+    $table = new flexible_table('user-index-participants-'.$course->id);
+    $table->define_columns($tablecolumns);
+    $table->define_headers($tableheaders);
+    $table->define_baseurl($baseurl->out());
+
+    if (!isset($hiddenfields['lastaccess'])) {
+        $table->sortable(true, 'lastaccess', SORT_DESC);
+    } else {
+        $table->sortable(true, 'firstname', SORT_ASC);
+    }
+
+    $table->no_sorting('roles');
+    $table->no_sorting('groups');
+    $table->no_sorting('groupings');
+    $table->no_sorting('select');
+
+    $table->set_attribute('cellspacing', '0');
+    $table->set_attribute('id', 'participants');
+    $table->set_attribute('class', 'generaltable generalbox');
+
+    $table->set_control_variables(array(
+                TABLE_VAR_SORT    => 'ssort',
+                TABLE_VAR_HIDE    => 'shide',
+                TABLE_VAR_SHOW    => 'sshow',
+                TABLE_VAR_IFIRST  => 'sifirst',
+                TABLE_VAR_ILAST   => 'silast',
+                TABLE_VAR_PAGE    => 'spage'
+                ));
+    $table->setup();
+
+    // we are looking for all users with this role assigned in this context or higher
+    $contextlist = get_related_contexts_string($context);
+
+    list($esql, $params) = get_enrolled_sql($context, NULL, $currentgroup, true);
+    $joins = array("FROM {user} u");
+    $wheres = array();
+
+    $extrasql = get_extra_user_fields_sql($context, 'u', '', array(
+            'id', 'username', 'firstname', 'lastname', 'email', 'city', 'country',
+            'picture', 'lang', 'timezone', 'maildisplay', 'imagealt', 'lastaccess'));
+
+    if ($isfrontpage) {
+        $select = "SELECT u.id, u.username, u.firstname, u.lastname,
+                          u.email, u.city, u.country, u.picture,
+                          u.lang, u.timezone, u.maildisplay, u.imagealt,
+                          u.lastaccess$extrasql";
+        $joins[] = "JOIN ($esql) e ON e.id = u.id"; // everybody on the frontpage usually
+        if ($accesssince) {
+            $wheres[] = get_user_lastaccess_sql($accesssince);
+        }
+
+    } else {
+        $select = "SELECT u.id, u.username, u.firstname, u.lastname,
+                          u.email, u.city, u.country, u.picture,
+                          u.lang, u.timezone, u.maildisplay, u.imagealt,
+                          COALESCE(ul.timeaccess, 0) AS lastaccess$extrasql";
+        $joins[] = "JOIN ($esql) e ON e.id = u.id"; // course enrolled users only
+        $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // not everybody accessed course yet
+        $params['courseid'] = $course->id;
+        if ($accesssince) {
+            $wheres[] = get_course_lastaccess_sql($accesssince);
+        }
+    }
+
+    // performance hacks - we preload user contexts together with accounts
+    list($ccselect, $ccjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
+    $select .= $ccselect;
+    $joins[] = $ccjoin;
+
+
+    // limit list to users with some role only
+    if ($roleid) {
+        $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid $contextlist)";
+        $params['roleid'] = $roleid;
+    }
+
+    
+    $from = implode("\n", $joins);
+    if ($wheres) {
+        $where = "WHERE " . implode(" AND ", $wheres);
+    } else {
+        $where = "";
+    }
+
+    $totalcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
+
+    if (!empty($search)) {
+
+       // echo "<br>";
+        $wheres[] = "(". $DB->sql_like($fullname, ':search1', false, false) .
+                    " OR ". $DB->sql_like('email', ':search2', false, false) .
+                    " OR ". $DB->sql_like('idnumber', ':search3', false, false) .") ";
+        $params['search1'] = "%$search%";
+        $params['search2'] = "%$search%";
+        $params['search3'] = "%$search%";
+    }
+        
+    list($twhere, $tparams) = $table->get_sql_where();
+    if ($twhere) {
+        $wheres[] = $twhere;
+        $params = array_merge($params, $tparams);
+    }
+
+    $from = implode("\n", $joins);
+    if ($wheres) {
+        $where = "WHERE " . implode(" AND ", $wheres);
+    } else {
+        $where = "";
+    }
+
+    if ($table->get_sql_sort()) {
+        $sort = ' ORDER BY '.$table->get_sql_sort();
+    } else {
+        $sort = '';
+    }
+
+    $matchcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
+
+    $table->initialbars(true);
+    $table->pagesize($perpage, $matchcount);
+
+    // list of users at the current visible page - paging makes it relatively short
+    $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size());
+
+    /// If there are multiple Roles in the course, then show a drop down menu for switching
+    if (count($rolenames) > 1) {
+       /* echo '<div class="rolesform">';
+        echo '<label for="rolesform_jump">'.get_string('currentrole', 'role').'&nbsp;</label>';
+        echo $OUTPUT->single_select($rolenamesurl, 'roleid', $rolenames, $roleid, null, 'rolesform');
+        echo '</div>';*/
+
+    } else if (count($rolenames) == 1) {
+        // when all users with the same role - print its name
+       /* echo '<div class="rolesform">';
+        echo get_string('role').get_string('labelsep', 'langconfig');*/
+        $rolename = reset($rolenames);
+       /* echo $rolename;
+        echo '</div>';*/
+    }
+
+    if ($roleid > 0) {
+        $a = new stdClass();
+        $a->number = $totalcount;
+        $a->role = $rolenames[$roleid];
+        $heading = format_string(get_string('xuserswiththerole', 'role', $a));
+
+        if ($currentgroup and $group) {
+            $a->group = $group->name;
+            $heading .= ' ' . format_string(get_string('ingroup', 'role', $a));
+        }
+
+        if ($accesssince) {
+            $a->timeperiod = $timeoptions[$accesssince];
+            $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a));
+        }
+
+        $heading .= ": $a->number";
+
+        if (user_can_assign($context, $roleid)) {
+            $heading .= ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?roleid='.$roleid.'&amp;contextid='.$context->id.'">';
+            $heading .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
+        }
+       // echo $OUTPUT->heading($heading, 3);
+    } else {
+        if ($course->id != SITEID && has_capability('moodle/course:enrolreview', $context)) {
+            $editlink = $OUTPUT->action_icon(new moodle_url('/enrol/users.php', array('id' => $course->id)),
+                                             new pix_icon('i/edit', get_string('edit')));
+        } else {
+            $editlink = '';
+        }
+        if ($course->id == SITEID and $roleid < 0) {
+            $strallparticipants = get_string('allsiteusers', 'role');
+        } else {
+            $strallparticipants = get_string('allparticipants');
+        }
+        if ($matchcount < $totalcount) {
+            echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount.'/'.$totalcount . $editlink, 3);
+        } else {
+            echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount . $editlink, 3);
+        }
+    }
+
+  //////////////////////////////////////////  ///////////////////////////7
+
+$xmlcontent =  '<?xml version="1.0" encoding="UTF-8" ?><FEEDBACK VERSION="200701" COMMENT="XML-Importfile for mod/feedback"><ITEMS>';
+if ($TipoDeForm == 1){
+///// PREGUNTAS Trabajos  ////////////////////////////////////////////    
+    $assignments = get_all_instances_in_course("assign", $course);
+
+    foreach ($assignments as $assignment) {
+        $xmlcontent .= '<ITEM TYPE="multichoice" REQUIRED="0"><ITEMID><![CDATA[1]]></ITEMID><ITEMTEXT><![CDATA[';
+        $cm = get_coursemodule_from_instance('assign', $assignment->id, 0, false, MUST_EXIST);
+        $xmlcontent .= $assignment->name;    
+        $xmlcontent .= ': Te ha parecido interesante?]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[r>>>>>Nada|Poco|Normal|Bastante|Mucho]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+        $xmlcontent .= '<ITEM TYPE="textarea" REQUIRED="0"><ITEMID><![CDATA[2]]></ITEMID><ITEMTEXT><![CDATA[';
+        $xmlcontent .= $assignment->name;  
+        $xmlcontent .= ': Comentarios]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[70|5]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+    }
+//////////////////////////////////////////////////////////////////////    
+}
+if ($TipoDeForm == 2){
+///// PREGUNTAS CURSO  ////////////////////////////////////////////
+    $xmlcontent .= '<ITEM TYPE="multichoice" REQUIRED="0"><ITEMID><![CDATA[1]]></ITEMID><ITEMTEXT><![CDATA[';
+    $xmlcontent .= $course->fullname;    
+    $xmlcontent .= ': Te ha parecido interesante el curso?]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[r>>>>>Nada|Poco|Normal|Bastante|Mucho]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+    $xmlcontent .= '<ITEM TYPE="textarea" REQUIRED="0"><ITEMID><![CDATA[2]]></ITEMID><ITEMTEXT><![CDATA[';
+    $xmlcontent .= $course->fullname;    
+    $xmlcontent .= ': Comentarios sobre el curso]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[70|5]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+////////////////////////////////////////////////////////////////////
+}
+if ($TipoDeForm == 3){
+        $countrysort = (strpos($sort, 'country') !== false);
+        $timeformat = get_string('strftimedate');
+
+
+       
+
+        $usersprinted = array();
+        foreach ($userlist as $user) {
+                
+
+             //    echo $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');
+                    $xmlcontent .= '<ITEM TYPE="multichoice" REQUIRED="0"><ITEMID><![CDATA[1]]></ITEMID><ITEMTEXT><![CDATA[';
+                    $xmlcontent .= $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');    
+                    $xmlcontent .= ': Que te ha parecido este profesor?]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[r>>>>>Nada|Poco|Normal|Bastante|Mucho]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+                    $xmlcontent .= '<ITEM TYPE="textarea" REQUIRED="0"><ITEMID><![CDATA[2]]></ITEMID><ITEMTEXT><![CDATA[';
+                    $xmlcontent .= $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');    
+                    $xmlcontent .= ': Comentarios sobre el profesor]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[70|5]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+            
+        }
+
+}
+         
+$xmlcontent .= '</ITEMS></FEEDBACK>';    
+////////////////////////////////////////////
+
+   
+
+    $xmldata = feedback_load_xml_data($xmlcontent);
+
+    feedback_import_loaded_data($xmldata, $feedback->id);
+/*
+    if ($importerror->stat == true) {
+        $url = 'edit.php?id='.$id.'&do_show=templates';
+        redirect($url, get_string('import_successfully', 'feedback'), 3);
+        exit;
+    }
+}
+
+
+/// Print the page header
+$strfeedbacks = get_string("modulenameplural", "feedback");
+$strfeedback  = get_string("modulename", "feedback");
+
+$PAGE->set_heading(format_string($course->fullname));
+$PAGE->set_title(format_string($feedback->name));
+echo $OUTPUT->header();
+
+/// print the tabs
+require('tabs.php');
+*/
+/// Print the main part of the page
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+//echo $OUTPUT->heading(get_string('import_questions', 'feedback'));
+/*
+if (isset($importerror->msg) AND is_array($importerror->msg)) {
+    echo $OUTPUT->box_start('generalbox errorboxcontent boxaligncenter');
+    foreach ($importerror->msg as $msg) {
+        echo $msg.'<br />';
+    }
+    echo $OUTPUT->box_end();
+}
+
+$mform->display();
+*/
+    // Print the header
+$strplural = get_string("modulenameplural", "assign");
+$PAGE->navbar->add($strplural);
+$PAGE->set_title($strplural);
+$PAGE->set_heading($course->fullname);
+
+$url = 'view.php?id='.$id.'&do_show=view';
+//$url = 'import3.php?id='.$id;
+redirect($url, get_string('import_successfully', 'feedback'), 3);
+echo $OUTPUT->header();
+
+
+
+
+
+echo $OUTPUT->footer();
+
+function feedback_load_xml_data($xmlcontent) {
+    global $CFG, $DB;
+    require_once($CFG->dirroot.'/lib/xmlize.php');
+
+    if (!$xmlcontent = feedback_check_xml_utf8($xmlcontent)) {
+        return false;
+    }
+
+    //echo ":Antes:";
+    /////////////////////////////////////////////
+    //$id = required_param('id', PARAM_INT);
+    //$cm = get_coursemodule_from_id('feedback', $id);
+    //$course = $DB->get_record("course", array("id"=>$cm->course));
+/*    
+    $assignments = get_all_instances_in_course("assign", $course);
+    
+    $xmlcontent =  '<?xml version="1.0" encoding="UTF-8" ?><FEEDBACK VERSION="200701" COMMENT="XML-Importfile for mod/feedback"><ITEMS>';
+//$xmlcontent = $xmlcontent + 'sda';
+    foreach ($assignments as $assignment) {
+    $xmlcontent .= '<ITEM TYPE="multichoice" REQUIRED="0"><ITEMID><![CDATA[1]]></ITEMID><ITEMTEXT><![CDATA[';
+    $cm = get_coursemodule_from_instance('assign', $assignment->id, 0, false, MUST_EXIST);
+    //echo $assignment->name;    
+    //echo "<br>";
+    $xmlcontent .= $assignment->name;    
+    $xmlcontent .= ': Te ha parecido interesante?]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[r>>>>>Nada|Poco|Normal|Bastante|Mucho]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+    $xmlcontent .= '<ITEM TYPE="textarea" REQUIRED="0"><ITEMID><![CDATA[2]]></ITEMID><ITEMTEXT><![CDATA[';
+    $xmlcontent .= $assignment->name;  
+    $xmlcontent .= ': Comentarios]]></ITEMTEXT><ITEMLABEL><![CDATA[]]></ITEMLABEL><PRESENTATION><![CDATA[70|5]]></PRESENTATION><OPTIONS><![CDATA[]]></OPTIONS><DEPENDITEM><![CDATA[0]]></DEPENDITEM><DEPENDVALUE><![CDATA[]]></DEPENDVALUE></ITEM>';
+    
+    
+}
+   
+$xmlcontent .= '</ITEMS></FEEDBACK>';    
+
+    //echo "LOLER:";
+    //echo $xmlcontent;
+  */  
+   /////////////////////////////////////////////
+    $data = xmlize($xmlcontent, 1, 'UTF-8');
+    //echo ":Despues:";
+    //echo $data;
+    
+    if (intval($data['FEEDBACK']['@']['VERSION']) != 200701) {
+        return false;
+    }
+    $data = $data['FEEDBACK']['#']['ITEMS'][0]['#']['ITEM'];
+    return $data;
+}
+
+function feedback_import_loaded_data(&$data, $feedbackid) {
+    global $CFG, $DB;
+
+    feedback_load_feedback_items();
+
+    //$deleteolditems = optional_param('deleteolditems', 0, PARAM_INT);
+$deleteolditems = 1;
+
+    $error = new stdClass();
+    $error->stat = true;
+    $error->msg = array();
+
+    if (!is_array($data)) {
+        $error->msg[] = get_string('data_is_not_an_array', 'feedback');
+        $error->stat = false;
+        return $error;
+    }
+
+    if ($deleteolditems) {
+        feedback_delete_all_items($feedbackid);
+        $position = 0;
+    } else {
+        //items will be add to the end of the existing items
+        $position = $DB->count_records('feedback_item', array('feedback'=>$feedbackid));
+    }
+
+    //depend items we are storing temporary in an mapping list array(new id => dependitem)
+    //we also store a mapping of all items array(oldid => newid)
+    $dependitemsmap = array();
+    $itembackup = array();
+    foreach ($data as $item) {
+        $position++;
+        //check the typ
+        $typ = $item['@']['TYPE'];
+        //echo $typ;
+        //check oldtypes first
+        switch($typ) {
+            case 'radio':
+                $typ = 'multichoice';
+                $oldtyp = 'radio';
+                break;
+            case 'dropdown':
+                $typ = 'multichoice';
+                $oldtyp = 'dropdown';
+                break;
+            case 'check':
+                $typ = 'multichoice';
+                $oldtyp = 'check';
+                break;
+            case 'radiorated':
+                $typ = 'multichoicerated';
+                $oldtyp = 'radiorated';
+                break;
+            case 'dropdownrated':
+                $typ = 'multichoicerated';
+                $oldtyp = 'dropdownrated';
+                break;
+            default:
+                $oldtyp = $typ;
+        }
+
+        $itemclass = 'feedback_item_'.$typ;
+        if ($typ != 'pagebreak' AND !class_exists($itemclass)) {
+            $error->stat = false;
+            $error->msg[] = 'type ('.$typ.') not found';
+            continue;
+        }
+        $itemobj = new $itemclass();
+
+        $newitem = new stdClass();
+        $newitem->feedback = $feedbackid;
+        $newitem->template = 0;
+        $newitem->typ = $typ;
+        $newitem->name = trim($item['#']['ITEMTEXT'][0]['#']);
+        $newitem->label = trim($item['#']['ITEMLABEL'][0]['#']);
+        $newitem->options = trim($item['#']['OPTIONS'][0]['#']);
+        $newitem->presentation = trim($item['#']['PRESENTATION'][0]['#']);
+        //check old types of radio, check, and so on
+        switch($oldtyp) {
+            case 'radio':
+                $newitem->presentation = 'r>>>>>'.$newitem->presentation;
+                break;
+            case 'dropdown':
+                $newitem->presentation = 'd>>>>>'.$newitem->presentation;
+                break;
+            case 'check':
+                $newitem->presentation = 'c>>>>>'.$newitem->presentation;
+                break;
+            case 'radiorated':
+                $newitem->presentation = 'r>>>>>'.$newitem->presentation;
+                break;
+            case 'dropdownrated':
+                $newitem->presentation = 'd>>>>>'.$newitem->presentation;
+                break;
+        }
+
+        if (isset($item['#']['DEPENDITEM'][0]['#'])) {
+            $newitem->dependitem = intval($item['#']['DEPENDITEM'][0]['#']);
+        } else {
+            $newitem->dependitem = 0;
+        }
+        if (isset($item['#']['DEPENDVALUE'][0]['#'])) {
+            $newitem->dependvalue = trim($item['#']['DEPENDVALUE'][0]['#']);
+        } else {
+            $newitem->dependvalue = '';
+        }
+        $olditemid = intval($item['#']['ITEMID'][0]['#']);
+
+        if ($typ != 'pagebreak') {
+            $newitem->hasvalue = $itemobj->get_hasvalue();
+        } else {
+            $newitem->hasvalue = 0;
+        }
+        $newitem->required = intval($item['@']['REQUIRED']);
+        $newitem->position = $position;
+        $newid = $DB->insert_record('feedback_item', $newitem);
+
+        $itembackup[$olditemid] = $newid;
+        if ($newitem->dependitem) {
+            $dependitemsmap[$newid] = $newitem->dependitem;
+        }
+
+    }
+    //remapping the dependency
+    foreach ($dependitemsmap as $key => $dependitem) {
+        $newitem = $DB->get_record('feedback_item', array('id'=>$key));
+        $newitem->dependitem = $itembackup[$newitem->dependitem];
+        $DB->update_record('feedback_item', $newitem);
+    }
+
+    return $error;
+}
+
+function feedback_check_xml_utf8($text) {
+    //find the encoding
+    $searchpattern = '/^\<\?xml.+(encoding=\"([a-z0-9-]*)\").+\?\>/is';
+
+    if (!preg_match($searchpattern, $text, $match)) {
+        return false; //no xml-file
+    }
+
+    //$match[0] = \<\? xml ... \?\> (without \)
+    //$match[1] = encoding="...."
+    //$match[2] = ISO-8859-1 or so on
+    if (isset($match[0]) AND !isset($match[1])) { //no encoding given. we assume utf-8
+        return $text;
+    }
+
+    //encoding is given in $match[2]
+    if (isset($match[0]) AND isset($match[1]) AND isset($match[2])) {
+        $enc = $match[2];
+        return textlib::convert($text, $enc);
+    }
+}
+
+function get_course_lastaccess_sql($accesssince='') {
+    if (empty($accesssince)) {
+        return '';
+    }
+    if ($accesssince == -1) { // never
+        return 'ul.timeaccess = 0';
+    } else {
+        return 'ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
+    }
+}
+
+function get_user_lastaccess_sql($accesssince='') {
+    if (empty($accesssince)) {
+        return '';
+    }
+    if ($accesssince == -1) { // never
+        return 'u.lastaccess = 0';
+    } else {
+        return 'u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
+    }
+}
diff --git a/mod/feedback/import_form.php b/mod/feedback/import_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/index.php b/mod/feedback/index.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/captcha/captcha_form.php b/mod/feedback/item/captcha/captcha_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/captcha/lib.php b/mod/feedback/item/captcha/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/captcha/print_captcha.php b/mod/feedback/item/captcha/print_captcha.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/feedback_item_class.php b/mod/feedback/item/feedback_item_class.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/feedback_item_form_class.php b/mod/feedback/item/feedback_item_form_class.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/info/info_form.php b/mod/feedback/item/info/info_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/info/lib.php b/mod/feedback/item/info/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/label/label_form.php b/mod/feedback/item/label/label_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/label/lib.php b/mod/feedback/item/label/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/multichoice/lib.php b/mod/feedback/item/multichoice/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/multichoice/multichoice_form.php b/mod/feedback/item/multichoice/multichoice_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/multichoicerated/lib.php b/mod/feedback/item/multichoicerated/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/multichoicerated/multichoicerated_form.php b/mod/feedback/item/multichoicerated/multichoicerated_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/numeric/lib.php b/mod/feedback/item/numeric/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/numeric/numeric_form.php b/mod/feedback/item/numeric/numeric_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/textarea/lib.php b/mod/feedback/item/textarea/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/textarea/textarea_form.php b/mod/feedback/item/textarea/textarea_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/textfield/lib.php b/mod/feedback/item/textfield/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/item/textfield/textfield_form.php b/mod/feedback/item/textfield/textfield_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/lang/en/feedback.php b/mod/feedback/lang/en/feedback.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/lib.php b/mod/feedback/lib.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/mapcourse.php b/mod/feedback/mapcourse.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/mod_form.php b/mod/feedback/mod_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/mod_formEvaluateMe.php b/mod/feedback/mod_formEvaluateMe.php
new file mode 100755
index 0000000..a0caf43
--- /dev/null
+++ b/mod/feedback/mod_formEvaluateMe.php
@@ -0,0 +1,236 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * print the form to add or edit a feedback-instance
+ *
+ * @author Andreas Grabs
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package feedback
+ */
+
+//It must be included from a Moodle page
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.');
+}
+require_once($CFG->dirroot.'/course/moodleform_mod.php');
+
+class mod_feedback_mod_form extends moodleform_mod {
+
+    public function definition() {
+        global $CFG, $DB;
+
+        $editoroptions = feedback_get_editor_options();
+
+        $mform    =& $this->_form;
+
+        //-------------------------------------------------------------------------------
+        $mform->addElement('header', 'general', get_string('general', 'form'));
+
+        $mform->addElement('hidden', 'name', get_string('name', 'feedback'), array('size'=>'64'));
+        $mform->setType('name', PARAM_TEXT);
+        $mform->addRule('name', null, 'required', null, 'client');
+
+        $this->add_intro_editor(true, get_string('description', 'feedback'));
+
+        //-------------------------------------------------------------------------------
+        $mform->addElement('header', 'timinghdr', get_string('timing', 'form'));
+
+        $enableopengroup = array();
+        $enableopengroup[] =& $mform->createElement('checkbox',
+                                    'openenable',
+                                    get_string('feedbackopen', 'feedback'));
+
+        $enableopengroup[] =& $mform->createElement('date_time_selector', 'timeopen', '');
+        $mform->addGroup($enableopengroup,
+                         'enableopengroup',
+                         get_string('feedbackopen', 'feedback'),
+                         ' ',
+                         false);
+
+        $mform->addHelpButton('enableopengroup', 'timeopen', 'feedback');
+        $mform->disabledIf('enableopengroup', 'openenable', 'notchecked');
+
+        $enableclosegroup = array();
+        $enableclosegroup[] =& $mform->createElement('checkbox',
+                                        'closeenable',
+                                        get_string('feedbackclose', 'feedback'));
+
+        $enableclosegroup[] =& $mform->createElement('date_time_selector', 'timeclose', '');
+        $mform->addGroup($enableclosegroup,
+                         'enableclosegroup',
+                         get_string('feedbackclose', 'feedback'),
+                         ' ',
+                         false);
+
+        $mform->addHelpButton('enableclosegroup', 'timeclose', 'feedback');
+        $mform->disabledIf('enableclosegroup', 'closeenable', 'notchecked');
+
+        //-------------------------------------------------------------------------------
+        $mform->addElement('header', 'feedbackhdr', get_string('feedback_options', 'feedback'));
+
+        $options=array();
+        $options[1]  = get_string('anonymous', 'feedback');
+        $options[2]  = get_string('non_anonymous', 'feedback');
+        $mform->addElement('select',
+                           'anonymous',
+                           get_string('anonymous_edit', 'feedback'),
+                           $options);
+
+        $mform->addElement('selectyesno',
+                           'publish_stats',
+                           get_string('show_analysepage_after_submit', 'feedback'));
+
+        $mform->addElement('selectyesno',
+                           'email_notification',
+                           get_string('email_notification', 'feedback'));
+
+        $mform->addHelpButton('email_notification', 'emailnotification', 'feedback');
+
+        // check if there is existing responses to this feedback
+        if (is_numeric($this->_instance) AND
+                    $this->_instance AND
+                    $feedback = $DB->get_record("feedback", array("id"=>$this->_instance))) {
+
+            $completed_feedback_count = feedback_get_completeds_group_count($feedback);
+        } else {
+            $completed_feedback_count = false;
+        }
+
+        if ($completed_feedback_count) {
+            $multiple_submit_value = $feedback->multiple_submit ? get_string('yes') : get_string('no');
+            $mform->addElement('text',
+                               'multiple_submit_static',
+                               get_string('multiple_submit', 'feedback'),
+                               array('size'=>'4',
+                                    'disabled'=>'disabled',
+                                    'value'=>$multiple_submit_value));
+
+            $mform->addElement('hidden', 'multiple_submit', '');
+            $mform->setType('', PARAM_INT);
+            $mform->addHelpButton('multiple_submit_static', 'multiplesubmit', 'feedback');
+        } else {
+            $mform->addElement('selectyesno',
+                               'multiple_submit',
+                               get_string('multiple_submit', 'feedback'));
+
+            $mform->addHelpButton('multiple_submit', 'multiplesubmit', 'feedback');
+        }
+        $mform->addElement('selectyesno', 'autonumbering', get_string('autonumbering', 'feedback'));
+        $mform->addHelpButton('autonumbering', 'autonumbering', 'feedback');
+
+        //-------------------------------------------------------------------------------
+        $mform->addElement('header', 'aftersubmithdr', get_string('after_submit', 'feedback'));
+
+        $mform->addElement('editor',
+                           'page_after_submit_editor',
+                           get_string("page_after_submit", "feedback"),
+                           null,
+                           $editoroptions);
+
+        $mform->setType('page_after_submit_editor', PARAM_RAW);
+
+        $mform->addElement('text',
+                           'site_after_submit',
+                           get_string('url_for_continue_button', 'feedback'),
+                           array('size'=>'64', 'maxlength'=>'255'));
+
+        $mform->setType('site_after_submit', PARAM_TEXT);
+        $mform->addHelpButton('site_after_submit', 'url_for_continue', 'feedback');
+        //-------------------------------------------------------------------------------
+        $this->standard_coursemodule_elements();
+        //-------------------------------------------------------------------------------
+        // buttons
+        $this->add_action_buttons();
+    }
+
+    public function data_preprocessing(&$default_values) {
+        if (empty($default_values['timeopen'])) {
+            $default_values['openenable'] = 0;
+        } else {
+            $default_values['openenable'] = 1;
+        }
+        if (empty($default_values['timeclose'])) {
+            $default_values['closeenable'] = 0;
+        } else {
+            $default_values['closeenable'] = 1;
+        }
+
+        $editoroptions = feedback_get_editor_options();
+
+        if ($this->current->instance) {
+            // editing an existing feedback - let us prepare the added editor elements (intro done automatically)
+            $draftitemid = file_get_submitted_draft_itemid('page_after_submit');
+            $default_values['page_after_submit_editor']['text'] =
+                                    file_prepare_draft_area($draftitemid, $this->context->id,
+                                    'mod_feedback', 'page_after_submit', false,
+                                    $editoroptions,
+                                    $default_values['page_after_submit']);
+
+            $default_values['page_after_submit_editor']['format'] = $default_values['page_after_submitformat'];
+            $default_values['page_after_submit_editor']['itemid'] = $draftitemid;
+        } else {
+            // adding a new feedback instance
+            $draftitemid = file_get_submitted_draft_itemid('page_after_submit_editor');
+
+            // no context yet, itemid not used
+            file_prepare_draft_area($draftitemid, null, 'mod_feedback', 'page_after_submit', false);
+            $default_values['page_after_submit_editor']['text'] = '';
+            $default_values['page_after_submit_editor']['format'] = editors_get_preferred_format();
+            $default_values['page_after_submit_editor']['itemid'] = $draftitemid;
+        }
+
+    }
+
+    public function get_data() {
+        $data = parent::get_data();
+        if ($data) {
+            $data->page_after_submitformat = $data->page_after_submit_editor['format'];
+            $data->page_after_submit = $data->page_after_submit_editor['text'];
+
+            // Turn off completion settings if the checkboxes aren't ticked
+            $autocompletion = !empty($data->completion) AND
+                                    $data->completion==COMPLETION_TRACKING_AUTOMATIC;
+            if (empty($data->completion) || !$autocompletion) {
+                $data->completionsubmit=0;
+            }
+            if (empty($data->completionsubmit)) {
+                $data->completionsubmit=0;
+            }
+        }
+
+        return $data;
+    }
+
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+        return $errors;
+    }
+
+    public function add_completion_rules() {
+        $mform =& $this->_form;
+
+        $mform->addElement('checkbox',
+                           'completionsubmit',
+                           '',
+                           get_string('completionsubmit', 'feedback'));
+        return array('completionsubmit');
+    }
+
+    public function completion_rule_enabled($data) {
+        return !empty($data['completionsubmit']);
+    }
+}
diff --git a/mod/feedback/pix/icon.gif b/mod/feedback/pix/icon.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/0.gif b/mod/feedback/pix/multichoice/0.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/1.gif b/mod/feedback/pix/multichoice/1.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/2.gif b/mod/feedback/pix/multichoice/2.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/3.gif b/mod/feedback/pix/multichoice/3.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/4.gif b/mod/feedback/pix/multichoice/4.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/5.gif b/mod/feedback/pix/multichoice/5.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/6.gif b/mod/feedback/pix/multichoice/6.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/7.gif b/mod/feedback/pix/multichoice/7.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/8.gif b/mod/feedback/pix/multichoice/8.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/multichoice/9.gif b/mod/feedback/pix/multichoice/9.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/notrequired.gif b/mod/feedback/pix/notrequired.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/pix/required.gif b/mod/feedback/pix/required.gif
old mode 100644
new mode 100755
diff --git a/mod/feedback/print.php b/mod/feedback/print.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/settings.php b/mod/feedback/settings.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/show_entries.php b/mod/feedback/show_entries.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/show_entries_anonym.php b/mod/feedback/show_entries_anonym.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/show_nonrespondents.php b/mod/feedback/show_nonrespondents.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/styles.css b/mod/feedback/styles.css
old mode 100644
new mode 100755
diff --git a/mod/feedback/tabs.php b/mod/feedback/tabs.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/unmapcourse.php b/mod/feedback/unmapcourse.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/use_templ.php b/mod/feedback/use_templ.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/use_templ_form.php b/mod/feedback/use_templ_form.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/version.php b/mod/feedback/version.php
old mode 100644
new mode 100755
diff --git a/mod/feedback/view.php b/mod/feedback/view.php
old mode 100644
new mode 100755
-- 
1.7.9.5

