# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: moodle/admin/settings/grades.php
--- moodle/admin/settings/grades.php Base (1.14.2.19)
+++ moodle/admin/settings/grades.php Locally Modified (Based On 1.14.2.19)
@@ -56,6 +56,8 @@
                                                          '5' => '5')));
 
         $temp->add(new admin_setting_special_gradeexport());
+
+        $temp->add(new admin_setting_special_gradelimiting());
     }
     $ADMIN->add('grades', $temp);
 
@@ -75,10 +77,28 @@
                          GRADE_AGGREGATE_MIN             =>get_string('aggregatemin', 'grades'),
                          GRADE_AGGREGATE_MAX             =>get_string('aggregatemax', 'grades'),
                          GRADE_AGGREGATE_MODE            =>get_string('aggregatemode', 'grades'),
-                         GRADE_AGGREGATE_SUM             =>get_string('aggregatesum', 'grades'));
+                         GRADE_AGGREGATE_SUM             =>get_string('aggregatesum', 'grades'),
+// aggregations allowing > 100%
+                         GRADE_AGGREGATE_MEAN_U            =>get_string('aggregatemean_u', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN_U   =>get_string('aggregateweightedmean_u', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN2_U  =>get_string('aggregateweightedmean2_u', 'grades'),
+                         GRADE_AGGREGATE_EXTRACREDIT_MEAN_U=>get_string('aggregateextracreditmean_u', 'grades'),
+                         GRADE_AGGREGATE_MEDIAN_U          =>get_string('aggregatemedian_u', 'grades'),
+                         GRADE_AGGREGATE_MIN_U             =>get_string('aggregatemin_u', 'grades'),
+                         GRADE_AGGREGATE_MAX_U             =>get_string('aggregatemax_u', 'grades'),
+                         GRADE_AGGREGATE_MODE_U            =>get_string('aggregatemode_u', 'grades'),
+                         GRADE_AGGREGATE_SUM_U             =>get_string('aggregatesum_u', 'grades'));
+
+        $defaultvisible = array(GRADE_AGGREGATE_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN2,
+                                GRADE_AGGREGATE_EXTRACREDIT_MEAN, GRADE_AGGREGATE_MEDIAN, GRADE_AGGREGATE_MIN,
+                                GRADE_AGGREGATE_MAX, GRADE_AGGREGATE_MODE, GRADE_AGGREGATE_SUM);
+
         $defaults = array('value'=>GRADE_AGGREGATE_WEIGHTED_MEAN2, 'forced'=>false, 'adv'=>false);
         $temp->add(new admin_setting_gradecat_combo('grade_aggregation', get_string('aggregation', 'grades'), get_string('aggregationhelp', 'grades'), $defaults, $options));
 
+        $temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', get_string('aggregationsvisible', 'grades'),
+                                                       get_string('aggregationsvisiblehelp', 'grades'), $defaultvisible, $options));
+
         $options = array(0 => get_string('no'), 1 => get_string('yes'));
 
         $defaults = array('value'=>1, 'forced'=>false, 'adv'=>true);
