Merge branch 'MDL-55835-master' of git://github.com/danpoltawski/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 10 Oct 2016 23:21:14 +0000 (01:21 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 10 Oct 2016 23:21:14 +0000 (01:21 +0200)
230 files changed:
.eslintignore
.stylelintignore
admin/index.php
admin/renderer.php
admin/settings/security.php
admin/tool/templatelibrary/classes/api.php
blocks/settings/amd/build/settingsblock.min.js
blocks/settings/amd/src/settingsblock.js
cache/locallib.php
cache/stores/apcu/lib.php
competency/classes/api.php
competency/tests/api_test.php
grade/report/overview/classes/external.php [new file with mode: 0644]
grade/report/overview/db/services.php [new file with mode: 0644]
grade/report/overview/index.php
grade/report/overview/lib.php
grade/report/overview/tests/externallib_test.php [new file with mode: 0644]
grade/report/overview/version.php
grade/report/user/index.php
grade/report/user/lang/en/gradereport_user.php
grade/report/user/lib.php
grade/report/user/renderer.php
grade/report/user/styles.css
grade/report/user/tests/behat/user_view.feature [new file with mode: 0644]
grade/tests/behat/behat_grade.php
grade/tests/behat/grade_aggregation.feature
grade/tests/behat/grade_hidden_items.feature
iplookup/tests/geoip_test.php
lang/en/admin.php
lang/en/moodle.php
lang/en/webservice.php
lib/adodb/adodb-active-record.inc.php
lib/adodb/adodb-active-recordx.inc.php
lib/adodb/adodb-csvlib.inc.php
lib/adodb/adodb-datadict.inc.php
lib/adodb/adodb-error.inc.php
lib/adodb/adodb-errorhandler.inc.php
lib/adodb/adodb-errorpear.inc.php
lib/adodb/adodb-exceptions.inc.php
lib/adodb/adodb-iterator.inc.php
lib/adodb/adodb-lib.inc.php
lib/adodb/adodb-memcache.lib.inc.php
lib/adodb/adodb-pager.inc.php
lib/adodb/adodb-pear.inc.php
lib/adodb/adodb-perf.inc.php
lib/adodb/adodb-php4.inc.php
lib/adodb/adodb-time.inc.php
lib/adodb/adodb-xmlschema.inc.php
lib/adodb/adodb-xmlschema03.inc.php
lib/adodb/adodb.inc.php
lib/adodb/datadict/datadict-access.inc.php
lib/adodb/datadict/datadict-db2.inc.php
lib/adodb/datadict/datadict-firebird.inc.php
lib/adodb/datadict/datadict-generic.inc.php
lib/adodb/datadict/datadict-ibase.inc.php
lib/adodb/datadict/datadict-informix.inc.php
lib/adodb/datadict/datadict-mssql.inc.php
lib/adodb/datadict/datadict-mssqlnative.inc.php
lib/adodb/datadict/datadict-mysql.inc.php
lib/adodb/datadict/datadict-oci8.inc.php
lib/adodb/datadict/datadict-postgres.inc.php
lib/adodb/datadict/datadict-sapdb.inc.php
lib/adodb/datadict/datadict-sqlite.inc.php
lib/adodb/datadict/datadict-sybase.inc.php
lib/adodb/drivers/adodb-access.inc.php
lib/adodb/drivers/adodb-ado.inc.php
lib/adodb/drivers/adodb-ado5.inc.php
lib/adodb/drivers/adodb-ado_access.inc.php
lib/adodb/drivers/adodb-ado_mssql.inc.php
lib/adodb/drivers/adodb-borland_ibase.inc.php
lib/adodb/drivers/adodb-csv.inc.php
lib/adodb/drivers/adodb-db2.inc.php
lib/adodb/drivers/adodb-db2oci.inc.php
lib/adodb/drivers/adodb-db2ora.inc.php
lib/adodb/drivers/adodb-fbsql.inc.php
lib/adodb/drivers/adodb-firebird.inc.php
lib/adodb/drivers/adodb-ibase.inc.php
lib/adodb/drivers/adodb-informix.inc.php
lib/adodb/drivers/adodb-informix72.inc.php
lib/adodb/drivers/adodb-ldap.inc.php
lib/adodb/drivers/adodb-mssql.inc.php
lib/adodb/drivers/adodb-mssqlnative.inc.php
lib/adodb/drivers/adodb-mssqlpo.inc.php
lib/adodb/drivers/adodb-mysql.inc.php
lib/adodb/drivers/adodb-mysqli.inc.php
lib/adodb/drivers/adodb-mysqlpo.inc.php
lib/adodb/drivers/adodb-mysqlt.inc.php
lib/adodb/drivers/adodb-netezza.inc.php
lib/adodb/drivers/adodb-oci8.inc.php
lib/adodb/drivers/adodb-oci805.inc.php
lib/adodb/drivers/adodb-oci8po.inc.php
lib/adodb/drivers/adodb-oci8quercus.inc.php
lib/adodb/drivers/adodb-odbc.inc.php
lib/adodb/drivers/adodb-odbc_db2.inc.php
lib/adodb/drivers/adodb-odbc_mssql.inc.php
lib/adodb/drivers/adodb-odbc_mssql2012.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-odbc_oracle.inc.php
lib/adodb/drivers/adodb-odbtp.inc.php
lib/adodb/drivers/adodb-odbtp_unicode.inc.php
lib/adodb/drivers/adodb-oracle.inc.php
lib/adodb/drivers/adodb-pdo.inc.php
lib/adodb/drivers/adodb-pdo_mssql.inc.php
lib/adodb/drivers/adodb-pdo_mysql.inc.php
lib/adodb/drivers/adodb-pdo_oci.inc.php
lib/adodb/drivers/adodb-pdo_pgsql.inc.php
lib/adodb/drivers/adodb-pdo_sqlite.inc.php
lib/adodb/drivers/adodb-postgres.inc.php
lib/adodb/drivers/adodb-postgres64.inc.php
lib/adodb/drivers/adodb-postgres7.inc.php
lib/adodb/drivers/adodb-postgres8.inc.php
lib/adodb/drivers/adodb-postgres9.inc.php
lib/adodb/drivers/adodb-proxy.inc.php
lib/adodb/drivers/adodb-sapdb.inc.php
lib/adodb/drivers/adodb-sqlanywhere.inc.php
lib/adodb/drivers/adodb-sqlite.inc.php
lib/adodb/drivers/adodb-sqlite3.inc.php
lib/adodb/drivers/adodb-sqlitepo.inc.php
lib/adodb/drivers/adodb-sybase.inc.php
lib/adodb/drivers/adodb-sybase_ase.inc.php
lib/adodb/drivers/adodb-vfp.inc.php
lib/adodb/perf/perf-db2.inc.php
lib/adodb/perf/perf-informix.inc.php
lib/adodb/perf/perf-mssql.inc.php
lib/adodb/perf/perf-mssqlnative.inc.php
lib/adodb/perf/perf-mysql.inc.php
lib/adodb/perf/perf-oci8.inc.php
lib/adodb/perf/perf-postgres.inc.php
lib/adodb/pivottable.inc.php
lib/adodb/readme_moodle.txt
lib/adodb/rsfilter.inc.php
lib/adodb/toexport.inc.php
lib/adodb/tohtml.inc.php
lib/classes/component.php
lib/classes/minify.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/javascript-static.js
lib/javascript.php
lib/minify/LICENSE.txt [deleted file]
lib/minify/config.php [deleted file]
lib/minify/groupsConfig.php [deleted file]
lib/minify/lib/CSSmin.php [deleted file]
lib/minify/lib/DooDigestAuth.php [deleted file]
lib/minify/lib/FirePHP.php [deleted file]
lib/minify/lib/HTTP/ConditionalGet.php [deleted file]
lib/minify/lib/HTTP/Encoder.php [deleted file]
lib/minify/lib/JSMinPlus.php [deleted file]
lib/minify/lib/Minify.php [deleted file]
lib/minify/lib/Minify/Build.php [deleted file]
lib/minify/lib/Minify/CSS.php [deleted file]
lib/minify/lib/Minify/CSS/Compressor.php [deleted file]
lib/minify/lib/Minify/CSS/UriRewriter.php [deleted file]
lib/minify/lib/Minify/CSSmin.php [deleted file]
lib/minify/lib/Minify/Cache/APC.php [deleted file]
lib/minify/lib/Minify/Cache/File.php [deleted file]
lib/minify/lib/Minify/Cache/Memcache.php [deleted file]
lib/minify/lib/Minify/Cache/WinCache.php [deleted file]
lib/minify/lib/Minify/Cache/XCache.php [deleted file]
lib/minify/lib/Minify/Cache/ZendPlatform.php [deleted file]
lib/minify/lib/Minify/ClosureCompiler.php [deleted file]
lib/minify/lib/Minify/CommentPreserver.php [deleted file]
lib/minify/lib/Minify/Controller/Base.php [deleted file]
lib/minify/lib/Minify/Controller/Files.php [deleted file]
lib/minify/lib/Minify/Controller/Groups.php [deleted file]
lib/minify/lib/Minify/Controller/MinApp.php [deleted file]
lib/minify/lib/Minify/Controller/Page.php [deleted file]
lib/minify/lib/Minify/Controller/Version1.php [deleted file]
lib/minify/lib/Minify/DebugDetector.php [deleted file]
lib/minify/lib/Minify/HTML.php [deleted file]
lib/minify/lib/Minify/HTML/Helper.php [deleted file]
lib/minify/lib/Minify/ImportProcessor.php [deleted file]
lib/minify/lib/Minify/JS/ClosureCompiler.php [deleted file]
lib/minify/lib/Minify/Lines.php [deleted file]
lib/minify/lib/Minify/Loader.php [deleted file]
lib/minify/lib/Minify/Logger.php [deleted file]
lib/minify/lib/Minify/Packer.php [deleted file]
lib/minify/lib/Minify/Source.php [deleted file]
lib/minify/lib/Minify/YUI/CssCompressor.java [deleted file]
lib/minify/lib/Minify/YUI/CssCompressor.php [deleted file]
lib/minify/lib/Minify/YUICompressor.php [deleted file]
lib/minify/lib/MrClay/Cli.php [deleted file]
lib/minify/lib/MrClay/Cli/Arg.php [deleted file]
lib/minify/matthiasmullie-minify/data/js/keywords_after.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/data/js/keywords_before.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/data/js/keywords_reserved.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/data/js/operators.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/data/js/operators_after.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/data/js/operators_before.txt [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/CSS.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/Exception.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/Exceptions/BasicException.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/Exceptions/FileImportException.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/Exceptions/IOException.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/JS.php [new file with mode: 0644]
lib/minify/matthiasmullie-minify/src/Minify.php [new file with mode: 0644]
lib/minify/matthiasmullie-pathconverter/src/Converter.php [new file with mode: 0644]
lib/minify/readme_moodle.txt
lib/minify/utils.php [deleted file]
lib/moodlelib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/templates/progress_bar.mustache [new file with mode: 0644]
lib/tests/minify_test.php
lib/tests/string_manager_standard_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/upgradelib.php
lib/weblib.php
login/change_password.php
login/change_password_form.php
mod/lti/mod_form.php
mod/lti/tests/behat/contentitem.feature
question/classes/bank/action_column_base.php
tag/templates/taglist.mustache
theme/boost/lib.php
theme/boost/pix/favicon.ico
theme/boost/scss/moodle/core.scss
theme/boost/scss/moodle/question.scss
theme/boost/templates/core/modal.mustache [new file with mode: 0644]
theme/boost/templates/core/modal_backdrop.mustache [new file with mode: 0644]
theme/boost/templates/core/progress_bar.mustache [new file with mode: 0644]
theme/bootstrapbase/less/moodle/blocks.less
theme/bootstrapbase/less/moodle/forms.less
theme/bootstrapbase/less/moodle/question.less
theme/bootstrapbase/style/moodle.css
theme/bootstrapbase/templates/theme_boost/admin_setting_tabs.mustache [new file with mode: 0644]
user/editadvanced.php
user/editadvanced_form.php
version.php
webservice/lib.php

index e35675a..73b2b4a 100644 (file)
@@ -20,7 +20,8 @@ lib/phpexcel/
 lib/google/
 lib/htmlpurifier/
 lib/jabber/
-lib/minify/
+lib/minify/matthiasmullie-minify/
+lib/minify/matthiasmullie-pathconverter/
 lib/flowplayer/
 lib/pear/Auth/RADIUS.php
 lib/pear/Crypt/CHAP.php
index 9a2dc50..b9e8b2c 100644 (file)
@@ -19,7 +19,8 @@ lib/phpexcel/
 lib/google/
 lib/htmlpurifier/
 lib/jabber/
-lib/minify/
+lib/minify/matthiasmullie-minify/
+lib/minify/matthiasmullie-pathconverter/
 lib/flowplayer/
 lib/pear/Auth/RADIUS.php
 lib/pear/Crypt/CHAP.php
index 2cf9d1a..6f87285 100644 (file)
@@ -851,6 +851,7 @@ $registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOOD
 $cachewarnings = cache_helper::warnings();
 // Check if there are events 1 API handlers.
 $eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
+$themedesignermode = !empty($CFG->themedesignermode);
 
 admin_externalpage_setup('adminnotifications');
 
@@ -858,4 +859,4 @@ $output = $PAGE->get_renderer('core', 'admin');
 
 echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
                                        $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
-                                       $registered, $cachewarnings, $eventshandlers);
+                                       $registered, $cachewarnings, $eventshandlers, $themedesignermode);
index 7895c31..2b841d6 100644 (file)
@@ -281,7 +281,7 @@ class core_admin_renderer extends plugin_renderer_base {
      */
     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
-            $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0) {
+            $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0, $themedesignermode = false) {
         global $CFG;
         $output = '';
 
@@ -290,6 +290,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $output .= $this->legacy_log_store_writing_error();
         $output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
         $output .= $this->insecure_dataroot_warning($insecuredataroot);
+        $output .= $this->themedesignermode_warning($themedesignermode);
         $output .= $this->display_errors_warning($errorsdisplayed);
         $output .= $this->buggy_iconv_warning($buggyiconvnomb);
         $output .= $this->cron_overdue_warning($cronoverdue);
@@ -532,6 +533,19 @@ class core_admin_renderer extends plugin_renderer_base {
         return $this->warning(get_string('displayerrorswarning', 'admin'));
     }
 
+    /**
+     * Render an appropriate message if themdesignermode is enabled.
+     * @param bool $themedesignermode true if enabled
+     * @return string HTML to output.
+     */
+    protected function themedesignermode_warning($themedesignermode) {
+        if (!$themedesignermode) {
+            return '';
+        }
+
+        return $this->warning(get_string('themedesignermodewarning', 'admin'));
+    }
+
     /**
      * Render an appropriate message if iconv is buggy and mbstring missing.
      * @param bool $buggyiconvnomb
index 946abbd..c892566 100644 (file)
@@ -96,6 +96,11 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('passwordchangelogout',
         new lang_string('passwordchangelogout', 'admin'),
         new lang_string('passwordchangelogout_desc', 'admin'), 0));
+
+    $temp->add(new admin_setting_configcheckbox('passwordchangetokendeletion',
+        new lang_string('passwordchangetokendeletion', 'admin'),
+        new lang_string('passwordchangetokendeletion_desc', 'admin'), 0));
+
     $temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', new lang_string('groupenrolmentkeypolicy', 'admin'), new lang_string('groupenrolmentkeypolicy_desc', 'admin'), 1));
     $temp->add(new admin_setting_configcheckbox('disableuserimages', new lang_string('disableuserimages', 'admin'), new lang_string('configdisableuserimages', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', new lang_string('emailchangeconfirmation', 'admin'), new lang_string('configemailchangeconfirmation', 'admin'), 1));
index 2ef5d4c..23b7dcf 100644 (file)
@@ -117,17 +117,21 @@ class api {
         // Get the list of possible template directories.
         $dirs = mustache_template_finder::get_template_directories_for_component($component);
         $filename = false;
+        $themedir = core_component::get_plugin_types()['theme'];
 
         foreach ($dirs as $dir) {
             // Skip theme dirs - we only want the original plugin/core template.
-            if (strpos($dir, "/theme/") === false) {
-                $candidate = $dir . $template . '.mustache';
-                if (file_exists($candidate)) {
-                    $filename = $candidate;
-                    break;
-                }
+            if (strpos($dir, $themedir) === 0) {
+                continue;
+            }
+
+            $candidate = $dir . $template . '.mustache';
+            if (file_exists($candidate)) {
+                $filename = $candidate;
+                break;
             }
         }
+
         if ($filename === false) {
             throw new moodle_exception('filenotfound', 'error');
         }
index 8a8e746..1cebc85 100644 (file)
Binary files a/blocks/settings/amd/build/settingsblock.min.js and b/blocks/settings/amd/build/settingsblock.min.js differ
index bdccda5..f17553f 100644 (file)
@@ -40,9 +40,6 @@ define(['jquery', 'core/tree'], function($, Tree) {
             };
             adminTree.collapseGroup = function(item) {
                 Tree.prototype.collapseGroup.call(this, item);
-                Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
-                    instanceid: instanceid
-                });
                 Y.use('moodle-core-event', function() {
                     Y.Global.fire(M.core.globalEvents.BLOCK_CONTENT_UPDATED, {
                         instanceid: instanceid
index 2e6813e..e97dd56 100644 (file)
@@ -691,7 +691,7 @@ abstract class cache_administration_helper extends cache_helper {
                 'plugin' => $details['plugin'],
                 'default' => $details['default'],
                 'isready' => $store->is_ready(),
-                'requirementsmet' => $store->are_requirements_met(),
+                'requirementsmet' => $class::are_requirements_met(),
                 'mappings' => 0,
                 'lock' => $lock,
                 'modes' => array(
index a0dd6b8..27cd2e6 100644 (file)
@@ -69,7 +69,8 @@ class cachestore_apcu extends cache_store implements cache_is_key_aware, cache_i
      * @return bool True if the stores software/hardware requirements have been met and it can be used. False otherwise.
      */
     public static function are_requirements_met() {
-        if (!extension_loaded('apcu') || !ini_get('apc.enabled')) {
+        $enabled = ini_get('apc.enabled') && (php_sapi_name() != "cli" || ini_get('apc.enable_cli'));
+        if (!extension_loaded('apcu') || !$enabled) {
             return false;
         }
 
index 043111e..a7f8b88 100644 (file)
@@ -2196,10 +2196,13 @@ class api {
      */
     public static function reorder_template_competency($templateid, $competencyidfrom, $competencyidto) {
         static::require_enabled();
-        // First we do a permissions check.
-        $context = context_system::instance();
+        $template = new template($templateid);
 
-        require_capability('moodle/competency:templatemanage', $context);
+        // First we do a permissions check.
+        if (!$template->can_manage()) {
+            throw new required_capability_exception($template->get_context(), 'moodle/competency:templatemanage',
+                'nopermissions', '');
+        }
 
         $down = true;
         $matches = template_competency::get_records(array('templateid' => $templateid, 'competencyid' => $competencyidfrom));
index cb815aa..d55446b 100644 (file)
@@ -1883,6 +1883,71 @@ class core_competency_api_testcase extends advanced_testcase {
         $this->assertInstanceOf('core_competency\\template_cohort', $result);
     }
 
+    public function test_reorder_template_competencies_permissions() {
+        $this->resetAfterTest(true);
+
+        $dg = $this->getDataGenerator();
+        $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
+        $cat = $dg->create_category();
+        $catcontext = context_coursecat::instance($cat->id);
+        $syscontext = context_system::instance();
+
+        $user = $dg->create_user();
+        $role = $dg->create_role();
+        assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);
+        $dg->role_assign($role, $user->id, $syscontext->id);
+
+        // Create a template.
+        $template = $lpg->create_template(array('contextid' => $catcontext->id));
+
+        // Create a competency framework.
+        $framework = $lpg->create_framework(array('contextid' => $catcontext->id));
+
+        // Create competencies.
+        $competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
+        $competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
+
+        // Add the competencies.
+        $lpg->create_template_competency(array(
+            'templateid' => $template->get_id(),
+            'competencyid' => $competency1->get_id()
+        ));
+        $lpg->create_template_competency(array(
+            'templateid' => $template->get_id(),
+            'competencyid' => $competency2->get_id()
+        ));
+        $this->setUser($user);
+        // Can reorder competencies with system context permissions in category context.
+        $result = api::reorder_template_competency($template->get_id(), $competency2->get_id(), $competency1->get_id());
+        $this->assertTrue($result);
+        unassign_capability('moodle/competency:templatemanage', $role, $syscontext->id);
+        accesslib_clear_all_caches_for_unit_testing();
+
+        try {
+            api::reorder_template_competency($template->get_id(), $competency2->get_id(), $competency1->get_id());
+            $this->fail('Exception expected due to not permissions to manage template competencies');
+        } catch (required_capability_exception $e) {
+            $this->assertEquals('nopermissions', $e->errorcode);
+        }
+
+        // Giving permissions in category context.
+        assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $catcontext->id, true);
+        $dg->role_assign($role, $user->id, $catcontext->id);
+        // User with templatemanage capability in category context can reorder competencies in temple.
+        $result = api::reorder_template_competency($template->get_id(), $competency1->get_id(), $competency2->get_id());
+        $this->assertTrue($result);
+        // Removing templatemanage capability in category context.
+        unassign_capability('moodle/competency:templatemanage', $role, $catcontext->id);
+        accesslib_clear_all_caches_for_unit_testing();
+
+        try {
+            api::reorder_template_competency($template->get_id(), $competency2->get_id(), $competency1->get_id());
+            $this->fail('Exception expected due to not permissions to manage template competencies');
+        } catch (required_capability_exception $e) {
+            $this->assertEquals('nopermissions', $e->errorcode);
+        }
+    }
+
     public function test_delete_template() {
         $this->resetAfterTest(true);
         $this->setAdminUser();
diff --git a/grade/report/overview/classes/external.php b/grade/report/overview/classes/external.php
new file mode 100644 (file)
index 0000000..abdb080
--- /dev/null
@@ -0,0 +1,224 @@
+<?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 grade report overview API
+ *
+ * @package    gradereport_overview
+ * @copyright  2016 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->libdir . '/externallib.php');
+require_once($CFG->libdir . '/gradelib.php');
+require_once($CFG->dirroot . '/grade/lib.php');
+require_once($CFG->dirroot . '/grade/report/overview/lib.php');
+
+/**
+ * External grade overview report API implementation
+ *
+ * @package    gradereport_overview
+ * @copyright  2016 Juan Leyva <juan@moodle.com>
+ * @category   external
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class gradereport_overview_external extends external_api {
+
+    /**
+     * Describes the parameters for get_course_grades.
+     *
+     * @return external_external_function_parameters
+     * @since Moodle 3.2
+     */
+    public static function get_course_grades_parameters() {
+        return new external_function_parameters (
+            array(
+                'userid' => new external_value(PARAM_INT, 'Get grades for this user (optional, default current)', VALUE_DEFAULT, 0)
+            )
+        );
+    }
+
+    /**
+     * Get the given user courses final grades
+     *
+     * @param int $userid get grades for this user (optional, default current)
+     *
+     * @return array the grades tables
+     * @since Moodle 3.2
+     */
+    public static function get_course_grades($userid = 0) {
+        global $USER;
+
+        $warnings = array();
+
+        // Validate the parameter.
+        $params = self::validate_parameters(self::get_course_grades_parameters(),
+            array(
+                'userid' => $userid
+            )
+        );
+
+        $userid = $params['userid'];
+        if (empty($userid)) {
+            $userid = $USER->id;
+        }
+
+        $systemcontext = context_system::instance();
+        self::validate_context($systemcontext);
+
+        if ($USER->id != $userid) {
+            // We must check if the current user can view other users grades.
+            $user = core_user::get_user($userid, '*', MUST_EXIST);
+            core_user::require_active_user($user);
+            require_capability('moodle/grade:viewall', $systemcontext);
+        }
+
+        // We need the site course, and course context.
+        $course = get_course(SITEID);
+        $context = context_course::instance($course->id);
+
+        // Force a regrade if required.
+        grade_regrade_final_grades_if_required($course);
+        // Get the course final grades now.
+        $gpr = new grade_plugin_return(array('type' => 'report', 'plugin' => 'overview', 'courseid' => $course->id,
+                                        'userid' => $userid));
+        $report = new grade_report_overview($userid, $gpr, $context);
+        $coursesgrades = $report->setup_courses_data(true);
+
+        $grades = array();
+        foreach ($coursesgrades as $coursegrade) {
+            $gradeinfo = array(
+                'courseid' => $coursegrade['course']->id,
+                'grade' => grade_format_gradevalue($coursegrade['finalgrade'], $coursegrade['courseitem'], true),
+                'rawgrade' => $coursegrade['finalgrade'],
+            );
+            if (isset($coursegrade['rank'])) {
+                $gradeinfo['rank'] = $coursegrade['rank'];
+            }
+            $grades[] = $gradeinfo;
+        }
+
+        $result = array();
+        $result['grades'] = $grades;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Describes the get_course_grades return value.
+     *
+     * @return external_single_structure
+     * @since Moodle 3.2
+     */
+    public static function get_course_grades_returns() {
+        return new external_single_structure(
+            array(
+                'grades' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'courseid' => new external_value(PARAM_INT, 'Course id'),
+                            'grade' => new external_value(PARAM_RAW, 'Grade formatted'),
+                            'rawgrade' => new external_value(PARAM_RAW, 'Raw grade, not formatted'),
+                            'rank' => new external_value(PARAM_INT, 'Your rank in the course', VALUE_OPTIONAL),
+                        )
+                    )
+                ),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
+
+    /**
+     * Returns description of method parameters
+     *
+     * @return external_function_parameters
+     * @since Moodle 3.2
+     */
+    public static function view_grade_report_parameters() {
+        return new external_function_parameters(
+            array(
+                'courseid' => new external_value(PARAM_INT, 'id of the course'),
+                'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0)
+            )
+        );
+    }
+
+    /**
+     * Trigger the user report events, do the same that the web interface view of the report
+     *
+     * @param int $courseid id of course
+     * @param int $userid id of the user the report belongs to
+     * @return array of warnings and status result
+     * @since Moodle 3.2
+     * @throws moodle_exception
+     */
+    public static function view_grade_report($courseid, $userid = 0) {
+        global $USER;
+
+        $params = self::validate_parameters(self::view_grade_report_parameters(),
+            array(
+                'courseid' => $courseid,
+                'userid' => $userid
+            )
+        );
+
+        $warnings = array();
+        $course = get_course($params['courseid']);
+
+        $context = context_course::instance($course->id);
+        self::validate_context($context);
+
+        $userid = $params['userid'];
+        if (empty($userid)) {
+            $userid = $USER->id;
+        } else {
+            $user = core_user::get_user($userid, '*', MUST_EXIST);
+            core_user::require_active_user($user);
+        }
+        $systemcontext = context_system::instance();
+        $personalcontext = context_user::instance($userid);
+
+        $access = grade_report_overview::check_access($systemcontext, $context, $personalcontext, $course, $userid);
+
+        if (!$access) {
+            throw new moodle_exception('nopermissiontoviewgrades', 'error');
+        }
+
+        grade_report_overview::viewed($context, $course->id, $userid);
+
+        $result = array();
+        $result['status'] = true;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Returns description of method result value
+     *
+     * @return external_description
+     * @since Moodle 3.2
+     */
+    public static function view_grade_report_returns() {
+        return new external_single_structure(
+            array(
+                'status' => new external_value(PARAM_BOOL, 'status: true if success'),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
+}
diff --git a/grade/report/overview/db/services.php b/grade/report/overview/db/services.php
new file mode 100644 (file)
index 0000000..56f4ea8
--- /dev/null
@@ -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/>.
+
+/**
+ * Overview grade report external functions and service definitions.
+ *
+ * @package    gradereport_overview
+ * @copyright  2016 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$functions = array(
+
+    'gradereport_overview_get_course_grades' => array(
+        'classname' => 'gradereport_overview_external',
+        'methodname' => 'get_course_grades',
+        'description' => 'Get the given user courses final grades',
+        'type' => 'read',
+        'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+    ),
+    'gradereport_overview_view_grade_report' => array(
+        'classname' => 'gradereport_overview_external',
+        'methodname' => 'view_grade_report',
+        'description' => 'Trigger the report view event',
+        'type' => 'write',
+        'capabilities' => 'gradereport/overview:view',
+        'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+    )
+);
index 14eef55..4125157 100644 (file)
@@ -71,27 +71,7 @@ if ($userid == $USER->id) {
     $PAGE->navigation->extend_for_user($user);
 }
 
-$access = false;
-if (has_capability('moodle/grade:viewall', $systemcontext)) {
-    // Ok - can view all course grades.
-    $access = true;
-
-} else if (has_capability('moodle/grade:viewall', $context)) {
-    // Ok - can view any grades in context.
-    $access = true;
-
-} else if ($userid == $USER->id and ((has_capability('moodle/grade:view', $context) and $course->showgrades)
-        || $courseid == SITEID)) {
-    // Ok - can view own course grades.
-    $access = true;
-
-} else if (has_capability('moodle/grade:viewall', $personalcontext) and $course->showgrades) {
-    // Ok - can view grades of this user - parent most probably.
-    $access = true;
-} else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and $course->showgrades) {
-    // Ok - can view grades of this user - parent most probably.
-    $access = true;
-}
+$access = grade_report_overview::check_access($systemcontext, $context, $personalcontext, $course, $userid);
 
 if (!$access) {
     // no access to grades!
@@ -214,15 +194,6 @@ if (has_capability('moodle/grade:viewall', $context) && $courseid != SITEID) {
     }
 }
 
-$event = \gradereport_overview\event\grade_report_viewed::create(
-    array(
-        'context' => $context,
-        'courseid' => $courseid,
-        'relateduserid' => $userid,
-    )
-);
-$event->trigger();
+grade_report_overview::viewed($context, $courseid, $userid);
 
 echo $OUTPUT->footer();
-
-
index 923fc2f..d8bf895 100644 (file)
@@ -164,6 +164,97 @@ class grade_report_overview extends grade_report {
         $this->table->setup();
     }
 
+    /**
+     * Set up the courses grades data for the report.
+     *
+     * @param bool $studentcoursesonly Only show courses that the user is a student of.
+     * @return array of course grades information
+     */
+    public function setup_courses_data($studentcoursesonly) {
+        global $USER, $DB;
+
+        $coursesdata = array();
+        $numusers = $this->get_numusers(false);
+
+        foreach ($this->courses as $course) {
+            if (!$course->showgrades) {
+                continue;
+            }
+
+            // If we are only showing student courses and this course isn't part of the group, then move on.
+            if ($studentcoursesonly && !isset($this->studentcourseids[$course->id])) {
+                continue;
+            }
+
+            $coursecontext = context_course::instance($course->id);
+
+            if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
+                // The course is hidden and the user isn't allowed to see it.
+                continue;
+            }
+
+            if (!has_capability('moodle/user:viewuseractivitiesreport', context_user::instance($this->user->id)) &&
+                    ((!has_capability('moodle/grade:view', $coursecontext) || $this->user->id != $USER->id) &&
+                    !has_capability('moodle/grade:viewall', $coursecontext))) {
+                continue;
+            }
+
+            $coursesdata[$course->id]['course'] = $course;
+            $coursesdata[$course->id]['context'] = $coursecontext;
+
+            $canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext);
+
+            // Get course grade_item.
+            $courseitem = grade_item::fetch_course_item($course->id);
+
+            // Get the stored grade.
+            $coursegrade = new grade_grade(array('itemid' => $courseitem->id, 'userid' => $this->user->id));
+            $coursegrade->grade_item =& $courseitem;
+            $finalgrade = $coursegrade->finalgrade;
+
+            if (!$canviewhidden and !is_null($finalgrade)) {
+                if ($coursegrade->is_hidden()) {
+                    $finalgrade = null;
+                } else {
+                    $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($course->id,
+                                                                                 $courseitem,
+                                                                                 $finalgrade);
+
+                    // We temporarily adjust the view of this grade item - because the min and
+                    // max are affected by the hidden values in the aggregation.
+                    $finalgrade = $adjustedgrade['grade'];
+                    $courseitem->grademax = $adjustedgrade['grademax'];
+                    $courseitem->grademin = $adjustedgrade['grademin'];
+                }
+            } else {
+                // We must use the specific max/min because it can be different for
+                // each grade_grade when items are excluded from sum of grades.
+                if (!is_null($finalgrade)) {
+                    $courseitem->grademin = $coursegrade->get_grade_min();
+                    $courseitem->grademax = $coursegrade->get_grade_max();
+                }
+            }
+
+            $coursesdata[$course->id]['finalgrade'] = $finalgrade;
+            $coursesdata[$course->id]['courseitem'] = $courseitem;
+
+            if ($this->showrank['any'] && $this->showrank[$course->id] && !is_null($finalgrade)) {
+                // Find the number of users with a higher grade.
+                // Please note this can not work if hidden grades involved :-( to be fixed in 2.0.
+                $params = array($finalgrade, $courseitem->id);
+                $sql = "SELECT COUNT(DISTINCT(userid))
+                          FROM {grade_grades}
+                         WHERE finalgrade IS NOT NULL AND finalgrade > ?
+                               AND itemid = ?";
+                $rank = $DB->count_records_sql($sql, $params) + 1;
+
+                $coursesdata[$course->id]['rank'] = $rank;
+                $coursesdata[$course->id]['numusers'] = $numusers;
+            }
+        }
+        return $coursesdata;
+    }
+
     /**
      * Fill the table for displaying.
      *
@@ -179,30 +270,14 @@ class grade_report_overview extends grade_report {
 
         // Only show user's courses instead of all courses.
         if ($this->courses) {
-            $numusers = $this->get_numusers(false);
-
-            foreach ($this->courses as $course) {
-                if (!$course->showgrades) {
-                    continue;
-                }
-
-                // If we are only showing student courses and this course isn't part of the group, then move on.
-                if ($studentcoursesonly && !isset($this->studentcourseids[$course->id])) {
-                    continue;
-                }
-
-                $coursecontext = context_course::instance($course->id);
+            $coursesdata = $this->setup_courses_data($studentcoursesonly);
 
-                if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
-                    // The course is hidden and the user isn't allowed to see it
-                    continue;
-                }
+            foreach ($coursesdata as $coursedata) {
 
-                if (!has_capability('moodle/user:viewuseractivitiesreport', context_user::instance($this->user->id)) &&
-                        ((!has_capability('moodle/grade:view', $coursecontext) || $this->user->id != $USER->id) &&
-                        !has_capability('moodle/grade:viewall', $coursecontext))) {
-                    continue;
-                }
+                $course = $coursedata['course'];
+                $coursecontext = $coursedata['context'];
+                $finalgrade = $coursedata['finalgrade'];
+                $courseitem = $coursedata['courseitem'];
 
                 $coursename = format_string(get_course_display_name_for_list($course), true, array('context' => $coursecontext));
                 // Link to the activity report version of the user grade report.
@@ -213,66 +288,25 @@ class grade_report_overview extends grade_report {
                     $courselink = html_writer::link(new moodle_url('/grade/report/user/index.php', array('id' => $course->id,
                         'userid' => $this->user->id)), $coursename);
                 }
-                $canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext);
-
-                // Get course grade_item
-                $course_item = grade_item::fetch_course_item($course->id);
 
-                // Get the stored grade
-                $course_grade = new grade_grade(array('itemid'=>$course_item->id, 'userid'=>$this->user->id));
-                $course_grade->grade_item =& $course_item;
-                $finalgrade = $course_grade->finalgrade;
+                $data = array($courselink, grade_format_gradevalue($finalgrade, $courseitem, true));
 
-                if (!$canviewhidden and !is_null($finalgrade)) {
-                    if ($course_grade->is_hidden()) {
-                        $finalgrade = null;
+                if ($this->showrank['any']) {
+                    if ($this->showrank[$course->id] && !is_null($finalgrade)) {
+                        $rank = $coursedata['rank'];
+                        $numusers = $coursedata['numusers'];
+                        $data[] = "$rank/$numusers";
                     } else {
-                        $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($course->id,
-                                                                                     $course_item,
-                                                                                     $finalgrade);
-
-                        // We temporarily adjust the view of this grade item - because the min and
-                        // max are affected by the hidden values in the aggregation.
-                        $finalgrade = $adjustedgrade['grade'];
-                        $course_item->grademax = $adjustedgrade['grademax'];
-                        $course_item->grademin = $adjustedgrade['grademin'];
+                        // No grade, no rank.
+                        // Or this course wants rank hidden.
+                        $data[] = '-';
                     }
-                } else {
-                    // We must use the specific max/min because it can be different for
-                    // each grade_grade when items are excluded from sum of grades.
-                    if (!is_null($finalgrade)) {
-                        $course_item->grademin = $course_grade->get_grade_min();
-                        $course_item->grademax = $course_grade->get_grade_max();
-                    }
-                }
-
-                $data = array($courselink, grade_format_gradevalue($finalgrade, $course_item, true));
-
-                if (!$this->showrank['any']) {
-                    //nothing to do
-
-                } else if ($this->showrank[$course->id] && !is_null($finalgrade)) {
-                    /// find the number of users with a higher grade
-                    /// please note this can not work if hidden grades involved :-( to be fixed in 2.0
-                    $params = array($finalgrade, $course_item->id);
-                    $sql = "SELECT COUNT(DISTINCT(userid))
-                              FROM {grade_grades}
-                             WHERE finalgrade IS NOT NULL AND finalgrade > ?
-                                   AND itemid = ?";
-                    $rank = $DB->count_records_sql($sql, $params) + 1;
-
-                    $data[] = "$rank/$numusers";
-
-                } else {
-                    // No grade, no rank.
-                    // Or this course wants rank hidden.
-                    $data[] = '-';
                 }
 
                 $this->table->add_data($data);
             }
-            return true;
 
+            return true;
         } else {
             echo $OUTPUT->notification(get_string('notenrolled', 'grades'), 'notifymessage');
             return false;
@@ -325,6 +359,63 @@ class grade_report_overview extends grade_report {
     public static function supports_mygrades() {
         return true;
     }
+
+    /**
+     * Check if the user can access the report.
+     *
+     * @param  stdClass $systemcontext   system context
+     * @param  stdClass $context         course context
+     * @param  stdClass $personalcontext personal context
+     * @param  stdClass $course          course object
+     * @param  int $userid               userid
+     * @return bool true if the user can access the report
+     * @since  Moodle 3.2
+     */
+    public static function check_access($systemcontext, $context, $personalcontext, $course, $userid) {
+        global $USER;
+
+        $access = false;
+        if (has_capability('moodle/grade:viewall', $systemcontext)) {
+            // Ok - can view all course grades.
+            $access = true;
+
+        } else if (has_capability('moodle/grade:viewall', $context)) {
+            // Ok - can view any grades in context.
+            $access = true;
+
+        } else if ($userid == $USER->id and ((has_capability('moodle/grade:view', $context) and $course->showgrades)
+                || $course->id == SITEID)) {
+            // Ok - can view own course grades.
+            $access = true;
+
+        } else if (has_capability('moodle/grade:viewall', $personalcontext) and $course->showgrades) {
+            // Ok - can view grades of this user - parent most probably.
+            $access = true;
+        } else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and $course->showgrades) {
+            // Ok - can view grades of this user - parent most probably.
+            $access = true;
+        }
+        return $access;
+    }
+
+    /**
+     * Trigger the grade_report_viewed event
+     *
+     * @param  stdClass $context  course context
+     * @param  int $courseid      course id
+     * @param  int $userid        user id
+     * @since Moodle 3.2
+     */
+    public static function viewed($context, $courseid, $userid) {
+        $event = \gradereport_overview\event\grade_report_viewed::create(
+            array(
+                'context' => $context,
+                'courseid' => $courseid,
+                'relateduserid' => $userid,
+            )
+        );
+        $event->trigger();
+    }
 }
 
 function grade_report_overview_settings_definition(&$mform) {
diff --git a/grade/report/overview/tests/externallib_test.php b/grade/report/overview/tests/externallib_test.php
new file mode 100644 (file)
index 0000000..1301c0d
--- /dev/null
@@ -0,0 +1,231 @@
+<?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/>.
+
+/**
+ * Overview grade report functions unit tests
+ *
+ * @package    gradereport_overview
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@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 . '/webservice/tests/helpers.php');
+
+/**
+ * Overview grade report functions unit tests
+ *
+ * @package    gradereport_overview
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class gradereport_overview_externallib_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Set up for every test
+     */
+    public function setUp() {
+        global $DB;
+        $this->resetAfterTest(true);
+
+        $s1grade1 = 80;
+        $s1grade2 = 40;
+        $s2grade = 60;
+
+        $this->course1 = $this->getDataGenerator()->create_course();
+        $this->course2 = $this->getDataGenerator()->create_course();
+
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
+        $this->student1 = $this->getDataGenerator()->create_user();
+        $this->teacher = $this->getDataGenerator()->create_user();
+        $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course1->id, $teacherrole->id);
+        $this->getDataGenerator()->enrol_user($this->student1->id, $this->course1->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($this->student1->id, $this->course2->id, $studentrole->id);
+
+        $this->student2 = $this->getDataGenerator()->create_user();
+        $this->getDataGenerator()->enrol_user($this->student2->id, $this->course1->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($this->student2->id, $this->course2->id, $studentrole->id);
+
+        $assignment1 = $this->getDataGenerator()->create_module('assign', array('name' => "Test assign", 'course' => $this->course1->id));
+        $assignment2 = $this->getDataGenerator()->create_module('assign', array('name' => "Test assign", 'course' => $this->course2->id));
+        $modcontext1 = get_coursemodule_from_instance('assign', $assignment1->id, $this->course1->id);
+        $modcontext2 = get_coursemodule_from_instance('assign', $assignment2->id, $this->course2->id);
+        $assignment1->cmidnumber = $modcontext1->id;
+        $assignment2->cmidnumber = $modcontext2->id;
+
+        $this->student1grade1 = array('userid' => $this->student1->id, 'rawgrade' => $s1grade1);
+        $this->student1grade2 = array('userid' => $this->student1->id, 'rawgrade' => $s1grade2);
+        $this->student2grade = array('userid' => $this->student2->id, 'rawgrade' => $s2grade);
+        $studentgrades = array($this->student1->id => $this->student1grade1, $this->student2->id => $this->student2grade);
+        assign_grade_item_update($assignment1, $studentgrades);
+        $studentgrades = array($this->student1->id => $this->student1grade2);
+        assign_grade_item_update($assignment2, $studentgrades);
+
+        grade_get_setting($this->course1->id, 'report_overview_showrank', 1);
+    }
+
+    /**
+     * Test get_course_grades function case student
+     */
+    public function test_get_course_grades_student() {
+
+        // A user can see his own grades in both courses.
+        $this->setUser($this->student1);
+        $studentgrades = gradereport_overview_external::get_course_grades();
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(2, $studentgrades['grades']);
+        foreach ($studentgrades['grades'] as $grade) {
+            if ($grade['courseid'] == $this->course1->id) {
+                $this->assertEquals(80.00, $grade['grade']);
+                $this->assertEquals(80.0000, $grade['rawgrade']);
+                $this->assertEquals(1, $grade['rank']);
+            } else {
+                $this->assertEquals(40.00, $grade['grade']);
+                $this->assertEquals(40.0000, $grade['rawgrade']);
+                $this->assertArrayNotHasKey('rank', $grade);
+            }
+        }
+
+        // Second student, no grade in one course.
+        $this->setUser($this->student2);
+        $studentgrades = gradereport_overview_external::get_course_grades();
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(2, $studentgrades['grades']);
+        foreach ($studentgrades['grades'] as $grade) {
+            if ($grade['courseid'] == $this->course1->id) {
+                $this->assertEquals(60.00, $grade['grade']);
+                $this->assertEquals(60.0000, $grade['rawgrade']);
+                $this->assertEquals(2, $grade['rank']);
+            } else {
+                $this->assertEquals('-', $grade['grade']);
+                $this->assertEmpty($grade['rawgrade']);
+                $this->assertArrayNotHasKey('rank', $grade);
+            }
+        }
+    }
+
+    /**
+     * Test get_course_grades function case admin
+     */
+    public function test_get_course_grades_admin() {
+
+        // A admin must see all student grades.
+        $this->setAdminUser();
+
+        $studentgrades = gradereport_overview_external::get_course_grades($this->student1->id);
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(2, $studentgrades['grades']);
+        foreach ($studentgrades['grades'] as $grade) {
+            if ($grade['courseid'] == $this->course1->id) {
+                $this->assertEquals(80.00, $grade['grade']);
+                $this->assertEquals(80.0000, $grade['rawgrade']);
+            } else {
+                $this->assertEquals(40.00, $grade['grade']);
+                $this->assertEquals(40.0000, $grade['rawgrade']);
+            }
+        }
+
+        $studentgrades = gradereport_overview_external::get_course_grades($this->student2->id);
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(2, $studentgrades['grades']);
+
+        // Admins don't see grades.
+        $studentgrades = gradereport_overview_external::get_course_grades();
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(0, $studentgrades['grades']);
+    }
+
+    /**
+     * Test get_course_grades function case teacher
+     */
+    public function test_get_course_grades_teacher() {
+        // Teachers don't see grades.
+        $this->setUser($this->teacher);
+
+        $studentgrades = gradereport_overview_external::get_course_grades();
+        $studentgrades = external_api::clean_returnvalue(gradereport_overview_external::get_course_grades_returns(), $studentgrades);
+        $this->assertCount(0, $studentgrades['warnings']);
+        $this->assertCount(0, $studentgrades['grades']);
+    }
+
+    /**
+     * Test get_course_grades function case incorrect permissions
+     */
+    public function test_get_course_grades_permissions() {
+        // Student can't see other student grades.
+        $this->setUser($this->student2);
+
+        $this->expectException('required_capability_exception');
+        $studentgrade = gradereport_overview_external::get_course_grades($this->student1->id);
+    }
+
+    /**
+     * Test view_grade_report function
+     */
+    public function test_view_grade_report() {
+        global $USER;
+
+        // Redirect events to the sink, so we can recover them later.
+        $sink = $this->redirectEvents();
+
+        $this->setUser($this->student1);
+        $result = gradereport_overview_external::view_grade_report($this->course1->id);
+        $result = external_api::clean_returnvalue(gradereport_overview_external::view_grade_report_returns(), $result);
+        $events = $sink->get_events();
+        $this->assertCount(1, $events);
+        $event = reset($events);
+
+        // Check the event details are correct.
+        $this->assertInstanceOf('\gradereport_overview\event\grade_report_viewed', $event);
+        $this->assertEquals(context_course::instance($this->course1->id), $event->get_context());
+        $this->assertEquals($USER->id, $event->get_data()['relateduserid']);
+
+        $this->setUser($this->teacher);
+        $result = gradereport_overview_external::view_grade_report($this->course1->id, $this->student1->id);
+        $result = external_api::clean_returnvalue(gradereport_overview_external::view_grade_report_returns(), $result);
+        $events = $sink->get_events();
+        $event = reset($events);
+        $sink->close();
+
+        // Check the event details are correct.
+        $this->assertInstanceOf('\gradereport_overview\event\grade_report_viewed', $event);
+        $this->assertEquals(context_course::instance($this->course1->id), $event->get_context());
+        $this->assertEquals($this->student1->id, $event->get_data()['relateduserid']);
+    }
+
+    /**
+     * Test view_grade_report_permissions function
+     */
+    public function test_view_grade_report_permissions() {
+        $this->setUser($this->student2);
+
+        $this->expectException('moodle_exception');
+        $studentgrade = gradereport_overview_external::view_grade_report($this->course1->id, $this->student1->id);
+    }
+}
index 686718e..aeb122f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2016052300;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2016052301;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2016051900;        // Requires this Moodle version
 $plugin->component = 'gradereport_overview'; // Full name of the plugin (used for diagnostics)
index 1e8460e..cad859f 100644 (file)
@@ -29,9 +29,16 @@ require_once $CFG->dirroot.'/grade/report/user/lib.php';
 
 $courseid = required_param('id', PARAM_INT);
 $userid   = optional_param('userid', $USER->id, PARAM_INT);
+$userview = optional_param('userview', 0, PARAM_INT);
 
 $PAGE->set_url(new moodle_url('/grade/report/user/index.php', array('id'=>$courseid)));
 
+if ($userview == 0) {
+    $userview = get_user_preferences('gradereport_user_view_user', GRADE_REPORT_USER_VIEW_USER);
+} else {
+    set_user_preference('gradereport_user_view_user', $userview);
+}
+
 /// basic access checks
 if (!$course = $DB->get_record('course', array('id' => $courseid))) {
     print_error('nocourseid');
@@ -103,6 +110,15 @@ if (has_capability('moodle/grade:viewall', $context)) { //Teachers will see all
     $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
     $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
     $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context);
+
+    $renderer = $PAGE->get_renderer('gradereport_user');
+
+    if ($userview == GRADE_REPORT_USER_VIEW_USER) {
+        $viewasuser = true;
+    } else {
+        $viewasuser = false;
+    }
+
     if (empty($userid)) {
         $gui = new graded_users_iterator($course, null, $currentgroup);
         $gui->require_active_enrolment($showonlyactiveenrol);
@@ -112,13 +128,14 @@ if (has_capability('moodle/grade:viewall', $context)) { //Teachers will see all
         groups_print_course_menu($course, $gpr->get_return_url('index.php?id='.$courseid, array('userid'=>0)));
 
         if ($user_selector) {
-            $renderer = $PAGE->get_renderer('gradereport_user');
             echo $renderer->graded_users_selector('user', $course, $userid, $currentgroup, true);
         }
 
+        echo $renderer->view_user_selector($userid, $userview);
+
         while ($userdata = $gui->next_user()) {
             $user = $userdata->user;
-            $report = new grade_report_user($courseid, $gpr, $context, $user->id);
+            $report = new grade_report_user($courseid, $gpr, $context, $user->id, $viewasuser);
 
             $studentnamelink = html_writer::link(new moodle_url('/user/view.php', array('id' => $report->user->id, 'course' => $courseid)), fullname($report->user));
             echo $OUTPUT->heading(get_string('pluginname', 'gradereport_user') . ' - ' . $studentnamelink);
@@ -130,7 +147,7 @@ if (has_capability('moodle/grade:viewall', $context)) { //Teachers will see all
         }
         $gui->close();
     } else { // Only show one user's report
-        $report = new grade_report_user($courseid, $gpr, $context, $userid);
+        $report = new grade_report_user($courseid, $gpr, $context, $userid, $viewasuser);
 
         $studentnamelink = html_writer::link(new moodle_url('/user/view.php', array('id' => $report->user->id, 'course' => $courseid)), fullname($report->user));
         print_grade_page_head($courseid, 'report', 'user', get_string('pluginname', 'gradereport_user') . ' - ' . $studentnamelink,
@@ -139,11 +156,12 @@ if (has_capability('moodle/grade:viewall', $context)) { //Teachers will see all
         groups_print_course_menu($course, $gpr->get_return_url('index.php?id='.$courseid, array('userid'=>0)));
 
         if ($user_selector) {
-            $renderer = $PAGE->get_renderer('gradereport_user');
             $showallusersoptions = true;
             echo $renderer->graded_users_selector('user', $course, $userid, $currentgroup, $showallusersoptions);
         }
 
+        echo $renderer->view_user_selector($userid, $userview);
+
         if ($currentgroup and !groups_is_member($currentgroup, $userid)) {
             echo $OUTPUT->notification(get_string('groupusernotmember', 'error'));
         } else {
index bf3f097..953b1e7 100644 (file)
@@ -25,4 +25,7 @@
 $string['eventgradereportviewed'] = 'Grade user report viewed';
 $string['pluginname'] = 'User report';
 $string['user:view'] = 'View your own grade report';
+$string['myself'] = 'Myself';
+$string['otheruser'] = 'User';
 $string['tablesummary'] = 'The table is arranged as a list of graded items including categories of graded items. When items are in a category they will be indicated as such.';
+$string['viewas'] = 'View report as';
index a6f15d1..c6978e4 100644 (file)
@@ -30,6 +30,9 @@ define("GRADE_REPORT_USER_HIDE_HIDDEN", 0);
 define("GRADE_REPORT_USER_HIDE_UNTIL", 1);
 define("GRADE_REPORT_USER_SHOW_HIDDEN", 2);
 
+define("GRADE_REPORT_USER_VIEW_SELF", 1);
+define("GRADE_REPORT_USER_VIEW_USER", 2);
+
 /**
  * Class providing an API for the user report building and displaying.
  * @uses grade_report
index c0270f3..7062bdd 100644 (file)
@@ -43,4 +43,29 @@ class gradereport_user_renderer extends plugin_renderer_base {
         return $output;
     }
 
+    /**
+     * Creates and renders the single select box for the user view.
+     *
+     * @param int $userid The selected userid
+     * @param int $userview The current view user setting constant
+     * @return string
+     */
+    public function view_user_selector($userid, $userview) {
+        global $PAGE, $USER;
+        $url = $PAGE->url;
+        if ($userid != $USER->id) {
+            $url->param('userid', $userid);
+        }
+
+        $options = array(GRADE_REPORT_USER_VIEW_USER => get_string('otheruser', 'gradereport_user'),
+                GRADE_REPORT_USER_VIEW_SELF => get_string('myself', 'gradereport_user'));
+        $select = new single_select($url, 'userview', $options, $userview, null);
+
+        $select->label = get_string('viewas', 'gradereport_user');
+
+        $output = html_writer::tag('div', $this->output->render($select), array('class' => 'view_users_selector'));
+
+        return $output;
+    }
+
 }
index fc336a0..7b94533 100644 (file)
@@ -3,7 +3,14 @@
     margin-bottom: 5px;
 }
 
-.path-grade-report-user #graded_users_selector .singleselect label {
+.path-grade-report-user .view_users_selector {
+    clear: both;
+    float: right;
+    margin-bottom: 5px;
+}
+
+.path-grade-report-user #graded_users_selector .singleselect label,
+.path-grade-report-user .view_users_selector .singleselect label {
     display: inline-block;
 }
 
diff --git a/grade/report/user/tests/behat/user_view.feature b/grade/report/user/tests/behat/user_view.feature
new file mode 100644 (file)
index 0000000..01794bf
--- /dev/null
@@ -0,0 +1,218 @@
+@core @core_grades @gradereport_user
+Feature: View the user report as the student will see it
+  In order to know what grades students will see
+  As a teacher
+  I need to be able to view the user report as that other user
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category | groupmode |
+      | Course 1 | C1 | 0 | 1 |
+    And the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | teacher1 | Teacher | 1 | teacher1@example.com | t1 |
+      | student1 | Student | 1 | student1@example.com | s1 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And the following "grade categories" exist:
+      | fullname | course |
+      | Sub category 1 | C1 |
+      | Sub category 2 | C1 |
+    And the following "activities" exist:
+      | activity | course | idnumber | name | intro | gradecategory| grade |
+      | assign | C1 | a1 | Test assignment one | Submit something! | Sub category 1 | 100 |
+      | assign | C1 | a2 | Test assignment two | Submit something! | Sub category 1 | 100 |
+      | assign | C1 | a3 | Test assignment three | Submit something! | Sub category 2 | 100 |
+      | assign | C1 | a4 | Test assignment four | Submit something! | Sub category 2 | 100 |
+    And the following "activities" exist:
+      | activity | course | idnumber | name | intro | grade |
+      | assign | C1 | a5 | Test assignment five | Submit something! | 100 |
+      | assign | C1 | a6 | Test assignment six | Submit something! | 100 |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I navigate to "Gradebook setup" node in "Course administration"
+    And I hide the grade item "Test assignment six"
+    And I hide the grade item "Sub category 2"
+    And I navigate to "Grades" node in "Course administration"
+    And I turn editing mode on
+    And I change window size to "large"
+    And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment one"
+    And I give the grade "35.00" to the user "Student 1" for the grade item "Test assignment two"
+    And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment three"
+    And I give the grade "50.00" to the user "Student 1" for the grade item "Test assignment four"
+    And I give the grade "21.00" to the user "Student 1" for the grade item "Test assignment five"
+    And I give the grade "97.00" to the user "Student 1" for the grade item "Test assignment six"
+    And I press "Save changes"
+    And I change window size to "medium"
+
+  Scenario: View the report as the teacher themselves
+    When I navigate to "User report" node in "Grade administration"
+    And I select "Student 1" from the "Select all or one user" singleselect
+    And I select "Myself" from the "View report as" singleselect
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 13.33 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 5.83 %                       |
+      | Sub category 1 total    | 33.33 %           | 115.00 | 0–200 | 57.50 %    | -                            |
+      | Test assignment three   | 50.00 %           | 100.00 | 0–100 | 100.00 %   | 16.67 %                      |
+      | Test assignment four    | 50.00 %           | 50.00  | 0–100 | 50.00 %    | 8.33 %                       |
+      | Sub category 2 total    | 33.33 %           | 150.00 | 0–200 | 75.00 %    | -                            |
+      | Test assignment five    | 16.67 %           | 21.00  | 0–100 | 21.00 %    | 3.50 %                       |
+      | Test assignment six     | 16.67 %           | 97.00  | 0–100 | 97.00 %    | 16.17 %                      |
+      | Course total            | -                 | 383.00 | 0–600 | 63.83 %    | -                            |
+
+  Scenario: View the report as the student from both the teachers and students perspective
+    When I navigate to "User report" node in "Grade administration"
+    And I select "Student 1" from the "Select all or one user" singleselect
+    And I select "User" from the "View report as" singleselect
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | -                 | 80.00  | 0–100 | 80.00 %    | -                            |
+      | Test assignment two     | -                 | 35.00  | 0–100 | 35.00 %    | -                            |
+      | Sub category 1 total    | 33.33 %           | -      | 0–200 | -          | -                            |
+      | Test assignment five    | -                 | 21.00  | 0–100 | 21.00 %    | -                            |
+      | Course total            | -                 | -      | 0–600 | -          | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I navigate to "Grades" node in "Course administration"
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | -                 | 80.00  | 0–100 | 80.00 %    | -                            |
+      | Test assignment two     | -                 | 35.00  | 0–100 | 35.00 %    | -                            |
+      | Sub category 1 total    | 33.33 %           | -      | 0–200 | -          | -                            |
+      | Test assignment five    | -                 | 21.00  | 0–100 | 21.00 %    | -                            |
+      | Course total            | -                 | -      | 0–600 | -          | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+
+  Scenario: View the report as the student from both the teachers and students perspective with totals excluding hidden
+    Given I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
+    And I press "Save changes"
+    And I navigate to "User report" node in "Grade administration"
+    When I select "Student 1" from the "Select all or one user" singleselect
+    And I select "User" from the "View report as" singleselect
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 26.67 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 11.67 %                      |
+      | Sub category 1 total    | 66.67 %           | 115.00 | 0–200 | 57.50      | -                            |
+      | Test assignment five    | 33.33 %           | 21.00  | 0–100 | 21.00 %    | 7.00 %                       |
+      | Course total            | -                 | 136.00 | 0–300 | 45.33 %    | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I navigate to "Grades" node in "Course administration"
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 26.67 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 11.67 %                      |
+      | Sub category 1 total    | 66.67 %           | 115.00 | 0–200 | 57.50      | -                            |
+      | Test assignment five    | 33.33 %           | 21.00  | 0–100 | 21.00 %    | 7.00 %                       |
+      | Course total            | -                 | 136.00 | 0–300 | 45.33 %    | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+
+  Scenario: View the report as the student from both the teachers and students perspective with totals including hidden
+    Given I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals including hidden items"
+    And I press "Save changes"
+    And I navigate to "User report" node in "Grade administration"
+    When I select "Student 1" from the "Select all or one user" singleselect
+    And I select "User" from the "View report as" singleselect
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 13.33 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 5.83 %                       |
+      | Sub category 1 total    | 33.33 %           | 115.00 | 0–200 | 57.50 %    | -                            |
+      | Test assignment five    | 16.67 %           | 21.00  | 0–100 | 21.00 %    | 3.50 %                       |
+      | Course total            | -                 | 383.00 | 0–600 | 63.83 %    | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I navigate to "Grades" node in "Course administration"
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 13.33 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 5.83 %                       |
+      | Sub category 1 total    | 33.33 %           | 115.00 | 0–200 | 57.50 %    | -                            |
+      | Test assignment five    | 16.67 %           | 21.00  | 0–100 | 21.00 %    | 3.50 %                       |
+      | Course total            | -                 | 383.00 | 0–600 | 63.83 %    | -                            |
+    And the following should not exist in the "user-grade" table:
+      | Grade item              |
+      | Test assignment three   |
+      | Test assignment four    |
+      | Sub category 2 total    |
+      | Test assignment six     |
+
+  Scenario: View the report as the student from both the teachers and students perspective when the student can view hidden
+    Given I log out
+    And I log in as "admin"
+    And I set the following system permissions of "Student" role:
+      | capability | permission |
+      | moodle/grade:viewhidden | Allow |
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I navigate to "Gradebook setup" node in "Course administration"
+    And I navigate to "Course grade settings" node in "Grade administration > Setup"
+    And I set the field with xpath "//select[@name='report_user_showtotalsifcontainhidden']" to "Show totals excluding hidden items"
+    And I press "Save changes"
+    And I navigate to "User report" node in "Grade administration"
+    When I select "Student 1" from the "Select all or one user" singleselect
+    And I select "User" from the "View report as" singleselect
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 13.33 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 5.83 %                       |
+      | Sub category 1 total    | 33.33 %           | 115.00 | 0–200 | 57.50 %    | -                            |
+      | Test assignment three   | 50.00 %           | 100.00 | 0–100 | 100.00 %   | 16.67 %                      |
+      | Test assignment four    | 50.00 %           | 50.00  | 0–100 | 50.00 %    | 8.33 %                       |
+      | Sub category 2 total    | 33.33 %           | 150.00 | 0–200 | 75.00 %    | -                            |
+      | Test assignment five    | 16.67 %           | 21.00  | 0–100 | 21.00 %    | 3.50 %                       |
+      | Test assignment six     | 16.67 %           | 97.00  | 0–100 | 97.00 %    | 16.17 %                      |
+      | Course total            | -                 | 383.00 | 0–600 | 63.83 %    | -                            |
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I navigate to "Grades" node in "Course administration"
+    Then the following should exist in the "user-grade" table:
+      | Grade item              | Calculated weight | Grade  | Range | Percentage | Contribution to course total |
+      | Test assignment one     | 50.00 %           | 80.00  | 0–100 | 80.00 %    | 13.33 %                      |
+      | Test assignment two     | 50.00 %           | 35.00  | 0–100 | 35.00 %    | 5.83 %                       |
+      | Sub category 1 total    | 33.33 %           | 115.00 | 0–200 | 57.50 %    | -                            |
+      | Test assignment three   | 50.00 %           | 100.00 | 0–100 | 100.00 %   | 16.67 %                      |
+      | Test assignment four    | 50.00 %           | 50.00  | 0–100 | 50.00 %    | 8.33 %                       |
+      | Sub category 2 total    | 33.33 %           | 150.00 | 0–200 | 75.00 %    | -                            |
+      | Test assignment five    | 16.67 %           | 21.00  | 0–100 | 21.00 %    | 3.50 %                       |
+      | Test assignment six     | 16.67 %           | 97.00  | 0–100 | 97.00 %    | 16.17 %                      |
+      | Course total            | -                 | 383.00 | 0–600 | 63.83 %    | -                            |
index 40337fd..a22f391 100644 (file)
@@ -91,6 +91,31 @@ class behat_grade extends behat_base {
         $this->execute('behat_forms::press_button', $this->escape($savechanges));
     }
 
+    /**
+     * Hids a grade item or category.
+     *
+     * Teacher must be either on the grade setup page or on the Grader report page with editing mode turned on.
+     *
+     * @Given /^I hide the grade item "(?P<grade_item_string>(?:[^"]|\\")*)"$/
+     * @param string $gradeitem
+     */
+    public function i_hide_the_grade_item($gradeitem) {
+
+        $gradeitem = behat_context_helper::escape($gradeitem);
+
+        if ($this->running_javascript()) {
+            $xpath = "//tr[contains(.,$gradeitem)]//*[contains(@class,'moodle-actionmenu')]//a[contains(@class,'toggle-display')]";
+            if ($this->getSession()->getPage()->findAll('xpath', $xpath)) {
+                $this->execute("behat_general::i_click_on", array($this->escape($xpath), "xpath_element"));
+            }
+        }
+
+        $hide = behat_context_helper::escape(get_string('hide') . '  ');
+        $linkxpath = "//a[./img[starts-with(@title,$hide) and contains(@title,$gradeitem)]]";
+
+        $this->execute("behat_general::i_click_on", array($this->escape($linkxpath), "xpath_element"));
+    }
+
     /**
      * Sets a calculated manual grade item. Needs a table with item name - idnumber relation.
      * The step requires you to be in the 'Gradebook setup' page.
index 3e2ab94..54c2cb7 100644 (file)
@@ -345,6 +345,7 @@ Feature: We can use calculated grade totals
     And I set the field "Show weightings" to "Show"
     And I press "Save changes"
     And I select "User report" from the "Grade report" singleselect
+    And I select "Myself" from the "View report as" singleselect
     And I select "Student 1" from the "Select all or one user" singleselect
     And the following should exist in the "user-grade" table:
       | Grade item | Calculated weight | Grade | Range | Contribution to course total |
@@ -534,6 +535,7 @@ Feature: We can use calculated grade totals
     And I press "Save changes"
     Then I should see "75.00 (16.85 %)" in the ".course" "css_element"
     And I select "User report" from the "Grade report" singleselect
+    And I select "Myself" from the "View report as" singleselect
     And I select "Student 1" from the "Select all or one user" singleselect
     And the following should exist in the "user-grade" table:
       | Grade item            | Calculated weight | Grade           | Contribution to course total |
index 724fb0a..a85f780 100644 (file)
@@ -46,6 +46,7 @@ Feature: Student and teacher's view of aggregated grade items is consistent when
     And I follow "Course 1"
     And I navigate to "Grades" node in "Course administration"
     And I select "User report" from the "Grade report" singleselect
+    And I select "Myself" from the "View report as" singleselect
     And I select "Student 1" from the "Select all or one user" singleselect
     Then the following should exist in the "user-grade" table:
       | Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
index 2143bc0..bef4621 100644 (file)
@@ -86,8 +86,8 @@ class core_iplookup_geoip_testcase extends advanced_testcase {
 
         $this->assertEquals('array', gettype($result));
         $this->assertEquals('Cambridge', $result['city']);
-        $this->assertEquals(0.1249, $result['longitude'], '', 0.001);
-        $this->assertEquals(52.191000000000003, $result['latitude'], '', 0.001);
+        $this->assertEquals(0.1167, $result['longitude'], 'Coordinates are out of accepted tolerance', 0.01);
+        $this->assertEquals(52.2, $result['latitude'], 'Coordinates are out of accepted tolerance', 0.01);
         $this->assertNull($result['error']);
         $this->assertEquals('array', gettype($result['title']));
         $this->assertEquals('Cambridge', $result['title'][0]);
@@ -100,8 +100,8 @@ class core_iplookup_geoip_testcase extends advanced_testcase {
 
         $this->assertEquals('array', gettype($result));
         $this->assertEquals('Lancaster', $result['city']);
-        $this->assertEquals(-2.79970, $result['longitude'], '', 0.001);
-        $this->assertEquals(54.04650, $result['latitude'], '', 0.001);
+        $this->assertEquals(-2.7997, $result['longitude'], 'Coordinates are out of accepted tolerance', 0.01);
+        $this->assertEquals(54.0465, $result['latitude'], 'Coordinates are out of accepted tolerance', 0.01);
         $this->assertNull($result['error']);
         $this->assertEquals('array', gettype($result['title']));
         $this->assertEquals('Lancaster', $result['title'][0]);
index 29f09b1..0f833ac 100644 (file)
@@ -778,6 +778,8 @@ $string['order3'] = 'Third';
 $string['order4'] = 'Fourth';
 $string['passwordchangelogout'] = 'Log out after password change';
 $string['passwordchangelogout_desc'] = 'If enabled, when a password is changed, all browser sessions are terminated, apart from the one in which the new password is specified. (This setting does not affect password changes via bulk user upload.)';
+$string['passwordchangetokendeletion'] = 'Remove web service access tokens after password change';
+$string['passwordchangetokendeletion_desc'] = 'If enabled, when a password is changed, all the user web service access tokens are deleted.';
 $string['passwordpolicy'] = 'Password policy';
 $string['passwordresettime'] = 'Maximum time to validate password reset request';
 $string['passwordreuselimit'] = 'Password rotation limit';
@@ -1063,6 +1065,7 @@ $string['tasktagcron'] = 'Background processing for tags';
 $string['tasktempfilecleanup'] = 'Delete stale temp files';
 $string['tempdatafoldercleanup'] = 'Clean up temporary data files older than';
 $string['themedesignermode'] = 'Theme designer mode';
+$string['themedesignermodewarning'] = 'Theme designer mode is enabled. This should not be enabled on production sites as it can significantly reduce performance.';
 $string['themelist'] = 'Theme list';
 $string['themenoselected'] = 'No theme selected';
 $string['themeresetcaches'] = 'Clear theme caches';
index 632356e..f37c7b2 100644 (file)
@@ -1712,6 +1712,8 @@ $string['showsettings'] = 'Show settings';
 $string['showtheselogs'] = 'Show these logs';
 $string['showthishelpinlanguage'] = 'Show this help in language: {$a}';
 $string['schedule'] = 'Schedule';
+$string['signoutofotherservices'] = 'Sign out everywhere';
+$string['signoutofotherservices_help'] = 'If ticked, the account will be signed out of all devices and systems which use web services, such as the mobile app.';
 $string['since'] = 'Since';
 $string['sincelast'] = 'since last login';
 $string['site'] = 'Site';
index 6eeb775..06cb7d1 100644 (file)
@@ -204,6 +204,7 @@ $string['usernameorid_help'] = 'Enter a username or a user id.';
 $string['usernameoridnousererror'] = 'No users were found with this username/user id.';
 $string['usernameoridoccurenceerror'] = 'More than one user was found with this username. Please enter the user id.';
 $string['usernotallowed'] = 'The user is not allowed for this service. First you need to allow this user on the {$a}\'s allowed users administration page.';
+$string['userservices'] = 'User services: {$a}';
 $string['usersettingssaved'] = 'User settings saved';
 $string['validuntil'] = 'Valid until';
 $string['validuntil_help'] = 'If set, the service will be inactivated after this date for this user.';
index 2c4b878..ae58564 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
 
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Latest version is available at http://adodb.sourceforge.net
index 9e4f7c9..f7b5179 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
 
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Latest version is available at http://adodb.sourceforge.net
index c306235..bded3ac 100644 (file)
@@ -8,7 +8,7 @@ $ADODB_INCLUDED_CSV = 1;
 
 /*
 
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 5f2ffc9..f2b29a6 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 307b8b5..3f2ab90 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 3b20cc2..e8dcaab 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 733eb17..db3e2a2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 1f92c4a..b3ffc38 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
@@ -33,16 +33,16 @@ var $database = '';
                case 'EXECUTE':
                        $this->sql = is_array($p1) ? $p1[0] : $p1;
                        $this->params = $p2;
-                       $s = "$dbms error: [$errno: $errmsg] in $fn(\"$this->sql\")\n";
+                       $s = "$dbms error: [$errno: $errmsg] in $fn(\"$this->sql\")";
                        break;
 
                case 'PCONNECT':
                case 'CONNECT':
                        $user = $thisConnection->user;
-                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n";
+                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)";
                        break;
                default:
-                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+                       $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
                        break;
                }
 
index 6b75388..4c8dffc 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 7711290..503bb15 100644 (file)
@@ -6,7 +6,7 @@ global $ADODB_INCLUDED_LIB;
 $ADODB_INCLUDED_LIB = 1;
 
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
@@ -426,7 +426,7 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
                if ( strpos($sql, '_ADODB_COUNT') !== FALSE ) {
                        $rewritesql = preg_replace('/^\s*?SELECT\s+_ADODB_COUNT(.*)_ADODB_COUNT\s/is','SELECT COUNT(*) ',$sql);
                } else {
-                       $rewritesql = preg_replace('/^\s*?SELECT\s.*?\s+(.*?)\s+FROM\s/is','SELECT COUNT(*) FROM ',$sql);
+                       $rewritesql = preg_replace('/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
                }
                // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
                // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
index 0714561..4dde732 100644 (file)
@@ -11,7 +11,7 @@ if (empty($ADODB_INCLUDED_CSV)) include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
 
 /*
 
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 15c371b..0221975 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-       @version   v5.20.3  01-Jan-2016
+       @version   v5.20.7  20-Sep-2016
        @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
        @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
          Released under both BSD license and Lesser GPL library license.
index 634eb15..237dcfe 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 1629996..3dfaab4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 926dbac..50963f0 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index a2991f3..df718cf 100644 (file)
@@ -3,7 +3,7 @@
 ADOdb Date Library, part of the ADOdb abstraction library
 Download: http://adodb.sourceforge.net/#download
 
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
index 0890155..ca5fa56 100644 (file)
@@ -157,7 +157,6 @@ class dbObject {
        * Destroys the object
        */
        function destroy() {
-               unset( $this );
        }
 
        /**
@@ -265,12 +264,14 @@ class dbTable extends dbObject {
                switch( $this->currentElement ) {
                        case 'INDEX':
                                if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, $this->addIndex( $attributes ) );
+                                       $index = $this->addIndex( $attributes );
+                                       xml_set_object( $parser,  $index );
                                }
                                break;
                        case 'DATA':
                                if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, $this->addData( $attributes ) );
+                                       $data = $this->addData( $attributes );
+                                       xml_set_object( $parser, $data );
                                }
                                break;
                        case 'DROP':
@@ -2196,7 +2197,6 @@ class adoSchema {
        function Destroy() {
                ini_set("magic_quotes_runtime", $this->mgq );
                #set_magic_quotes_runtime( $this->mgq );
-               unset( $this );
        }
 }
 
index 45a59bb..c1ecb88 100644 (file)
@@ -175,7 +175,6 @@ class dbObject {
        * Destroys the object
        */
        function destroy() {
-               unset( $this );
        }
 
        /**
@@ -290,12 +289,14 @@ class dbTable extends dbObject {
                switch( $this->currentElement ) {
                        case 'INDEX':
                                if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, $this->addIndex( $attributes ) );
+                                       $index = $this->addIndex( $attributes );
+                                       xml_set_object( $parser,  $index );
                                }
                                break;
                        case 'DATA':
                                if( !isset( $attributes['PLATFORM'] ) OR $this->supportedPlatform( $attributes['PLATFORM'] ) ) {
-                                       xml_set_object( $parser, $this->addData( $attributes ) );
+                                       $data = $this->addData( $attributes );
+                                       xml_set_object( $parser, $data );
                                }
                                break;
                        case 'DROP':
@@ -2378,7 +2379,6 @@ class adoSchema {
        function Destroy() {
                ini_set("magic_quotes_runtime", $this->mgq );
                #set_magic_quotes_runtime( $this->mgq );
-               unset( $this );
        }
 }
 
index b6496e6..4967f6a 100644 (file)
@@ -14,7 +14,7 @@
 /**
        \mainpage
 
-       @version   v5.20.3  01-Jan-2016
+       @version   v5.20.7  20-Sep-2016
        @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
        @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
 if (!defined('_ADODB_LAYER')) {
        define('_ADODB_LAYER',1);
 
+       // The ADOdb extension is no longer maintained and effectively unsupported
+       // since v5.04. The library will not function properly if it is present.
+       if(defined('ADODB_EXTENSION')) {
+               $msg = "Unsupported ADOdb Extension (v" . ADODB_EXTENSION . ") detected! "
+                       . "Disable it to use ADOdb";
+
+               $errorfn = defined('ADODB_ERROR_HANDLER') ? ADODB_ERROR_HANDLER : false;
+               if ($errorfn) {
+                       $conn = false;
+                       $errorfn('ADOdb', basename(__FILE__), -9999, $msg, null, null, $conn);
+               } else {
+                       die($msg . PHP_EOL);
+               }
+       }
+
        //==============================================================================================
        // CONSTANT DEFINITIONS
        //==============================================================================================
@@ -218,7 +233,7 @@ if (!defined('_ADODB_LAYER')) {
                /**
                 * ADODB version as a string.
                 */
-               $ADODB_vers = 'v5.20.3  01-Jan-2016';
+               $ADODB_vers = 'v5.20.7  20-Sep-2016';
 
                /**
                 * Determines whether recordset->RecordCount() is used.
@@ -659,23 +674,23 @@ if (!defined('_ADODB_LAYER')) {
                }
                if (isset($rez)) {
                        $err = $this->ErrorMsg();
+                       $errno = $this->ErrorNo();
                        if (empty($err)) {
                                $err = "Connection error to server '$argHostname' with user '$argUsername'";
                        }
-                       $ret = false;
                } else {
                        $err = "Missing extension for ".$this->dataProvider;
-                       $ret = 0;
+                       $errno = 0;
                }
                if ($fn = $this->raiseErrorFn) {
-                       $fn($this->databaseType,'CONNECT',$this->ErrorNo(),$err,$this->host,$this->database,$this);
+                       $fn($this->databaseType, 'CONNECT', $errno, $err, $this->host, $this->database, $this);
                }
 
                $this->_connectionID = false;
                if ($this->debug) {
                        ADOConnection::outp( $this->host.': '.$err);
                }
-               return $ret;
+               return false;
        }
 
        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabaseName) {
@@ -1117,20 +1132,35 @@ if (!defined('_ADODB_LAYER')) {
                                $sqlarr = explode('?',$sql);
                                $nparams = sizeof($sqlarr)-1;
 
+                               if (!$array_2d) {
+                                       // When not Bind Bulk - convert to array of arguments list
+                                       $inputarr = array($inputarr);
+                               } else {
+                                       // Bulk bind - Make sure all list of params have the same number of elements
+                                       $countElements = array_map('count', $inputarr);
+                                       if (1 != count(array_unique($countElements))) {
+                                               $this->outp_throw(
+                                                       "[bulk execute] Input array has different number of params  [" . print_r($countElements, true) .  "].",
+                                                       'Execute'
+                                               );
+                                               return false;
+                                       }
+                                       unset($countElements);
+                               }
                                // Make sure the number of parameters provided in the input
                                // array matches what the query expects
-                               if ($nparams != count($inputarr)) {
+                               $element0 = reset($inputarr);
+                               if ($nparams != count($element0)) {
                                        $this->outp_throw(
-                                               "Input array has " . count($inputarr) .
+                                               "Input array has " . count($element0) .
                                                " params, does not match query: '" . htmlspecialchars($sql) . "'",
                                                'Execute'
                                        );
                                        return false;
                                }
 
-                               if (!$array_2d) {
-                                       $inputarr = array($inputarr);
-                               }
+                               // clean memory
+                               unset($element0);
 
                                foreach($inputarr as $arr) {
                                        $sql = ''; $i = 0;
index 0d2f36b..25a72a8 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index f5fb983..a3fa783 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 2f5372f..8f85f89 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index ed84fff..0521cc6 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 5370417..c6629d1 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 98263a6..8ab2b6e 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 4ffb9bb..1eae3af 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index bab0c39..8c88404 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index c1433ae..0148915 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 6cedf95..b758ede 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 98e6510..be2700e 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index cadfc02..9a7671b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 4b6eb6f..8ec2927 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 0650103..d0e84f6 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 71a672f..b020d36 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index d8c1c8d..bcfc899 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index b9120a4..0205c93 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index defb1f5..fa1629b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 Released under both BSD license and Lesser GPL library license.
index d8342e6..d6993ed 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 978f2bf..ad5f61b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index f97435f..be0f1bd 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 2fe2a83..67c19ee 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
index e58820c..0d1d226 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 87925b9..ee5b960 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index b28feb6..7ac6dd1 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  Released under both BSD license and Lesser GPL library license.
index 556512e..84f1af5 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index db1344e..a095e58 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 356e530..951f4ef 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-* @version   v5.20.3  01-Jan-2016
+* @version   v5.20.7  20-Sep-2016
 * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 * Released under both BSD license and Lesser GPL library license.
index 3668dee..e1cf814 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim. All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 2839441..bfebe48 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
    Released under both BSD license and Lesser GPL library license.
index b68cbf4..d710d4a 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 5d6b02b..64726b0 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
@@ -1074,7 +1074,7 @@ class ADORecordset_mssqlnative extends ADORecordSet {
                is running. All associated result memory for the specified result identifier will automatically be freed.       */
        function _close()
        {
-               if($this->_queryID) {
+               if(is_object($this->_queryID)) {
                        $rez = sqlsrv_free_stmt($this->_queryID);
                        $this->_queryID = false;
                        return $rez;
index d733244..e99f31e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-* @version   v5.20.3  01-Jan-2016
+* @version   v5.20.7  20-Sep-2016
 * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 * Released under both BSD license and Lesser GPL library license.
index d57d11a..1dc0dcb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index a3b9ea8..3df1b10 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
@@ -118,7 +118,8 @@ class ADODB_mysqli extends ADOConnection {
                                        $argUsername,
                                        $argPassword,
                                        $argDatabasename,
-                                       $this->port,
+                                       # PHP7 compat: port must be int. Use default port if cast yields zero
+                                       (int)$this->port != 0 ? (int)$this->port : 3306,
                                        $this->socket,
                                        $this->clientFlags);
 
@@ -1053,13 +1054,13 @@ class ADORecordSet_mysqli extends ADORecordSet{
                //if results are attached to this pointer from Stored Proceedure calls, the next standard query will die 2014
                //only a problem with persistant connections
 
-               if($this->connection->_connectionID) {
+               if(isset($this->connection->_connectionID) && $this->connection->_connectionID) {
                        while(mysqli_more_results($this->connection->_connectionID)){
                                mysqli_next_result($this->connection->_connectionID);
                        }
                }
 
-               if($this->_queryID) {
+               if($this->_queryID instanceof mysqli_result) {
                        mysqli_free_result($this->_queryID);
                }
                $this->_queryID = false;
index fe7ef11..fe0213b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index e0c55b7..efc9333 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 79123f1..c0f476a 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
index 2b84b71..33d19a8 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
 
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim. All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
index 06e9f32..e2979f5 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 15e89fb..0013467 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim. All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 441af92..341e2fc 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim. All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 60dcb26..b6b0556 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 8337707..ca2b63c 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index ce4f166..b14618c 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
diff --git a/lib/adodb/drivers/adodb-odbc_mssql2012.inc.php b/lib/adodb/drivers/adodb-odbc_mssql2012.inc.php
new file mode 100644 (file)
index 0000000..a3b7f69
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/*
+ @version   v5.21.0-dev  ??-???-2016
+ @copyright (c) 2015      Damien Regad, Mark Newnham and the ADOdb community
+  Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
+  the BSD license will take precedence.
+  Set tabs to 4.
+
+  Microsoft SQL Server 2012 via ODBC
+*/
+
+if (!defined('ADODB_DIR')) 
+       die();
+
+include_once(ADODB_DIR."/drivers/adodb-odbc_mssql.inc.php");
+
+class  ADODB_odbc_mssql2012 extends ADODB_odbc_mssql
+{
+       /*
+       * Makes behavior similar to prior versions of SQL Server
+       */
+       var $connectStmt = 'SET CONCAT_NULL_YIELDS_NULL ON';
+}
+
+class  ADORecordSet_odbc_mssql2012 extends ADORecordSet_odbc_mssql
+{
+}
\ No newline at end of file
index 3f66078..42dc1b2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 18bf8cd..740e9bf 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index ae091a5..9ddd408 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-       @version   v5.20.3  01-Jan-2016
+       @version   v5.20.7  20-Sep-2016
        @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
        @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 8452d33..f5dae53 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index ccc0a7e..179268b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
-       @version   v5.20.3  01-Jan-2016
+       @version   v5.20.7  20-Sep-2016
        @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
        @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 
@@ -196,6 +196,7 @@ class ADODB_pdo extends ADOConnection {
 
                        $this->_driver->_connectionID = $this->_connectionID;
                        $this->_UpdatePDO();
+                       $this->_driver->database = $this->database;
                        return true;
                }
                $this->_driver = new ADODB_pdo_base();
@@ -266,6 +267,16 @@ class ADODB_pdo extends ADOConnection {
                return $this->_driver->OffsetDate($dayFraction,$date);
        }
 
+       function SelectDB($dbName)
+       {
+               return $this->_driver->SelectDB($dbName);
+       }
+
+       function SQLDate($fmt, $col=false)
+       {
+               return $this->_driver->SQLDate($fmt, $col);
+       }
+
        function ErrorMsg()
        {
                if ($this->_errormsg !== false) {
@@ -507,6 +518,30 @@ class ADODB_pdo extends ADOConnection {
        {
                return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0;
        }
+
+       /**
+        * Quotes a string to be sent to the database.
+        * If we have an active connection, delegates quoting to the underlying
+        * PDO object. Otherwise, replace "'" by the value of $replaceQuote (same
+        * behavior as mysqli driver)
+        * @param string  $s            The string to quote
+        * @param boolean $magic_quotes If false, use PDO::quote().
+        * @return string Quoted string
+        */
+       function qstr($s, $magic_quotes = false)
+       {
+               if (!$magic_quotes) {
+                       if ($this->_connectionID) {
+                               return $this->_connectionID->quote($s);
+                       }
+                       return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
+               }
+
+               // undo magic quotes for "
+               $s = str_replace('\\"', '"', $s);
+               return "'$s'";
+       }
+
 }
 
 class ADODB_pdo_base extends ADODB_pdo {
@@ -699,12 +734,22 @@ class ADORecordSet_pdo extends ADORecordSet {
                }
                //adodb_pr($arr);
                $o->name = $arr['name'];
-               if (isset($arr['native_type']) && $arr['native_type'] <> "null") {
-                       $o->type = $arr['native_type'];
-               }
-               else {
-                       $o->type = adodb_pdo_type($arr['pdo_type']);
-               }
+               if (isset($arr['sqlsrv:decl_type']) && $arr['sqlsrv:decl_type'] <> "null") 
+               {
+                   /*
+                   * If the database is SQL server, use the native built-ins
+                   */
+                   $o->type = $arr['sqlsrv:decl_type'];
+               }
+               elseif (isset($arr['native_type']) && $arr['native_type'] <> "null") 
+               {
+                   $o->type = $arr['native_type'];
+               }
+               else 
+               {
+                    $o->type = adodb_pdo_type($arr['pdo_type']);
+               }
+               
                $o->max_length = $arr['len'];
                $o->precision = $arr['precision'];
 
index 94b6850..2c46842 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index fb35357..746161d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
@@ -70,7 +70,9 @@ class ADODB_pdo_mysql extends ADODB_pdo {
        {
                $save = $this->metaTablesSQL;
                if ($showSchema && is_string($showSchema)) {
-                       $this->metaTablesSQL .= " from $showSchema";
+                       $this->metaTablesSQL .= $this->qstr($showSchema);
+               } else {
+                       $this->metaTablesSQL .= 'schema()';
                }
 
                if ($mask) {
index 394c5fd..d900627 100644 (file)
@@ -2,7 +2,7 @@
 
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index e2b75a7..059f495 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 6bf4cb1..a06bc04 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 0fb2542..cc5698d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 54bb4cb..22fdbf4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 0b8fdd3..851e0af 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 3bf7609..386e65c 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index c445b5b..9fda8bd 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
- @version   v5.20.3  01-Jan-2016
+ @version   v5.20.7  20-Sep-2016
  @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 316b4d9..f7aac07 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 388f095..f3f94e3 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index e4c4760..23625b0 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013  John Lim (jlim#natsoft.com).  All rights
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
 reserved.
index 728c2e6..9782e49 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 33b7820..ab00feb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index e659dd6..e2b0b93 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 9aeb0cf..933f2f2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim. All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 7efd60a..03add79 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index bb84550..0b0e8d9 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index e0865c3..b0bdceb 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 2234ba5..072b274 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 092209c..4227b1c 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 9da3fab..e4ca57b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index f961246..7a0bf06 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 06181b2..eb120c2 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index a362d75..1eaf322 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /*
-@version   v5.20.3  01-Jan-2016
+@version   v5.20.7  20-Sep-2016
 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
 @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 8debf4f..3a554ad 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index a2590c6..f894c69 100644 (file)
@@ -1,4 +1,4 @@
-Description of ADODB V5.20.1 library import into Moodle
+Description of ADODB V5.20.7 library import into Moodle
 
 This library will be probably removed in Moodle 2.1,
 it is now used only in enrol and auth db plugins.
@@ -27,6 +27,5 @@ Our changes:
  * Removed random seed initialization from lib/adodb/adodb.inc.php:216 (see 038f546 and MDL-41198).
  * MDL-52286 Added muting erros in ADORecordSet::__destruct().
    Check if fixed upstream during the next upgrade and remove this note.
- * MDL-52544 Pull upstream patch for php7 and ocipo.
 
-skodak, iarenaza, moodler, stronk7, abgreeve
+skodak, iarenaza, moodler, stronk7, abgreeve, lameze
index d309c06..3343983 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index 246a65d..5cbfb94 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @version   v5.20.3  01-Jan-2016
+ * @version   v5.20.7  20-Sep-2016
  * @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  * @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
  * Released under both BSD license and Lesser GPL library license.
index c51de3b..e859907 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /*
-  @version   v5.20.3  01-Jan-2016
+  @version   v5.20.7  20-Sep-2016
   @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
   @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   Released under both BSD license and Lesser GPL library license.
index 226aa3b..5d3b327 100644 (file)
@@ -79,7 +79,9 @@ class core_component {
         'Sabberworm\\CSS' => 'lib/php-css-parser',
         'MoodleHQ\\RTLCSS' => 'lib/rtlcss',
         'Leafo\\ScssPhp' => 'lib/scssphp',
-        'Box\\Spout' => 'lib/spout/src/Spout'
+        'Box\\Spout' => 'lib/spout/src/Spout',
+        'MatthiasMullie\\Minify' => 'lib/minify/matthiasmullie-minify/src/',
+        'MatthiasMullie\\PathConverter' => 'lib/minify/matthiasmullie-pathconverter/src/',
     );
 
     /**
index 6ebb067..6a570e4 100644 (file)
@@ -35,18 +35,9 @@ class core_minify {
      * @return string minified JS code
      */
     public static function js($content) {
-        global $CFG;
-        require_once("$CFG->libdir/minify/lib/JSMinPlus.php");
-
         try {
-            ob_start(); // JSMinPlus just echos errors, weird...
-            $compressed = JSMinPlus::minify($content);
-            if ($compressed !== false) {
-                ob_end_clean();
-                return $compressed;
-            }
-            $error = ob_get_clean();
-
+            $minifier = new MatthiasMullie\Minify\JS($content);
+            return $minifier->minify();
         } catch (Exception $e) {
             ob_end_clean();
             $error = $e->getMessage();
@@ -97,16 +88,10 @@ EOD;
      * @return string minified CSS
      */
     public static function css($content) {
-        global $CFG;
-        require_once("$CFG->libdir/minify/lib/Minify/CSS/Compressor.php");
-
         $error = 'unknown';
         try {
-            $compressed = Minify_CSS_Compressor::process($content);
-            if ($compressed !== false) {
-                return $compressed;
-            }
-
+            $minifier = new MatthiasMullie\Minify\CSS($content);
+            return $minifier->minify();
         } catch (Exception $e) {
             $error = $e->getMessage();
         }
index 7ad1284..96d8a2a 100644 (file)
@@ -996,6 +996,8 @@ class grade_category extends grade_object {
                                                        & $weights = null,
                                                        $grademinoverrides = array(),
                                                        $grademaxoverrides = array()) {
+        global $CFG;
+
         $category_item = $this->load_grade_item();
         $grademin = $category_item->grademin;
         $grademax = $category_item->grademax;
@@ -1283,8 +1285,9 @@ class grade_category extends grade_object {
 
                 // This setting indicates if we should use algorithm prior to MDL-49257 fix for calculating extra credit weights.
                 // Even though old algorith has bugs in it, we need to preserve existing grades.
-                $gradebookcalculationfreeze = (int)get_config('core', 'gradebook_calculations_freeze_' . $this->courseid);
-                $oldextracreditcalculation = $gradebookcalculationfreeze && ($gradebookcalculationfreeze <= 20150619);
+                $gradebookcalculationfreeze = 'gradebook_calculations_freeze_' . $this->courseid;
+                $oldextracreditcalculation = isset($CFG->$gradebookcalculationfreeze)
+                        && ($CFG->$gradebookcalculationfreeze <= 20150619);
 
                 $sumweights = 0;
                 $grademin = 0;
@@ -1479,7 +1482,7 @@ class grade_category extends grade_object {
      * @return void
      */
     private function auto_update_max() {
-        global $DB;
+        global $CFG, $DB;
         if ($this->aggregation != GRADE_AGGREGATE_SUM) {
             // not needed at all
             return;
@@ -1491,11 +1494,10 @@ class grade_category extends grade_object {
 
         // Check to see if the gradebook is frozen. This allows grades to not be altered at all until a user verifies that they
         // wish to update the grades.
-        $gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->courseid);
+        $gradebookcalculationfreeze = 'gradebook_calculations_freeze_' . $this->courseid;
+        $oldextracreditcalculation = isset($CFG->$gradebookcalculationfreeze) && ($CFG->$gradebookcalculationfreeze <= 20150627);
         // Only run if the gradebook isn't frozen.
-        if ($gradebookcalculationsfreeze && (int)$gradebookcalculationsfreeze <= 20150627) {
-            // Do nothing.
-        } else{
+        if (!$oldextracreditcalculation) {
             // Don't automatically update the max for calculated items.
             if ($this->grade_item->is_calculated()) {
                 return;
index d258820..eb57b0d 100644 (file)
@@ -352,9 +352,9 @@ class grade_grade extends grade_object {
 
         // Check to see if the gradebook is frozen. This allows grades to not be altered at all until a user verifies that they
         // wish to update the grades.
-        $gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->grade_item->courseid);
+        $gradebookcalculationsfreeze = 'gradebook_calculations_freeze_' . $this->grade_item->courseid;
         // Gradebook is frozen, run through old code.
-        if ($gradebookcalculationsfreeze && (int)$gradebookcalculationsfreeze <= 20150627) {
+        if (isset($CFG->$gradebookcalculationsfreeze) && (int)$CFG->$gradebookcalculationsfreeze <= 20150627) {
             // Only aggregate items use separate min grades.
             if ($minmaxtouse == GRADE_MIN_MAX_FROM_GRADE_GRADE || $this->grade_item->is_aggregate_item()) {
                 return array($this->rawgrademin, $this->rawgrademax);
index e0438e6..dc56fe3 100644 (file)
@@ -1300,30 +1300,33 @@ function stripHTML(str) {
 }
 
 function updateProgressBar(id, percent, msg, estimate) {
-    var progressIndicator = Y.one('#' + id);
-    if (!progressIndicator) {
+    var event,
+        el = document.getElementById(id),
+        eventData = {};
+
+    if (!el) {
         return;
     }
 
-    var progressBar = progressIndicator.one('.bar'),
-        statusIndicator = progressIndicator.one('h2'),
-        estimateIndicator = progressIndicator.one('p');
+    eventData.message = msg;
+    eventData.percent = percent;
+    eventData.estimate = estimate;
 
-    statusIndicator.set('innerHTML', Y.Escape.html(msg));
-    progressBar.set('innerHTML', Y.Escape.html('' + percent + '%'));
-    if (percent === 100) {
-        progressIndicator.addClass('progress-success');
-        estimateIndicator.set('innerHTML', null);
-    } else {
-        if (estimate) {
-            estimateIndicator.set('innerHTML', Y.Escape.html(estimate));
-        } else {
-            estimateIndicator.set('innerHTML', null);
+    try {
+        event = new CustomEvent('update', {
+            bubbles: false,
+            cancelable: true,
+            detail: eventData
+        });
+    } catch (exception) {
+        if (!(exception instanceof TypeError)) {
+            throw exception;
         }
-        progressIndicator.removeClass('progress-success');
+        event = document.createEvent('Event');
+        event.initCustomEvent('update', false, true, eventData);
     }
-    progressBar.setAttribute('aria-valuenow', percent);
-    progressBar.setStyle('width', percent + '%');
+
+    el.dispatchEvent(event);
 }
 
 // ===== Deprecated core Javascript functions for Moodle ====
index f8ad74c..7e7869f 100644 (file)
@@ -30,7 +30,6 @@ define('NO_DEBUG_DISPLAY', true);
 define('ABORT_AFTER_CONFIG', true);
 require('../config.php'); // this stops immediately at the beginning of lib/setup.php
 require_once("$CFG->dirroot/lib/jslib.php");
-require_once("$CFG->dirroot/lib/classes/minify.php");
 
 if ($slashargument = min_get_slash_argument()) {
     $slashargument = ltrim($slashargument, '/');
@@ -93,6 +92,15 @@ if ($rev > 0 and $rev < (time() + 60*60)) {
         js_send_cached($candidate, $etag);
 
     } else {
+        // The JS needs minfifying, so we're gonna have to load our full Moodle
+        // environment to process it..
+        define('ABORT_AFTER_CONFIG_CANCEL', true);
+
+        define('NO_MOODLE_COOKIES', true); // Session not used here.
+        define('NO_UPGRADE_CHECK', true);  // Ignore upgrade check.
+
+        require("$CFG->dirroot/lib/setup.php");
+
         js_write_cache_file_content($candidate, core_minify::js_files($jsfiles));
         // verify nothing failed in cache file creation
         clearstatcache();
diff --git a/lib/minify/LICENSE.txt b/lib/minify/LICENSE.txt
deleted file mode 100644 (file)
index 8f008ad..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Copyright (c) 2008 Ryan Grove <ryan@wonko.com>
-Copyright (c) 2008 Steve Clay <steve@mrclay.org>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-  * Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
-  * Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-  * Neither the name of this project nor the names of its contributors may be
-    used to endorse or promote products derived from this software without
-    specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/lib/minify/config.php b/lib/minify/config.php
deleted file mode 100644 (file)
index 0750f22..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-<?php
-/**
- * Configuration for "min", the default application built with the Minify
- * library
- *
- * @package Minify
- */
-
-
-defined('MOODLE_INTERNAL') || die(); // start of moodle modification
-
-// NOTE: Copy all necessary settings here, do not modify the rest.
-//       Minifier can not be accessed directly, only use PHP api.
-
-$min_enableBuilder = false;
-$min_errorLogger = false;
-$min_allowDebugFlag = $CFG->debugdeveloper;
-$min_cachePath = $CFG->tempdir;
-$min_documentRoot = $CFG->dirroot.'/lib/minify';
-$min_cacheFileLocking = empty($CFG->preventfilelocking);
-$min_serveOptions['bubbleCssImports'] = false;
-$min_serveOptions['maxAge'] = 1800;
-$min_serveOptions['minApp']['groupsOnly'] = true;
-$min_symlinks = array();
-$min_uploaderHoursBehind = 0;
-$min_libPath = dirname(__FILE__) . '/lib';
-// do not change zlib compression or buffering here
-
-return; // end of moodle modification
-
-
-/**
- * Allow use of the Minify URI Builder app. Only set this to true while you need it.
- */
-$min_enableBuilder = false;
-
-/**
- * If non-empty, the Builder will be protected with HTTP Digest auth.
- * The username is "admin".
- */
-$min_builderPassword = 'admin';
-
-
-/**
- * Set to true to log messages to FirePHP (Firefox Firebug addon).
- * Set to false for no error logging (Minify may be slightly faster).
- * @link http://www.firephp.org/
- *
- * If you want to use a custom error logger, set this to your logger
- * instance. Your object should have a method log(string $message).
- */
-$min_errorLogger = false;
-
-
-/**
- * To allow debug mode output, you must set this option to true.
- *
- * Once true, you can send the cookie minDebug to request debug mode output. The
- * cookie value should match the URIs you'd like to debug. E.g. to debug
- * /min/f=file1.js send the cookie minDebug=file1.js
- * You can manually enable debugging by appending "&debug" to a URI.
- * E.g. /min/?f=script1.js,script2.js&debug
- *
- * In 'debug' mode, Minify combines files with no minification and adds comments
- * to indicate line #s of the original files.
- */
-$min_allowDebugFlag = false;
-
-
-/**
- * For best performance, specify your temp directory here. Otherwise Minify
- * will have to load extra code to guess. Some examples below:
- */
-//$min_cachePath = 'c:\\WINDOWS\\Temp';
-//$min_cachePath = '/tmp';
-//$min_cachePath = preg_replace('/^\\d+;/', '', session_save_path());
-/**
- * To use APC/Memcache/ZendPlatform for cache storage, require the class and
- * set $min_cachePath to an instance. Example below:
- */
-//require dirname(__FILE__) . '/lib/Minify/Cache/APC.php';
-//$min_cachePath = new Minify_Cache_APC();
-
-
-/**
- * Leave an empty string to use PHP's $_SERVER['DOCUMENT_ROOT'].
- *
- * On some servers, this value may be misconfigured or missing. If so, set this
- * to your full document root path with no trailing slash.
- * E.g. '/home/accountname/public_html' or 'c:\\xampp\\htdocs'
- *
- * If /min/ is directly inside your document root, just uncomment the
- * second line. The third line might work on some Apache servers.
- */
-$min_documentRoot = '';
-//$min_documentRoot = substr(__FILE__, 0, -15);
-//$min_documentRoot = $_SERVER['SUBDOMAIN_DOCUMENT_ROOT'];
-
-
-/**
- * Cache file locking. Set to false if filesystem is NFS. On at least one
- * NFS system flock-ing attempts stalled PHP for 30 seconds!
- */
-$min_cacheFileLocking = true;
-
-
-/**
- * Combining multiple CSS files can place @import declarations after rules, which
- * is invalid. Minify will attempt to detect when this happens and place a
- * warning comment at the top of the CSS output. To resolve this you can either
- * move the @imports within your CSS files, or enable this option, which will
- * move all @imports to the top of the output. Note that moving @imports could
- * affect CSS values (which is why this option is disabled by default).
- */
-$min_serveOptions['bubbleCssImports'] = false;
-
-
-/**
- * Cache-Control: max-age value sent to browser (in seconds). After this period,
- * the browser will send another conditional GET. Use a longer period for lower
- * traffic but you may want to shorten this before making changes if it's crucial
- * those changes are seen immediately.
- *
- * Note: Despite this setting, if you include a number at the end of the
- * querystring, maxAge will be set to one year. E.g. /min/f=hello.css&123456
- */
-$min_serveOptions['maxAge'] = 1800;
-
-
-/**
- * To use Google's Closure Compiler API to minify Javascript (falling back to JSMin
- * on failure), uncomment the following line:
- */
-//$min_serveOptions['minifiers']['application/x-javascript'] = array('Minify_JS_ClosureCompiler', 'minify');
-
-
-/**
- * If you'd like to restrict the "f" option to files within/below
- * particular directories below DOCUMENT_ROOT, set this here.
- * You will still need to include the directory in the
- * f or b GET parameters.
- *
- * // = shortcut for DOCUMENT_ROOT
- */
-//$min_serveOptions['minApp']['allowDirs'] = array('//js', '//css');
-
-/**
- * Set to true to disable the "f" GET parameter for specifying files.
- * Only the "g" parameter will be considered.
- */
-$min_serveOptions['minApp']['groupsOnly'] = false;
-
-
-/**
- * By default, Minify will not minify files with names containing .min or -min
- * before the extension. E.g. myFile.min.js will not be processed by JSMin
- *
- * To minify all files, set this option to null. You could also specify your
- * own pattern that is matched against the filename.
- */
-//$min_serveOptions['minApp']['noMinPattern'] = '@[-\\.]min\\.(?:js|css)$@i';
-
-
-/**
- * If you minify CSS files stored in symlink-ed directories, the URI rewriting
- * algorithm can fail. To prevent this, provide an array of link paths to
- * target paths, where the link paths are within the document root.
- *
- * Because paths need to be normalized for this to work, use "//" to substitute
- * the doc root in the link paths (the array keys). E.g.:
- * <code>
- * array('//symlink' => '/real/target/path') // unix
- * array('//static' => 'D:\\staticStorage')  // Windows
- * </code>
- */
-$min_symlinks = array();
-
-
-/**
- * If you upload files from Windows to a non-Windows server, Windows may report
- * incorrect mtimes for the files. This may cause Minify to keep serving stale
- * cache files when source file changes are made too frequently (e.g. more than
- * once an hour).
- *
- * Immediately after modifying and uploading a file, use the touch command to
- * update the mtime on the server. If the mtime jumps ahead by a number of hours,
- * set this variable to that number. If the mtime moves back, this should not be
- * needed.
- *
- * In the Windows SFTP client WinSCP, there's an option that may fix this
- * issue without changing the variable below. Under login > environment,
- * select the option "Adjust remote timestamp with DST".
- * @link http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time
- */
-$min_uploaderHoursBehind = 0;
-
-
-/**
- * Path to Minify's lib folder. If you happen to move it, change
- * this accordingly.
- */
-$min_libPath = dirname(__FILE__) . '/lib';
-
-
-// try to disable output_compression (may not have an effect)
-ini_set('zlib.output_compression', '0');
diff --git a/lib/minify/groupsConfig.php b/lib/minify/groupsConfig.php
deleted file mode 100644 (file)
index c900776..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Groups configuration for default Minify implementation
- * @package Minify
- */
-
-/** 
- * You may wish to use the Minify URI Builder app to suggest
- * changes. http://yourdomain/min/builder/
- *
- * See http://code.google.com/p/minify/wiki/CustomSource for other ideas
- **/
-
-return array(
-    // 'js' => array('//js/file1.js', '//js/file2.js'),
-    // 'css' => array('//css/file1.css', '//css/file2.css'),
-);
\ No newline at end of file
diff --git a/lib/minify/lib/CSSmin.php b/lib/minify/lib/CSSmin.php
deleted file mode 100644 (file)
index fab0102..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-<?php
-
-/*!
- * cssmin.php v2.4.8-4
- * Author: Tubal Martin - http://tubalmartin.me/
- * Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
- *
- * This is a PHP port of the CSS minification tool distributed with YUICompressor,
- * itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
- * Permission is hereby granted to use the PHP version under the same
- * conditions as the YUICompressor.
- */
-
-/*!
- * YUI Compressor
- * http://developer.yahoo.com/yui/compressor/
- * Author: Julien Lecomte - http://www.julienlecomte.net/
- * Copyright (c) 2013 Yahoo! Inc. All rights reserved.
- * The copyrights embodied in the content of this file are licensed
- * by Yahoo! Inc. under the BSD (revised) open source license.
- */
-
-class CSSmin
-{
-    const NL = '___YUICSSMIN_PRESERVED_NL___';
-    const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
-    const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
-    const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
-    const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
-
-    private $comments;
-    private $preserved_tokens;
-    private $memory_limit;
-    private $max_execution_time;
-    private $pcre_backtrack_limit;
-    private $pcre_recursion_limit;
-    private $raise_php_limits;
-
-    /**
-     * @param bool|int $raise_php_limits
-     * If true, PHP settings will be raised if needed
-     */
-    public function __construct($raise_php_limits = TRUE)
-    {
-        // Set suggested PHP limits
-        $this->memory_limit = 128 * 1048576; // 128MB in bytes
-        $this->max_execution_time = 60; // 1 min
-        $this->pcre_backtrack_limit = 1000 * 1000;
-        $this->pcre_recursion_limit =  500 * 1000;
-
-        $this->raise_php_limits = (bool) $raise_php_limits;
-    }
-
-    /**
-     * Minify a string of CSS
-     * @param string $css
-     * @param int|bool $linebreak_pos
-     * @return string
-     */
-    public function run($css = '', $linebreak_pos = FALSE)
-    {
-        if (empty($css)) {
-            return '';
-        }
-
-        if ($this->raise_php_limits) {
-            $this->do_raise_php_limits();
-        }
-
-        $this->comments = array();
-        $this->preserved_tokens = array();
-
-        $start_index = 0;
-        $length = strlen($css);
-
-        $css = $this->extract_data_urls($css);
-
-        // collect all comment blocks...
-        while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
-            $end_index = $this->index_of($css, '*/', $start_index + 2);
-            if ($end_index < 0) {
-                $end_index = $length;
-            }
-            $comment_found = $this->str_slice($css, $start_index + 2, $end_index);
-            $this->comments[] = $comment_found;
-            $comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
-            $css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
-            // Set correct start_index: Fixes issue #2528130
-            $start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
-        }
-
-        // preserve strings so their content doesn't get accidentally minified
-        $css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
-
-        // Let's divide css code in chunks of 5.000 chars aprox.
-        // Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
-        // of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
-        // long strings and a (sub)pattern matches a number of chars greater than
-        // the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
-        // returning NULL and $css would be empty.
-        $charset = '';
-        $charset_regexp = '/(@charset)( [^;]+;)/i';
-        $css_chunks = array();
-        $css_chunk_length = 5000; // aprox size, not exact
-        $start_index = 0;
-        $i = $css_chunk_length; // save initial iterations
-        $l = strlen($css);
-
-
-        // if the number of characters is 5000 or less, do not chunk
-        if ($l <= $css_chunk_length) {
-            $css_chunks[] = $css;
-        } else {
-            // chunk css code securely
-            while ($i < $l) {
-                $i += 50; // save iterations
-                if ($l - $start_index <= $css_chunk_length || $i >= $l) {
-                    $css_chunks[] = $this->str_slice($css, $start_index);
-                    break;
-                }
-                if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
-                    // If there are two ending curly braces }} separated or not by spaces,
-                    // join them in the same chunk (i.e. @media blocks)
-                    $next_chunk = substr($css, $i);
-                    if (preg_match('/^\s*\}/', $next_chunk)) {
-                        $i = $i + $this->index_of($next_chunk, '}') + 1;
-                    }
-
-                    $css_chunks[] = $this->str_slice($css, $start_index, $i);
-                    $start_index = $i;
-                }
-            }
-        }
-
-        // Minify each chunk
-        for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
-            $css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
-            // Keep the first @charset at-rule found
-            if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
-                $charset = strtolower($matches[1]) . $matches[2];
-            }
-            // Delete all @charset at-rules
-            $css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
-        }
-
-        // Update the first chunk and push the charset to the top of the file.
-        $css_chunks[0] = $charset . $css_chunks[0];
-
-        return implode('', $css_chunks);
-    }
-
-    /**
-     * Sets the memory limit for this script
-     * @param int|string $limit
-     */
-    public function set_memory_limit($limit)
-    {
-        $this->memory_limit = $this->normalize_int($limit);
-    }
-
-    /**
-     * Sets the maximum execution time for this script
-     * @param int|string $seconds
-     */
-    public function set_max_execution_time($seconds)
-    {
-        $this->max_execution_time = (int) $seconds;
-    }
-
-    /**
-     * Sets the PCRE backtrack limit for this script
-     * @param int $limit
-     */
-    public function set_pcre_backtrack_limit($limit)
-    {
-        $this->pcre_backtrack_limit = (int) $limit;
-    }
-
-    /**
-     * Sets the PCRE recursion limit for this script
-     * @param int $limit
-     */
-    public function set_pcre_recursion_limit($limit)
-    {
-        $this->pcre_recursion_limit = (int) $limit;
-    }
-
-    /**
-     * Try to configure PHP to use at least the suggested minimum settings
-     */
-    private function do_raise_php_limits()
-    {
-        $php_limits = array(
-            'memory_limit' => $this->memory_limit,
-            'max_execution_time' => $this->max_execution_time,
-            'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
-            'pcre.recursion_limit' =>  $this->pcre_recursion_limit
-        );
-
-        // If current settings are higher respect them.
-        foreach ($php_limits as $name => $suggested) {
-            $current = $this->normalize_int(ini_get($name));
-            // memory_limit exception: allow -1 for "no memory limit".
-            if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
-                ini_set($name, $suggested);
-            }
-        }
-    }
-
-    /**
-     * Does bulk of the minification
-     * @param string $css
-     * @param int|bool $linebreak_pos
-     * @return string
-     */
-    private function minify($css, $linebreak_pos)
-    {
-        // strings are safe, now wrestle the comments
-        for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
-
-            $token = $this->comments[$i];
-            $placeholder = '/' . self::COMMENT . $i . '___/';
-
-            // ! in the first position of the comment means preserve
-            // so push to the preserved tokens keeping the !
-            if (substr($token, 0, 1) === '!') {
-                $this->preserved_tokens[] = $token;
-                $token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
-                $css = preg_replace($placeholder, $token_tring, $css, 1);
-                // Preserve new lines for /*! important comments
-                $css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
-                $css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
-                continue;
-            }
-
-            // \ in the last position looks like hack for Mac/IE5
-            // shorten that to /*\*/ and the next one to /**/
-            if (substr($token, (strlen($token) - 1), 1) === '\\') {
-                $this->preserved_tokens[] = '\\';
-                $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
-                $i = $i + 1; // attn: advancing the loop
-                $this->preserved_tokens[] = '';
-                $css = preg_replace('/' . self::COMMENT . $i . '___/',  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
-                continue;
-            }
-
-            // keep empty comments after child selectors (IE7 hack)
-            // e.g. html >/**/ body
-            if (strlen($token) === 0) {
-                $start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
-                if ($start_index > 2) {
-                    if (substr($css, $start_index - 3, 1) === '>') {
-                        $this->preserved_tokens[] = '';
-                        $css = preg_replace($placeholder,  self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
-                    }
-                }
-            }
-
-            // in all other cases kill the comment
-            $css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
-        }
-
-
-        // Normalize all whitespace strings to single spaces. Easier to work with that way.
-        $css = preg_replace('/\s+/', ' ', $css);
-
-               // Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
-               $css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
-
-        // Shorten & preserve calculations calc(...) since spaces are important
-        $css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
-
-        // Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
-        // +1.2em to 1.2em, +.8px to .8px, +2% to 2%
-        $css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
-
-        // Remove leading zeros from integer and float numbers preceded by : or a white-space
-        // 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
-        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
-
-        // Remove trailing zeros from float numbers preceded by : or a white-space
-        // -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
-        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
-
-        // Remove trailing .0 -> -9.0 to -9
-        $css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
-
-        // Replace 0 length numbers with 0
-        $css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
-
-        // Remove the spaces before the things that should not have spaces before them.
-        // But, be careful not to turn "p :link {...}" into "p:link{...}"
-        // Swap out any pseudo-class colons with the token, and then swap back.
-        $css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
-
-        // Remove spaces before the things that should not have spaces before them.
-        $css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
-
-        // Restore spaces for !important
-        $css = preg_replace('/\!important/i', ' !important', $css);
-
-        // bring back the colon
-        $css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
-
-        // retain space for special IE6 cases
-        $css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
-
-        // no space after the end of a preserved comment
-        $css = preg_replace('/\*\/ /', '*/', $css);
-
-        // lowercase some popular @directives
-        $css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
-
-        // lowercase some more common pseudo-elements
-        $css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
-
-        // lowercase some more common functions
-        $css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
-
-        // lower case some common function that can be values
-        // NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
-        $css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
-
-        // Put the space back in some cases, to support stuff like
-        // @media screen and (-webkit-min-device-pixel-ratio:0){
-        $css = preg_replace('/\band\(/i', 'and (', $css);
-
-        // Remove the spaces after the things that should not have spaces after them.
-        $css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
-
-        // remove unnecessary semicolons
-        $css = preg_replace('/;+\}/', '}', $css);
-
-        // Fix for issue: #2528146
-        // Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
-        // to avoid issues on Symbian S60 3.x browsers.
-        $css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
-
-        // Replace 0 <length> and 0 <percentage> values with 0.
-        // <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
-        // <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
-        $css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
-
-               // 0% step in a keyframe? restore the % unit
-               $css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
-
-        // Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
-        $css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
-
-        // Fix for issue: #2528142
-        // Replace text-shadow:0; with text-shadow:0 0 0;
-        $css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
-
-        // Replace background-position:0; with background-position:0 0;
-        // same for transform-origin
-        // Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
-        $css = preg_replace('/(background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
-
-        // Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
-        // Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
-        // This makes it more likely that it'll get further compressed in the next step.
-        $css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
-        $css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
-
-        // Shorten colors from #AABBCC to #ABC or short color name.
-        $css = $this->compress_hex_colors($css);
-
-        // border: none to border:0, outline: none to outline:0
-        $css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
-
-        // shorter opacity IE filter
-        $css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
-
-        // Find a fraction that is used for Opera's -o-device-pixel-ratio query
-        // Add token to add the "\" back in later
-        $css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
-
-        // Remove empty rules.
-        $css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
-
-        // Add "/" back to fix Opera -o-device-pixel-ratio query
-        $css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
-
-               // Replace multiple semi-colons in a row by a single one
-        // See SF bug #1980989
-        $css = preg_replace('/;;+/', ';', $css);
-
-        // Restore new lines for /*! important comments
-        $css = preg_replace('/'. self::NL .'/', "\n", $css);
-
-        // Lowercase all uppercase properties
-        $css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
-
-        // Some source control tools don't like it when files containing lines longer
-        // than, say 8000 characters, are checked in. The linebreak option is used in
-        // that case to split long lines after a specific column.
-        if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
-            $linebreak_pos = (int) $linebreak_pos;
-            $start_index = $i = 0;
-            while ($i < strlen($css)) {
-                $i++;
-                if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
-                    $css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
-                    $start_index = $i;
-                }
-            }
-        }
-
-        // restore preserved comments and strings in reverse order
-        for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
-            $css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
-        }
-
-        // Trim the final string (for any leading or trailing white spaces)
-        return trim($css);
-    }
-
-    /**
-     * Utility method to replace all data urls with tokens before we start
-     * compressing, to avoid performance issues running some of the subsequent
-     * regexes against large strings chunks.
-     *
-     * @param string $css
-     * @return string
-     */
-    private function extract_data_urls($css)
-    {
-        // Leave data urls alone to increase parse performance.
-        $max_index = strlen($css) - 1;
-        $append_index = $index = $last_index = $offset = 0;
-        $sb = array();
-        $pattern = '/url\(\s*(["\']?)data\:/i';
-
-        // Since we need to account for non-base64 data urls, we need to handle
-        // ' and ) being part of the data string. Hence switching to indexOf,
-        // to determine whether or not we have matching string terminators and
-        // handling sb appends directly, instead of using matcher.append* methods.
-
-        while (preg_match($pattern, $css, $m, 0, $offset)) {
-            $index = $this->index_of($css, $m[0], $offset);
-            $last_index = $index + strlen($m[0]);
-            $start_index = $index + 4; // "url(".length()
-            $end_index = $last_index - 1;
-            $terminator = $m[1]; // ', " or empty (not quoted)
-            $found_terminator = FALSE;
-
-            if (strlen($terminator) === 0) {
-                $terminator = ')';
-            }
-
-            while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
-                $end_index = $this->index_of($css, $terminator, $end_index + 1);
-
-                // endIndex == 0 doesn't really apply here
-                if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
-                    $found_terminator = TRUE;
-                    if (')' != $terminator) {
-                        $end_index = $this->index_of($css, ')', $end_index);
-                    }
-                }
-            }
-
-            // Enough searching, start moving stuff over to the buffer
-            $sb[] = $this->str_slice($css, $append_index, $index);
-
-            if ($found_terminator) {
-                $token = $this->str_slice($css, $start_index, $end_index);
-                $token = preg_replace('/\s+/', '', $token);
-                $this->preserved_tokens[] = $token;
-
-                $preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
-                $sb[] = $preserver;
-
-                $append_index = $end_index + 1;
-            } else {
-                // No end terminator found, re-add the whole match. Should we throw/warn here?
-                $sb[] = $this->str_slice($css, $index, $last_index);
-                $append_index = $last_index;
-            }
-
-            $offset = $last_index;
-        }
-
-        $sb[] = $this->str_slice($css, $append_index);
-
-        return implode('', $sb);
-    }
-
-    /**
-     * Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
-     *
-     * DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
-     * e.g. #AddressForm { ... }
-     *
-     * DOES NOT compress IE filters, which have hex color values (which would break things).
-     * e.g. filter: chroma(color="#FFFFFF");
-     *
-     * DOES NOT compress invalid hex values.
-     * e.g. background-color: #aabbccdd
-     *
-     * @param string $css
-     * @return string
-     */
-    private function compress_hex_colors($css)
-    {
-        // Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
-        $pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
-        $_index = $index = $last_index = $offset = 0;
-        $sb = array();
-        // See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
-        $short_safe = array(
-            '#808080' => 'gray',
-            '#008000' => 'green',
-            '#800000' => 'maroon',
-            '#000080' => 'navy',
-            '#808000' => 'olive',
-            '#ffa500' => 'orange',
-            '#800080' => 'purple',
-            '#c0c0c0' => 'silver',
-            '#008080' => 'teal',
-            '#f00' => 'red'
-        );
-
-        while (preg_match($pattern, $css, $m, 0, $offset)) {
-            $index = $this->index_of($css, $m[0], $offset);
-            $last_index = $index + strlen($m[0]);
-            $is_filter = $m[1] !== null && $m[1] !== '';
-
-            $sb[] = $this->str_slice($css, $_index, $index);
-
-            if ($is_filter) {
-                // Restore, maintain case, otherwise filter will break
-                $sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
-            } else {
-                if (strtolower($m[2]) == strtolower($m[3]) &&
-                    strtolower($m[4]) == strtolower($m[5]) &&
-                    strtolower($m[6]) == strtolower($m[7])) {
-                    // Compress.
-                    $hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
-                } else {
-                    // Non compressible color, restore but lower case.
-                    $hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
-                }
-                // replace Hex colors to short safe color names
-                $sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
-            }
-
-            $_index = $offset = $last_index - strlen($m[8]);
-        }
-
-        $sb[] = $this->str_slice($css, $_index);
-
-        return implode('', $sb);
-    }
-
-    /* CALLBACKS
-     * ---------------------------------------------------------------------------------------------
-     */
-
-    private function replace_string($matches)
-    {
-        $match = $matches[0];
-        $quote = substr($match, 0, 1);
-        // Must use addcslashes in PHP to avoid parsing of backslashes
-        $match = addcslashes($this->str_slice($match, 1, -1), '\\');
-
-        // maybe the string contains a comment-like substring?
-        // one, maybe more? put'em back then
-        if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
-            for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
-                $match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
-            }
-        }
-
-        // minify alpha opacity in filter strings
-        $match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
-
-        $this->preserved_tokens[] = $match;
-        return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
-    }
-
-    private function replace_colon($matches)
-    {
-        return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
-    }
-
-    private function replace_calc($matches)
-    {
-        $this->preserved_tokens[] = trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]));
-        return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
-    }
-
-       private function preserve_old_IE_specific_matrix_definition($matches)
-       {
-               $this->preserved_tokens[] = $matches[1];
-               return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
-    }
-
-       private function replace_keyframe_zero($matches)
-    {
-        return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
-    }
-
-    private function rgb_to_hex($matches)
-    {
-        // Support for percentage values rgb(100%, 0%, 45%);
-        if ($this->index_of($matches[1], '%') >= 0){
-            $rgbcolors = explode(',', str_replace('%', '', $matches[1]));
-            for ($i = 0; $i < count($rgbcolors); $i++) {
-                $rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
-            }
-        } else {
-            $rgbcolors = explode(',', $matches[1]);
-        }
-
-        // Values outside the sRGB color space should be clipped (0-255)
-        for ($i = 0; $i < count($rgbcolors); $i++) {
-            $rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
-            $rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
-        }
-
-        // Fix for issue #2528093
-        if (!preg_match('/[\s\,\);\}]/', $matches[2])){
-            $matches[2] = ' ' . $matches[2];
-        }
-
-        return '#' . implode('', $rgbcolors) . $matches[2];
-    }
-
-    private function hsl_to_hex($matches)
-    {
-        $values = explode(',', str_replace('%', '', $matches[1]));
-        $h = floatval($values[0]);
-        $s = floatval($values[1]);
-        $l = floatval($values[2]);
-
-        // Wrap and clamp, then fraction!
-        $h = ((($h % 360) + 360) % 360) / 360;
-        $s = $this->clamp_number($s, 0, 100) / 100;
-        $l = $this->clamp_number($l, 0, 100) / 100;
-
-        if ($s == 0) {
-            $r = $g = $b = $this->round_number(255 * $l);
-        } else {
-            $v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
-            $v1 = (2 * $l) - $v2;
-            $r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
-            $g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
-            $b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
-        }
-
-        return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
-    }
-
-    private function lowercase_pseudo_first($matches)
-    {
-        return ':first-'. strtolower($matches[1]) .' '. $matches[2];
-    }
-
-    private function lowercase_directives($matches)
-    {
-        return '@'. strtolower($matches[1]);
-    }
-
-    private function lowercase_pseudo_elements($matches)
-    {
-        return ':'. strtolower($matches[1]);
-    }
-
-    private function lowercase_common_functions($matches)
-    {
-        return ':'. strtolower($matches[1]) .'(';
-    }
-
-    private function lowercase_common_functions_values($matches)
-    {
-        return $matches[1] . strtolower($matches[2]);
-    }
-
-    private function lowercase_properties($matches)
-    {
-        return $matches[1].strtolower($matches[2]).$matches[3];
-    }
-
-    /* HELPERS
-     * ---------------------------------------------------------------------------------------------
-     */
-
-    private function hue_to_rgb($v1, $v2, $vh)
-    {
-        $vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
-        if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
-        if ($vh * 2 < 1) return $v2;
-        if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
-        return $v1;
-    }
-
-    private function round_number($n)
-    {
-        return intval(floor(floatval($n) + 0.5), 10);
-    }
-
-    private function clamp_number($n, $min, $max)
-    {
-        return min(max($n, $min), $max);
-    }
-
-    /**
-     * PHP port of Javascript's "indexOf" function for strings only
-     * Author: Tubal Martin http://blog.margenn.com
-     *
-     * @param string $haystack
-     * @param string $needle
-     * @param int    $offset index (optional)
-     * @return int
-     */
-    private function index_of($haystack, $needle, $offset = 0)
-    {
-        $index = strpos($haystack, $needle, $offset);
-
-        return ($index !== FALSE) ? $index : -1;
-    }
-
-    /**
-     * PHP port of Javascript's "slice" function for strings only
-     * Author: Tubal Martin http://blog.margenn.com
-     * Tests: http://margenn.com/tubal/str_slice/
-     *
-     * @param string   $str
-     * @param int      $start index
-     * @param int|bool $end index (optional)
-     * @return string
-     */
-    private function str_slice($str, $start = 0, $end = FALSE)
-    {
-        if ($end !== FALSE && ($start < 0 || $end <= 0)) {
-            $max = strlen($str);
-
-            if ($start < 0) {
-                if (($start = $max + $start) < 0) {
-                    return '';
-                }
-            }
-
-            if ($end < 0) {
-                if (($end = $max + $end) < 0) {
-                    return '';
-                }
-            }
-
-            if ($end <= $start) {
-                return '';
-            }
-        }
-
-        $slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
-        return ($slice === FALSE) ? '' : $slice;
-    }
-
-    /**
-     * Convert strings like "64M" or "30" to int values
-     * @param mixed $size
-     * @return int
-     */
-    private function normalize_int($size)
-    {
-        if (is_string($size)) {
-            switch (substr($size, -1)) {
-                case 'M': case 'm': return $size * 1048576;
-                case 'K': case 'k': return $size * 1024;
-                case 'G': case 'g': return $size * 1073741824;
-            }
-        }
-
-        return (int) $size;
-    }
-}
\ No newline at end of file
diff --git a/lib/minify/lib/DooDigestAuth.php b/lib/minify/lib/DooDigestAuth.php
deleted file mode 100644 (file)
index 69bc4ed..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-/**
- * DooDigestAuth class file.
- *
- * @author Leng Sheng Hong <darkredz@gmail.com>
- * @link http://www.doophp.com/
- * @copyright Copyright &copy; 2009 Leng Sheng Hong
- * @license http://www.doophp.com/license
- */
-
-/**
- * Handles HTTP digest authentication
- *
- * <p>HTTP digest authentication can be used with the URI router.
- * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption.
- * If you are running PHP on Apache in CGI/FastCGI mode, you would need to
- * add the following line to your .htaccess for digest auth to work correctly.</p>
- * <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code>
- *
- * <p>This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.</p>
- *
- * @author Leng Sheng Hong <darkredz@gmail.com>
- * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22
- * @package doo.auth
- * @since 1.0
- */
-class DooDigestAuth{
-
-    /**
-     * Authenticate against a list of username and passwords.
-     *
-     * <p>HTTP Digest Authentication doesn't work with PHP in CGI mode,
-     * you have to add this into your .htaccess <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code></p>
-     *
-     * @param string $realm Name of the authentication session
-     * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2')
-     * @param string $fail_msg Message to be displayed if the User cancel the login
-     * @param string $fail_url URL to be redirect if the User cancel the login
-     * @return string The username if login success.
-     */
-    public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL){
-        $realm = "Restricted area - $realm";
-
-        //user => password
-        //$users = array('admin' => '1234', 'guest' => 'guest');
-        if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){
-            $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
-        }
-
-        if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
-            header('WWW-Authenticate: Digest realm="'.$realm.
-                   '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
-            header('HTTP/1.1 401 Unauthorized');
-            if($fail_msg!=NULL)
-                die($fail_msg);
-            if($fail_url!=NULL)
-                die("<script>window.location.href = '$fail_url'</script>");
-            exit;
-        }
-
-        // analyze the PHP_AUTH_DIGEST variable
-        if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){
-            header('WWW-Authenticate: Digest realm="'.$realm.
-                   '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
-            header('HTTP/1.1 401 Unauthorized');
-            if($fail_msg!=NULL)
-                die($fail_msg);
-            if($fail_url!=NULL)
-                die("<script>window.location.href = '$fail_url'</script>");
-            exit;
-        }
-
-        // generate the valid response
-        $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
-        $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
-        $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
-
-        if ($data['response'] != $valid_response){
-            header('HTTP/1.1 401 Unauthorized');
-            header('WWW-Authenticate: Digest realm="'.$realm.
-                   '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
-            if($fail_msg!=NULL)
-                die($fail_msg);
-            if($fail_url!=NULL)
-                die("<script>window.location.href = '$fail_url'</script>");
-            exit;
-        }
-
-        // ok, valid username & password
-        return $data['username'];
-    }
-
-    /**
-     * Method to parse the http auth header, works with IE.
-     *
-     * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do.
-     *
-     * @param string $txt header string to parse
-     * @return array An assoc array of the digest auth session
-     */
-    private static function http_digest_parse($txt)
-    {
-        $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match);
-        $data['username'] = (isset($match[1]))?$match[1]:null;
-        $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match);
-        $data['nonce'] = $match[1];
-        $res = preg_match('/nc=([0-9]+)/i', $txt, $match);
-        $data['nc'] = $match[1];
-        $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match);
-        $data['cnonce'] = $match[1];
-        $res = preg_match('/qop=([^,]+)/i', $txt, $match);
-        $data['qop'] = str_replace('"','',$match[1]);
-        $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match);
-        $data['uri'] = $match[1];
-        $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match);
-        $data['response'] = $match[1];
-        return $data;
-    }
-
-
-}
diff --git a/lib/minify/lib/FirePHP.php b/lib/minify/lib/FirePHP.php
deleted file mode 100644 (file)
index d301a64..0000000
+++ /dev/null
@@ -1,1370 +0,0 @@
-<?php
-/**
- * *** BEGIN LICENSE BLOCK *****
- *  
- * This file is part of FirePHP (http://www.firephp.org/).
- * 
- * Software License Agreement (New BSD License)
- * 
- * Copyright (c) 2006-2008, Christoph Dorn
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- * 
- *     * Redistributions in binary form must reproduce the above copyright notice,
- *       this list of conditions and the following disclaimer in the documentation
- *       and/or other materials provided with the distribution.
- * 
- *     * Neither the name of Christoph Dorn nor the names of its
- *       contributors may be used to endorse or promote products derived from this
- *       software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * ***** END LICENSE BLOCK *****
- * 
- * @copyright   Copyright (C) 2007-2008 Christoph Dorn
- * @author      Christoph Dorn <christoph@christophdorn.com>
- * @license     http://www.opensource.org/licenses/bsd-license.php
- * @package     FirePHP
- */
-/**
- * Sends the given data to the FirePHP Firefox Extension.
- * The data can be displayed in the Firebug Console or in the
- * "Server" request tab.
- * 
- * For more information see: http://www.firephp.org/
- * 
- * @copyright   Copyright (C) 2007-2008 Christoph Dorn
- * @author      Christoph Dorn <christoph@christophdorn.com>
- * @license     http://www.opensource.org/licenses/bsd-license.php
- * @package     FirePHP
- */
-class FirePHP {
-  
-  /**
-   * FirePHP version
-   *
-   * @var string
-   */
-  const VERSION = '0.2.0';
-  
-  /**
-   * Firebug LOG level
-   *
-   * Logs a message to firebug console.
-   * 
-   * @var string
-   */
-  const LOG = 'LOG';
-  
-  /**
-   * Firebug INFO level
-   *
-   * Logs a message to firebug console and displays an info icon before the message.
-   * 
-   * @var string
-   */
-  const INFO = 'INFO';
-  
-  /**
-   * Firebug WARN level
-   *
-   * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
-   * 
-   * @var string
-   */
-  const WARN = 'WARN';
-  
-  /**
-   * Firebug ERROR level
-   *
-   * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
-   * 
-   * @var string
-   */
-  const ERROR = 'ERROR';
-  
-  /**
-   * Dumps a variable to firebug's server panel
-   *
-   * @var string
-   */
-  const DUMP = 'DUMP';
-  
-  /**
-   * Displays a stack trace in firebug console
-   *
-   * @var string
-   */
-  const TRACE = 'TRACE';
-  
-  /**
-   * Displays an exception in firebug console
-   * 
-   * Increments the firebug error count.
-   *
-   * @var string
-   */
-  const EXCEPTION = 'EXCEPTION';
-  
-  /**
-   * Displays an table in firebug console
-   *
-   * @var string
-   */
-  const TABLE = 'TABLE';
-  
-  /**
-   * Starts a group in firebug console
-   * 
-   * @var string
-   */
-  const GROUP_START = 'GROUP_START';
-  
-  /**
-   * Ends a group in firebug console
-   * 
-   * @var string
-   */
-  const GROUP_END = 'GROUP_END';
-  
-  /**
-   * Singleton instance of FirePHP
-   *
-   * @var FirePHP
-   */
-  protected static $instance = null;
-  
-  /**
-   * Wildfire protocol message index
-   *
-   * @var int
-   */
-  protected $messageIndex = 1;
-    
-  /**
-   * Options for the library
-   * 
-   * @var array
-   */
-  protected $options = array();
-  
-  /**
-   * Filters used to exclude object members when encoding
-   * 
-   * @var array
-   */
-  protected $objectFilters = array();
-  
-  /**
-   * A stack of objects used to detect recursion during object encoding
-   * 
-   * @var object
-   */
-  protected $objectStack = array();
-  
-  /**
-   * Flag to enable/disable logging
-   * 
-   * @var boolean
-   */
-  protected $enabled = true;
-  
-  /**
-   * The object constructor
-   */
-  function __construct() {
-    $this->options['maxObjectDepth'] = 10;
-    $this->options['maxArrayDepth'] = 20;
-    $this->options['useNativeJsonEncode'] = true;
-    $this->options['includeLineNumbers'] = true;
-  }
-    
-  /**
-   * When the object gets serialized only include specific object members.
-   * 
-   * @return array
-   */  
-  public function __sleep() {
-    return array('options','objectFilters','enabled');
-  }
-    
-  /**
-   * Gets singleton instance of FirePHP
-   *
-   * @param boolean $AutoCreate
-   * @return FirePHP
-   */
-  public static function getInstance($AutoCreate=false) {
-    if($AutoCreate===true && !self::$instance) {
-      self::init();
-    }
-    return self::$instance;
-  }
-   
-  /**
-   * Creates FirePHP object and stores it for singleton access
-   *
-   * @return FirePHP
-   */
-  public static function init() {
-    return self::$instance = new self();
-  }
-  
-  /**
-   * Enable and disable logging to Firebug
-   * 
-   * @param boolean $Enabled TRUE to enable, FALSE to disable
-   * @return void
-   */
-  public function setEnabled($Enabled) {
-    $this->enabled = $Enabled;
-  }
-  
-  /**
-   * Check if logging is enabled
-   * 
-   * @return boolean TRUE if enabled
-   */
-  public function getEnabled() {
-    return $this->enabled;
-  }
-  
-  /**
-   * Specify a filter to be used when encoding an object
-   * 
-   * Filters are used to exclude object members.
-   * 
-   * @param string $Class The class name of the object
-   * @param array $Filter An array or members to exclude
-   * @return void
-   */
-  public function setObjectFilter($Class, $Filter) {
-    $this->objectFilters[$Class] = $Filter;
-  }
-  
-  /**
-   * Set some options for the library
-   * 
-   * Options:
-   *  - maxObjectDepth: The maximum depth to traverse objects (default: 10)
-   *  - maxArrayDepth: The maximum depth to traverse arrays (default: 20)
-   *  - useNativeJsonEncode: If true will use json_encode() (default: true)
-   *  - includeLineNumbers: If true will include line numbers and filenames (default: true)
-   * 
-   * @param array $Options The options to be set
-   * @return void
-   */
-  public function setOptions($Options) {
-    $this->options = array_merge($this->options,$Options);
-  }
-  
-  /**
-   * Register FirePHP as your error handler
-   * 
-   * Will throw exceptions for each php error.
-   */
-  public function registerErrorHandler()
-  {
-    //NOTE: The following errors will not be caught by this error handler:
-    //      E_ERROR, E_PARSE, E_CORE_ERROR,
-    //      E_CORE_WARNING, E_COMPILE_ERROR,
-    //      E_COMPILE_WARNING, E_STRICT
-    
-    set_error_handler(array($this,'errorHandler'));     
-  }
-
-  /**
-   * FirePHP's error handler
-   * 
-   * Throws exception for each php error that will occur.
-   *
-   * @param int $errno
-   * @param string $errstr
-   * @param string $errfile
-   * @param int $errline
-   * @param array $errcontext
-   */
-  public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
-  {
-    // Don't throw exception if error reporting is switched off
-    if (error_reporting() == 0) {
-      return;
-    }
-    // Only throw exceptions for errors we are asking for
-    if (error_reporting() & $errno) {
-      throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
-    }
-  }
-  
-  /**
-   * Register FirePHP as your exception handler
-   */
-  public function registerExceptionHandler()
-  {
-    set_exception_handler(array($this,'exceptionHandler'));     
-  }
-  
-  /**
-   * FirePHP's exception handler
-   * 
-   * Logs all exceptions to your firebug console and then stops the script.
-   *
-   * @param Exception $Exception
-   * @throws Exception
-   */
-  function exceptionHandler($Exception) {
-    $this->fb($Exception);
-  }
-  
-  /**
-   * Set custom processor url for FirePHP
-   *
-   * @param string $URL
-   */    
-  public function setProcessorUrl($URL)
-  {
-    $this->setHeader('X-FirePHP-ProcessorURL', $URL);
-  }
-
-  /**
-   * Set custom renderer url for FirePHP
-   *
-   * @param string $URL
-   */
-  public function setRendererUrl($URL)
-  {
-    $this->setHeader('X-FirePHP-RendererURL', $URL);
-  }
-  
-  /**
-   * Start a group for following messages
-   *
-   * @param string $Name
-   * @return true
-   * @throws Exception
-   */
-  public function group($Name) {
-    return $this->fb(null, $Name, FirePHP::GROUP_START);
-  }
-  
-  /**
-   * Ends a group you have started before
-   *
-   * @return true
-   * @throws Exception
-   */
-  public function groupEnd() {
-    return $this->fb(null, null, FirePHP::GROUP_END);
-  }
-
-  /**
-   * Log object with label to firebug console
-   *
-   * @see FirePHP::LOG
-   * @param mixes $Object
-   * @param string $Label
-   * @return true
-   * @throws Exception
-   */
-  public function log($Object, $Label=null) {
-    return $this->fb($Object, $Label, FirePHP::LOG);
-  } 
-
-  /**
-   * Log object with label to firebug console
-   *
-   * @see FirePHP::INFO
-   * @param mixes $Object
-   * @param string $Label
-   * @return true
-   * @throws Exception
-   */
-  public function info($Object, $Label=null) {
-    return $this->fb($Object, $Label, FirePHP::INFO);
-  } 
-
-  /**
-   * Log object with label to firebug console
-   *
-   * @see FirePHP::WARN
-   * @param mixes $Object
-   * @param string $Label
-   * @return true
-   * @throws Exception
-   */
-  public function warn($Object, $Label=null) {
-    return $this->fb($Object,&nb