Index: moodle/grade/edit/tree/category_form.php
--- moodle/grade/edit/tree/category_form.php Base (1.9.2.15)
+++ moodle/grade/edit/tree/category_form.php Locally Modified (Based On 1.9.2.15)
@@ -26,6 +26,7 @@
 require_once $CFG->libdir.'/formslib.php';
 
 class edit_category_form extends moodleform {
+    var $allaggoptions;
 
     function definition() {
         global $CFG, $COURSE;
@@ -39,7 +40,18 @@
                          GRADE_AGGREGATE_MIN             =>get_string('aggregatemin', 'grades'),
                          GRADE_AGGREGATE_MAX             =>get_string('aggregatemax', 'grades'),
                          GRADE_AGGREGATE_MODE            =>get_string('aggregatemode', 'grades'),
-                         GRADE_AGGREGATE_SUM             =>get_string('aggregatesum', 'grades'));
+                         GRADE_AGGREGATE_SUM             =>get_string('aggregatesum', 'grades'),
+// aggregations allowing > 100%
+                         GRADE_AGGREGATE_MEAN_U            =>get_string('aggregatemean_u', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN_U   =>get_string('aggregateweightedmean_u', 'grades'),
+                         GRADE_AGGREGATE_WEIGHTED_MEAN2_U  =>get_string('aggregateweightedmean2_u', 'grades'),
+                         GRADE_AGGREGATE_EXTRACREDIT_MEAN_U=>get_string('aggregateextracreditmean_u', 'grades'),
+                         GRADE_AGGREGATE_MEDIAN_U          =>get_string('aggregatemedian_u', 'grades'),
+                         GRADE_AGGREGATE_MIN_U             =>get_string('aggregatemin_u', 'grades'),
+                         GRADE_AGGREGATE_MAX_U             =>get_string('aggregatemax_u', 'grades'),
+                         GRADE_AGGREGATE_MODE_U            =>get_string('aggregatemode_u', 'grades'),
+                         GRADE_AGGREGATE_SUM_U             =>get_string('aggregatesum_u', 'grades'));
+        $this->allaggoptions = array_keys($options);
 
         // visible elements
         $mform->addElement('header', 'headercategory', get_string('gradecategory', 'grades'));
@@ -55,6 +67,7 @@
         $mform->addElement('checkbox', 'aggregateonlygraded', get_string('aggregateonlygraded', 'grades'));
         $mform->setHelpButton('aggregateonlygraded', array('aggregateonlygraded', get_string('aggregateonlygraded', 'grades'),'grade'), true);
         $mform->disabledIf('aggregateonlygraded', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
+        $mform->disabledIf('aggregateonlygraded', 'aggregation', 'eq', GRADE_AGGREGATE_SUM_U);
         if ((int)$CFG->grade_aggregateonlygraded_flag & 2) {
             $mform->setAdvanced('aggregateonlygraded');
         }
@@ -111,10 +124,10 @@
                 $default = $cat->id;
             }
             if ($cat->is_aggregationcoef_used()) {
-                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefweight') ? 'aggregationcoefweight' : 'aggregationcoef';
 
-                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextra') ? 'aggregationcoefextra' : 'aggregationcoef';
 
                 } else {
@@ -194,10 +207,13 @@
             }
         }
 
+        $current_aggregation = null;
+
         if ($id = $mform->getElementValue('id')) {
             $grade_category = grade_category::fetch(array('id'=>$id));
             $grade_item = $grade_category->load_grade_item();
 
+            $current_aggregation = $grade_category->aggregation;
 
             // remove agg coef if not used
             if ($grade_category->is_course_category()) {
@@ -224,9 +240,9 @@
                     //fix label if needed
                     $agg_el =& $mform->getElement('aggregationcoef');
                     $aggcoef = '';
-                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                         $aggcoef = 'aggregationcoefweight';
-                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                         $aggcoef = 'aggregationcoefextra';
                     }
                     if ($aggcoef !== '') {
@@ -272,6 +288,21 @@
             } 
         }
 
+        // remove unvanted aggregation options
+        if ($mform->elementExists('aggregation')) {
+            $agg_el =& $mform->getElement('aggregation');
+            $visible = explode(',', $CFG->grade_aggregations_visible);
+            if (!is_null($current_aggregation)) {
+                // current type is always visible
+                $visible[] = $current_aggregation;
+            }
+            foreach ($this->allaggoptions as $type) {
+                if (!in_array($type, $visible)) {
+                    $agg_el->removeOption($type);
+                }
+            }
+        }
+
         // no parent header for course category
         if (!$mform->elementExists('aggregationcoef') and !$mform->elementExists('parentcategory')) {
             $mform->removeElement('headerparent');
Index: moodle/grade/edit/tree/item.php
--- moodle/grade/edit/tree/item.php Base (1.14.2.4)
+++ moodle/grade/edit/tree/item.php Locally Modified (Based On 1.14.2.4)
@@ -93,7 +93,7 @@
 
 if (empty($parent_category)) {
     $item->aggregationcoef = 0;
-} else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+} else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_SUM_U) {
     $item->aggregationcoef = $item->aggregationcoef > 0 ? 1 : 0;
 } else {
     $item->aggregationcoef = format_float($item->aggregationcoef, 4);
Index: moodle/grade/edit/tree/item_form.php
--- moodle/grade/edit/tree/item_form.php Base (1.20.2.19)
+++ moodle/grade/edit/tree/item_form.php Locally Modified (Based On 1.20.2.19)
@@ -156,13 +156,13 @@
                 $default = $cat->id;
             }
             if ($cat->is_aggregationcoef_used()) {
-                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefweight') ? 'aggregationcoefweight' : 'aggregationcoef';
 
-                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextra') ? 'aggregationcoefextra' : 'aggregationcoef';
 
-                } else if ($cat->aggregation == GRADE_AGGREGATE_SUM) {
+                } else if ($cat->aggregation == GRADE_AGGREGATE_SUM or $cat->aggregation == GRADE_AGGREGATE_SUM_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextrasum') ? 'aggregationcoefextrasum' : 'aggregationcoef';
 
                 } else {
@@ -279,13 +279,13 @@
                     //fix label if needed
                     $agg_el =& $mform->getElement('aggregationcoef');
                     $aggcoef = '';
-                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                         $aggcoef = 'aggregationcoefweight';
 
-                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                         $aggcoef = 'aggregationcoefextra';
 
-                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_SUM_U) {
                         $aggcoef = 'aggregationcoefextrasum';
                     }
 
@@ -297,7 +297,7 @@
             }
 
             if ($category = $grade_item->get_item_category()) {
-                if ($category->aggregation == GRADE_AGGREGATE_SUM) {
+                if ($category->aggregation == GRADE_AGGREGATE_SUM or $category->aggregation == GRADE_AGGREGATE_SUM_U) {
                     if ($mform->elementExists('gradetype')) {
                         $mform->hardFreeze('gradetype');
                     }
Index: moodle/grade/edit/tree/outcomeitem.php
--- moodle/grade/edit/tree/outcomeitem.php Base (1.15.2.7)
+++ moodle/grade/edit/tree/outcomeitem.php Locally Modified (Based On 1.15.2.7)
@@ -91,7 +91,7 @@
 
 if (empty($parent_category)) {
     $item->aggregationcoef = 0;
-} else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+} else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_SUM_U) {
     $item->aggregationcoef = $item->aggregationcoef > 0 ? 1 : 0;
 } else {
     $item->aggregationcoef = format_float($item->aggregationcoef, 4);
Index: moodle/grade/edit/tree/outcomeitem_form.php
--- moodle/grade/edit/tree/outcomeitem_form.php Base (1.12.2.14)
+++ moodle/grade/edit/tree/outcomeitem_form.php Locally Modified (Based On 1.12.2.14)
@@ -99,13 +99,13 @@
                 $default = $cat->id;
             }
             if ($cat->is_aggregationcoef_used()) {
-                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                if ($cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $cat->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefweight') ? 'aggregationcoefweight' : 'aggregationcoef';
 
-                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                } else if ($cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $cat->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextra') ? 'aggregationcoefextra' : 'aggregationcoef';
 
-                } else if ($cat->aggregation == GRADE_AGGREGATE_SUM) {
+                } else if ($cat->aggregation == GRADE_AGGREGATE_SUM or $cat->aggregation == GRADE_AGGREGATE_SUM_U) {
                     $coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextrasum') ? 'aggregationcoefextrasum' : 'aggregationcoef';
 
                 } else {
@@ -190,7 +190,7 @@
 
                 $parent_category->apply_forced_settings();
 
-                if (!$parent_category->is_aggregationcoef_used() or $parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+                if (!$parent_category->is_aggregationcoef_used() or $parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_SUM_U) {
                     if ($mform->elementExists('aggregationcoef')) {
                         $mform->removeElement('aggregationcoef');
                     }
@@ -198,13 +198,13 @@
                     //fix label if needed
                     $agg_el =& $mform->getElement('aggregationcoef');
                     $aggcoef = '';
-                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                    if ($parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U) {
                         $aggcoef = 'aggregationcoefweight';
 
-                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN or $parent_category->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U) {
                         $aggcoef = 'aggregationcoefextra';
 
-                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM) {
+                    } else if ($parent_category->aggregation == GRADE_AGGREGATE_SUM or $parent_category->aggregation == GRADE_AGGREGATE_SUM_U) {
                         $aggcoef = 'aggregationcoefextrasum';
                     }
 
Index: moodle/grade/lib.php
--- moodle/grade/lib.php Base (1.120.2.22)
+++ moodle/grade/lib.php Locally Modified (Based On 1.120.2.22)
@@ -790,12 +790,18 @@
                     if ($category = $element['object']->get_item_category()) {
                         switch ($category->aggregation) {
                             case GRADE_AGGREGATE_MEAN:
+                            case GRADE_AGGREGATE_MEAN_U:
                             case GRADE_AGGREGATE_MEDIAN:
+                            case GRADE_AGGREGATE_MEDIAN_U:
                             case GRADE_AGGREGATE_WEIGHTED_MEAN:
+                            case GRADE_AGGREGATE_WEIGHTED_MEAN_U:
                             case GRADE_AGGREGATE_WEIGHTED_MEAN2:
+                            case GRADE_AGGREGATE_WEIGHTED_MEAN2_U:
                             case GRADE_AGGREGATE_EXTRACREDIT_MEAN:
+                            case GRADE_AGGREGATE_EXTRACREDIT_MEAN_U:
                                 return '<img src="'.$CFG->pixpath.'/i/agg_mean.gif" class="icon itemicon" alt="'.get_string('aggregation', 'grades').'"/>';
                             case GRADE_AGGREGATE_SUM:
+                            case GRADE_AGGREGATE_SUM_U:
                                 return '<img src="'.$CFG->pixpath.'/i/agg_sum.gif" class="icon itemicon" alt="'.get_string('aggregation', 'grades').'"/>';
                         }
                     }
Index: moodle/grade/report/grader/lib.php
--- moodle/grade/report/grader/lib.php Base (1.98.2.49)
+++ moodle/grade/report/grader/lib.php Locally Modified (Based On 1.98.2.49)
@@ -817,7 +817,7 @@
                             if ($gradeval < 1) {
                                 $studentshtml .= '<span class="gradevalue'.$hidden.$gradepass.'">-</span>';
                             } else {
-                                $gradeval = (int)bounded_number($grade->grade_item->grademin, $gradeval, $grade->grade_item->grademax); //just in case somebody changes scale
+                                $gradeval = $grade->grade_item->bounded_grade($gradeval); //just in case somebody changes scale
                                 $studentshtml .= '<span class="gradevalue'.$hidden.$gradepass.'">'.$scales[$gradeval-1].'</span>';
                             }
                         } else {
Index: moodle/lang/en_utf8/grades.php
--- moodle/lang/en_utf8/grades.php Base (1.111.2.60)
+++ moodle/lang/en_utf8/grades.php Locally Modified (Based On 1.111.2.60)
@@ -12,11 +12,17 @@
 $string['additem'] = 'Add grade item';
 $string['addoutcomeitem'] = 'Add outcome item';
 $string['aggregateextracreditmean'] = 'Mean of grades (with extra credits)';
+$string['aggregateextracreditmean_u'] = 'Mean of grades (unlimited with extra credits)';
 $string['aggregatemean'] = 'Mean of grades';
+$string['aggregatemean_u'] = 'Mean of grades (unlimited)';
 $string['aggregatemedian'] = 'Median of grades';
+$string['aggregatemedian_u'] = 'Median of grades (unlimited)';
 $string['aggregatemin'] = 'Lowest grade';
+$string['aggregatemin_u'] = 'Lowest grade (unlimited)';
 $string['aggregatemax'] = 'Highest grade';
+$string['aggregatemax_u'] = 'Highest grade (unlimited)';
 $string['aggregatemode'] = 'Mode of grades';
+$string['aggregatemode_u'] = 'Mode of grades (unlimited)';
 $string['aggregateonlygraded'] = 'Aggregate only non-empty grades';
 $string['aggregateonlygradedhelp'] = 'Nonexistent grades are either treated as minimal grades or not included in aggregation.';
 $string['aggregateoutcomes'] = 'Include outcomes in aggregation';
@@ -24,9 +30,12 @@
 $string['aggregatesubcats'] = 'Aggregate including subcategories';
 $string['aggregatesubcatshelp'] = 'The aggregation is usually done only with immediate children, it is also possible to aggregate grades in all subcategories excluding other aggregated grades.';
 $string['aggregatesum'] = 'Sum of grades';
+$string['aggregatesum_u'] = 'Sum of grades (unlimited)';
 $string['aggregatesonly'] = 'Aggregates only';
 $string['aggregateweightedmean'] = 'Weighted mean of grades';
+$string['aggregateweightedmean_u'] = 'Weighted mean of grades (unlimited)';
 $string['aggregateweightedmean2'] = 'Simple weighted mean of grades';
+$string['aggregateweightedmean2_u'] = 'Simple weighted mean of grades (unlimited)';
 $string['aggregation'] = 'Aggregation';
 $string['aggregationcoef'] = 'Aggregation coefficient';
 $string['aggregationcoefextra'] = 'Extra credit';
@@ -37,6 +46,8 @@
 $string['aggregationcoefweighthelp'] = 'Weight applied to all grades in this grade item during aggregation with other grade items.';
 $string['aggregationhelp'] = 'Strategy used to aggregate grades across all students in a course.';
 $string['aggregationposition'] = 'Aggregation position';
+$string['aggregationsvisible'] = 'Selectable aggregation types';
+$string['aggregationsvisiblehelp'] = 'Select all aggragation types that should be available. Hint: use ctrl key when selecting.';
 $string['aggregationview'] = 'Aggregation view';
 $string['allgrades'] = 'All grades by category';
 $string['allstudents'] = 'All students';
@@ -111,6 +122,8 @@
 $string['configshowuserimage'] = 'Whether to show the user\'s profile image next to the name in the grader report.';
 $string['configstudentsperpage'] = 'The number of students to display per page in the grader report.';
 $string['configstudentsperpagedefault'] = 'The number of students to display per page in the grader report. Leave this field empty to use the site default (currently $a).';
+$string['configunlimitedgrades'] = 'By default grade values are limited by corresponding grade minimun and maximum, the only exception is unlimited aggregation types.
+Enable this option only if your organisation uses grades over hundred procent everywhere. Please not that all grades need to be recalculated which may cause high server load.';
 $string['contract'] = 'Contract Category';
 $string['controls'] = 'Controls';
 $string['coursegradecategory'] = 'Course grade category';
@@ -502,6 +515,7 @@
 $string['uncategorised'] = 'Uncategorised';
 $string['unchangedgrade'] = 'Grade unchanged';
 $string['unenrolledusersinimport'] = 'This import included the following grades for users not currently enrolled in this course: $a';
+$string['unlimitedgrades'] = 'Unlimited grade values';
 $string['unlock'] = 'Unlock';
 $string['unlockverbose'] = 'Unlock $a->category$a->itemmodule $a->itemname';
 $string['unused'] = 'Unused';
Index: moodle/lib/adminlib.php
--- moodle/lib/adminlib.php Base (1.153.2.66)
+++ moodle/lib/adminlib.php Locally Modified (Based On 1.153.2.66)
@@ -3484,6 +3484,35 @@
     }
 }
 
+class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
+    function admin_setting_special_gradelimiting() {
+        parent::admin_setting_configcheckbox('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
+                                                  get_string('configunlimitedgrades', 'grades'), '0', '1', '0');
+    }
+
+    function regrade_all() {
+        global $CFG;
+        require_once("$CFG->libdir/gradelib.php");
+        grade_force_site_regrading();
+    }
+
+    function write_setting($data) {
+        $previous = $this->get_setting();
+
+        if ($previous === null) {
+            if ($data) {
+                $this->regrade_all();
+            }
+        } else {
+            if ($data != $previous) {
+                $this->regrade_all();
+            }
+        }
+        return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
+    }
+
+}
+
 /**
  * Primary grade export plugin - has state tracking.
  */
Index: moodle/lib/form/select.php
--- moodle/lib/form/select.php Base (1.10)
+++ moodle/lib/form/select.php Locally Modified (Based On 1.10)
@@ -92,6 +92,8 @@
         foreach ($this->_options as $key=>$option){
             if ($option['attr']['value']==$value){
                 unset($this->_options[$key]);
+                // we must reindex the options because the ugly code in quickforms' select.php expects that keys are 0,1,2,3... !?!?
+                $this->_options = array_merge($this->_options);
\ No newline at end of file
                 return;
             }
         }
Index: moodle/lib/grade/constants.php
--- moodle/lib/grade/constants.php Base (1.7.2.3)
+++ moodle/lib/grade/constants.php Locally Modified (Based On 1.7.2.3)
@@ -43,6 +43,17 @@
 define('GRADE_AGGREGATE_EXTRACREDIT_MEAN', 12);
 define('GRADE_AGGREGATE_SUM', 13);
 
+// value > 99 means aggregation allows grades > 100%
+define('GRADE_AGGREGATE_MEAN_U', 100);
+define('GRADE_AGGREGATE_MEDIAN_U', 102);
+define('GRADE_AGGREGATE_MIN_U', 104);
+define('GRADE_AGGREGATE_MAX_U', 106);
+define('GRADE_AGGREGATE_MODE_U', 108);
+define('GRADE_AGGREGATE_WEIGHTED_MEAN_U', 110);
+define('GRADE_AGGREGATE_WEIGHTED_MEAN2_U', 111);
+define('GRADE_AGGREGATE_EXTRACREDIT_MEAN_U', 112);
+define('GRADE_AGGREGATE_SUM_U', 113);
+
 // grade types
 define('GRADE_TYPE_NONE', 0);
 define('GRADE_TYPE_VALUE', 1);
Index: moodle/lib/grade/grade_category.php
--- moodle/lib/grade/grade_category.php Base (1.96.2.22)
+++ moodle/lib/grade/grade_category.php Locally Modified (Based On 1.96.2.22)
@@ -507,7 +507,7 @@
 
 
     /// sum is a special aggregation types - it adjusts the min max, does not use relative values
-        if ($this->aggregation == GRADE_AGGREGATE_SUM) {
+        if ($this->aggregation == GRADE_AGGREGATE_SUM or $this->aggregation == GRADE_AGGREGATE_SUM_U) {
             $this->sum_grades($grade, $oldfinalgrade, $items, $grade_values, $excluded);
             return;
         }
@@ -564,11 +564,7 @@
         // recalculate the grade back to requested range
         $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $this->grade_item->grademin, $this->grade_item->grademax);
 
-        if (is_null($finalgrade)) {
-            $grade->finalgrade = null;
-        } else {
-            $grade->finalgrade = (float)bounded_number($this->grade_item->grademin, $finalgrade, $this->grade_item->grademax);
-        }
+        $grade->finalgrade = $this->grade_item->bounded_grade($finalgrade);
 
         // update in db if changed
         if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) {
@@ -584,6 +580,7 @@
     function aggregate_values($grade_values, $items) {
         switch ($this->aggregation) {
             case GRADE_AGGREGATE_MEDIAN: // Middle point value in the set: ignores frequencies
+            case GRADE_AGGREGATE_MEDIAN_U:
                 $num = count($grade_values);
                 $grades = array_values($grade_values);
                 if ($num % 2 == 0) {
@@ -594,14 +591,17 @@
                 break;
 
             case GRADE_AGGREGATE_MIN:
+            case GRADE_AGGREGATE_MIN_U:
                 $agg_grade = reset($grade_values);
                 break;
 
             case GRADE_AGGREGATE_MAX:
+            case GRADE_AGGREGATE_MAX:
                 $agg_grade = array_pop($grade_values);
                 break;
 
             case GRADE_AGGREGATE_MODE:       // the most common value, average used if multimode
+            case GRADE_AGGREGATE_MODE_U:
                 // array_count_values only counts INT and STRING, so if grades are floats we must convert them to string
                 $converted_grade_values = array();
 
@@ -622,6 +622,7 @@
                 break;
 
             case GRADE_AGGREGATE_WEIGHTED_MEAN: // Weighted average of all existing final grades, weight specified in coef
+            case GRADE_AGGREGATE_WEIGHTED_MEAN_U:
                 $weightsum = 0;
                 $sum       = 0;
                 foreach($grade_values as $itemid=>$grade_value) {
@@ -639,6 +640,7 @@
                 break;
 
             case GRADE_AGGREGATE_WEIGHTED_MEAN2: // Weighted average of all existing final grades, weight is the range of grade (ususally grademax)
+            case GRADE_AGGREGATE_WEIGHTED_MEAN2_U:
                 $weightsum = 0;
                 $sum       = 0;
                 foreach($grade_values as $itemid=>$grade_value) {
@@ -657,6 +659,7 @@
                 break;
 
             case GRADE_AGGREGATE_EXTRACREDIT_MEAN: // special average
+            case GRADE_AGGREGATE_EXTRACREDIT_MEAN_U:
                 $num = 0;
                 $sum = 0;
                 foreach($grade_values as $itemid=>$grade_value) {
@@ -675,6 +678,7 @@
                 break;
 
             case GRADE_AGGREGATE_MEAN:    // Arithmetic average of all grade items (if ungraded aggregated, NULL counted as minimum)
+            case GRADE_AGGREGATE_MEAN_U:
             default:
                 $num = count($grade_values);
                 $sum = array_sum($grade_values);
@@ -744,8 +748,7 @@
         $this->apply_limit_rules($grade_values);
 
         $sum = array_sum($grade_values);
-        $grade->finalgrade = bounded_number($this->grade_item->grademin, $sum, $this->grade_item->grademax);
-
+        $grade->finalgrade = $this->grade_item->bounded_grade($sum);
         // update in db if changed
         if (grade_floats_different($grade->finalgrade, $oldfinalgrade)) {
             $grade->update('aggregation');
@@ -780,8 +783,11 @@
      */
     function is_aggregationcoef_used() {
         return ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN
+             or $this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN_U
              or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
-             or $this->aggregation == GRADE_AGGREGATE_SUM);
+             or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN_U
+             or $this->aggregation == GRADE_AGGREGATE_SUM
+             or $this->aggregation == GRADE_AGGREGATE_SUM_U);
 
     }
 
Index: moodle/lib/grade/grade_grade.php
--- moodle/lib/grade/grade_grade.php Base (1.14.2.18)
+++ moodle/lib/grade/grade_grade.php Locally Modified (Based On 1.14.2.18)
@@ -667,9 +667,7 @@
                             // recalculate the rawgrade back to requested range
                             $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $grade_items[$do]->grademin, $grade_items[$do]->grademax);
 
-                            if (!is_null($finalgrade)) {
-                                $finalgrade = bounded_number($grade_items[$do]->grademin, $finalgrade, $grade_items[$do]->grademax);
-                            }
+                            $finalgrade = $grade_items[$do]->bounded_grade($finalgrade);
 
                             $altered[$do] = $finalgrade;
                             unset($todo[$key]);
Index: moodle/lib/grade/grade_item.php
--- moodle/lib/grade/grade_item.php Base (1.130.2.29)
+++ moodle/lib/grade/grade_item.php Locally Modified (Based On 1.130.2.29)
@@ -740,7 +740,7 @@
             $rawgrade *= $this->multfactor;
             $rawgrade += $this->plusfactor;
 
-            return bounded_number($this->grademin, $rawgrade, $this->grademax);
+            return $this->bounded_grade($rawgrade);
 
         } else if ($this->gradetype == GRADE_TYPE_SCALE) { // Dealing with a scale value
             if (empty($this->scale)) {
@@ -761,7 +761,7 @@
                 $rawgrade = grade_grade::standardise_score($rawgrade, $rawmin, $rawmax, $this->grademin, $this->grademax);
             }
 
-            return (int)bounded_number(0, round($rawgrade+0.00001), $this->grademax);
+            return $this->bounded_grade($rawgrade);
 
 
         } else if ($this->gradetype == GRADE_TYPE_TEXT or $this->gradetype == GRADE_TYPE_NONE) { // no value
@@ -1215,6 +1215,43 @@
     }
 
     /**
+     * Makes sure value is a valid grade value.
+     * @param float $gradevalue
+     * @return mixed float or int fixed grade value
+     */
+    function bounded_grade($gradevalue) {
+        global $CFG;
+
+        if (is_null($gradevalue)) {
+            return null;
+        }
+
+        if ($this->gradetype == GRADE_TYPE_SCALE) {
+            // no >100% grades hack for scale grades!
+            // 1.5 is rounded to 2 ;-)
+            return (int)bounded_number($this->grademin, round($gradevalue+0.00001), $this->grademax);
+        }
+
+        $grademax = $this->grademax;
+
+        // NOTE: if you change this value you must manually reset the needsupdate flag in all grade items
+        $maxcoef = isset($CFG->gradeoverhundredprocentmax) ? $CFG->gradeoverhundredprocentmax : 10; // 1000% max by default
+
+        if (!empty($CFG->unlimitedgrades)) {
+            // NOTE: if you change this value you must manually reset the needsupdate flag in all grade items
+            $grademax = $grademax * $maxcoef;
+        } else if ($this->is_category_item() or $this->is_course_item()) {
+            $category = $this->load_item_category();
+            if ($category->aggregation >= 100) {
+                // grade >100% hack
+                $grademax = $grademax * $maxcoef;
+            }
+        }
+
+        return (float)bounded_number($this->grademin, $gradevalue, $grademax);
+    }
+
+    /**
      * Finds out on which other items does this depend directly when doing calculation or category agregation
      * @param bool $reset_cache
      * @return array of grade_item ids this one depends on
@@ -1393,11 +1430,7 @@
                 $grade->overridden = 0;
             }
 
-            if (is_null($finalgrade)) {
-                $grade->finalgrade = null;
-            } else {
-                $grade->finalgrade = bounded_number($this->grademin, $finalgrade, $this->grademax);
-            }
+            $grade->finalgrade = $this->bounded_grade($finalgrade);
         }
 
         // do we have comment from teacher?
@@ -1740,11 +1773,7 @@
 
         } else {
             // normalize
-            $result = bounded_number($this->grademin, $result, $this->grademax);
-            if ($this->gradetype == GRADE_TYPE_SCALE) {
-                $result = round($result+0.00001); // round scales upwards
-            }
-            $grade->finalgrade = $result;
+            $grade->finalgrade = $this->bounded_grade($result);
         }
 
         // update in db if changed
Index: moodle/lib/gradelib.php
--- moodle/lib/gradelib.php Base (1.120.2.27)
+++ moodle/lib/gradelib.php Locally Modified (Based On 1.120.2.27)
@@ -706,7 +706,7 @@
             return get_string('error');
         }
 
-        $value = (int)bounded_number($grade_item->grademin, $value, $grade_item->grademax);
+        $value = $grade_item->bounded_grade($value);
         return format_string($scale->scale_items[$value-1]);
 
     } else {
@@ -720,7 +720,7 @@
     if ($min == $max) {
         return '';
     }
-    $value = bounded_number($min, $value, $max);
+    $value = $grade_item->bounded_grade($value);
     $percentage = (($value-$min)*100)/($max-$min);
     return format_float($percentage, $decimals, $localized).' %';
 }
@@ -731,6 +731,10 @@
         return ''; // no letters??
     }
 
+    if (is_null($value)) {
+        return '-';
+    }
+
     $value = grade_grade::standardise_score($value, $grade_item->grademin, $grade_item->grademax, 0, 100);
     $value = bounded_number(0, $value, 100); // just in case
     foreach ($letters as $boundary => $letter) {
@@ -862,6 +866,15 @@
 }
 
 /**
+ * Forces regrading of all site grades - usualy when chanign site setings
+ */
+function grade_force_site_regrading() {
+    global $CFG;
+    $sql = "UPDATE {$CFG->prefix}grade_items SET needsupdate=1";
+    execute_sql($sql);
+}
+
+/**
  * Updates all final grades in course.
  *
  * @param int $courseid
