Skip to content

Commit ccf756e

Browse files
Merge pull request #602 from turnitin/develop
Release 2020111801
2 parents bf0299b + b6dd395 commit ccf756e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+4943
-2517
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
### Date: 2020-Nov-18
2+
### Release: v2020111801
3+
4+
---
5+
6+
#### :wrench: Fixes and enhancements
7+
8+
#### Rubrics sync back to the assignment
9+
A bug could cause a rubric that is attached to a multi-part assignment from within the Turnitin viewer to become detached after opening it again. Rubrics will now correctly sync to the assignment and remain attached.
10+
11+
#### Tooltip shows correct maximum file size limit
12+
Turnitin updated our maximum file size limit quite some time ago, but the file size provided in the tooltip had slipped through the net! It will now accurately reflect the maximum file size.
13+
14+
---
15+
116
### Date: 2020-Jul-22
217
### Release: v2020072201
318

ajax.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@
279279
$updatefromtii = ($refreshrequested || $turnitintooltwoassignment->turnitintooltwo->autoupdates == 1) ? 1 : 0;
280280
$istutor = (has_capability('mod/turnitintooltwo:grade', context_module::instance($cm->id))) ? true : false;
281281

282+
if ($refreshrequested && $start == 0) {
283+
$turnitintooltwoassignment->update_assignment_from_tii();
284+
}
285+
282286
if ($updatefromtii && $start == 0) {
283287
$turnitintooltwoassignment->get_submission_ids_from_tii($parts[$partid]);
284288
$total = count($_SESSION["TiiSubmissions"][$partid]);
@@ -603,7 +607,7 @@
603607

604608
$modules = $DB->get_record('modules', array('name' => 'turnitintooltwo'));
605609

606-
$return = turnitintooltwo_get_courses_from_tii($tiiintegrationids, $title, $courseintegration, $enddate, $source);
610+
$return = turnitintooltwo_get_courses_from_tii(turnitintooltwo_get_integration_ids(), $title, $courseintegration, $enddate, $source);
607611
echo json_encode($return);
608612
break;
609613

backup/moodle2/backup_turnitintooltwo_stepslib.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ protected function define_structure() {
4949
'studentreports', 'dateformat', 'usegrademark', 'gradedisplay', 'autoupdates', 'commentedittime', 'commentmaxsize',
5050
'autosubmission', 'shownonsubmission', 'excludebiblio', 'excludequoted', 'excludevalue', 'excludetype', 'erater',
5151
'erater_handbook', 'erater_dictionary', 'erater_spelling', 'erater_grammar', 'erater_usage', 'erater_mechanics',
52-
'erater_style', 'transmatch', 'allownonor'
52+
'erater_style', 'transmatch', 'rubric', 'allownonor'
5353
));
5454

5555
$parts = new backup_nested_element('parts');

classes/digitalreceipt/instructor_message.php

+1-6
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ public function send_instructor_message($instructors, $message, $courseid) {
5353

5454
$subject = get_string('receipt_instructor_copy_subject', 'turnitintooltwo');
5555

56-
// Pre 2.9 does not have \core\message\message()
57-
if ($CFG->branch >= 29) {
58-
$eventdata = new \core\message\message();
59-
} else {
60-
$eventdata = new stdClass();
61-
}
56+
$eventdata = new \core\message\message();
6257

6358
$eventdata->component = 'mod_turnitintooltwo';
6459
$eventdata->name = 'notify_instructor_of_submission'; // This is the message name from messages.php.

classes/digitalreceipt/receipt_message.php

+1-6
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,7 @@ public function send_message($userid, $message, $courseid) {
2929

3030
$subject = get_string('digital_receipt_subject', 'turnitintooltwo');
3131

32-
// Pre 2.9 does not have \core\message\message()
33-
if ($CFG->branch >= 29) {
34-
$eventdata = new \core\message\message();
35-
} else {
36-
$eventdata = new stdClass();
37-
}
32+
$eventdata = new \core\message\message();
3833

3934
$eventdata->component = 'mod_turnitintooltwo';
4035
$eventdata->name = 'submission'; // This is the message name from messages.php.

classes/v1migration/v1migration.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ private function log_success_migration_event($turnitintooltwoid, $course_id, $v1
545545
}
546546

547547
/**
548-
* Get assignments for migrated data table. Called from ajax.php via turnitintooltwo_extra-2018102601.min.js.
548+
* Get assignments for migrated data table. Called from ajax.php via turnitintooltwo_extra-2020111101.min.js.
549549
*
550550
* @global type $DB
551551
* @return array return array of assignments to display

classes/view/members.php

+3-4
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,17 @@ public function __construct($course=null, $coursemodule=null, $turnitintooltwovi
4141
* @return string Members HTML for a role
4242
*/
4343
public function build_members_view($displayrole = "students") {
44-
$output = "";
4544
$istutor = $this->is_tutor();
4645

4746
if (!$istutor) {
4847
turnitintooltwo_print_error('permissiondeniederror', 'turnitintooltwo');
4948
exit();
5049
}
5150

52-
$wrapperclass = $displayrole == "tutors" ? "members members-instructors" : "members members-students";
51+
$wrapperclass = $displayrole == "tutors" ? "members-instructors" : "members-students";
5352

54-
// wrapper element for strong CSS selectors
55-
$output .= html_writer::start_tag("div", array("class" => $wrapperclass));
53+
// Wrapper element for strong CSS selectors.
54+
$output = html_writer::start_tag("div", array("class" => "mod_turnitintooltwo_members " . $wrapperclass));
5655

5756
$output .= $this->build_intro_message($displayrole);
5857
$output .= $this->build_members_table($displayrole);

css/student_noscript.css

+9-14
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,28 @@
1-
.mod_turnitintooltwo .submissionsDataTable {
1+
.mod_turnitintooltwo_submissions_data_table {
22
margin-top:16px;
33
}
44

5-
.mod_turnitintooltwo .submissionsDataTable th {
5+
.mod_turnitintooltwo_submissions_data_table th {
66
border:1px solid #999999;
77
}
88

9-
.mod_turnitintooltwo .submissionsDataTable td {
9+
.mod_turnitintooltwo_submissions_data_table td {
1010
border:1px solid #999999;
1111
}
1212

13-
.mod_turnitintooltwo #tabs ul#part_tabs_menu, .mod_turnitintooltwo a.toggle_summary, .mod_turnitintooltwo a.toggle_peermarks,
14-
.mod_turnitintooltwo a.toggle_peermark_instructions, .mod_turnitintooltwo .turnitin_ula, .mod_turnitintooltwo a.messages_inbox,
15-
.mod_turnitintooltwo .noscript_hide, .mod_turnitintooltwo .download_original_open, .mod_turnitintooltwo th.raw_data,
16-
.mod_turnitintooltwo td.raw_data, .mod_turnitintooltwo .submissionsDataTable th.cpart,
17-
.mod_turnitintooltwo .submissionsDataTable th.ccheckbox, .mod_turnitintooltwo .submissionsDataTable td.c0,
18-
.mod_turnitintooltwo .submissionsDataTable td.c1 {
13+
.mod_turnitintooltwo #tabs ul#part_tabs_menu, .mod_turnitintooltwo a.toggle_summary, .mod_turnitintooltwo a.toggle_peermarks,
14+
.mod_turnitintooltwo a.toggle_peermark_instructions, .mod_turnitintooltwo .mod_turnitintooltwo_eula, .mod_turnitintooltwo_messages_inbox,
15+
.mod_turnitintooltwo .noscript_hide, .mod_turnitintooltwo .download_original_open, .mod_turnitintooltwo th.raw_data,
16+
.mod_turnitintooltwo td.raw_data, .mod_turnitintooltwo_submissions_data_table th.cpart,
17+
.mod_turnitintooltwo_submissions_data_table th.ccheckbox, .mod_turnitintooltwo_submissions_data_table td.c0,
18+
.mod_turnitintooltwo_submissions_data_table td.c1 {
1919
display:none;
2020
}
2121

2222
.mod_turnitintooltwo .peermark_instructions {
2323
display: block;
2424
}
2525

26-
.mod_turnitintooltwo .turnitin_ula_noscript {
27-
line-height: 28px;
28-
margin-top:16px;
29-
}
30-
3126
.mod_turnitintooltwo .part_table {
3227
background:#EFEFEF;
3328
border:1px solid #DEDEDE;

db/install.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<FIELD NAME="transmatch" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="erater_style" NEXT="rubric"/>
5656
<FIELD NAME="rubric" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="transmatch" NEXT="allownonor"/>
5757
<FIELD NAME="allownonor" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="rubric" NEXT="needs_updating"/>
58-
<FIELD NAME="needs_updating" TYPE="int" LENGTH="10" NOTNULL="false" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="allownonor" NEXT="syncreport"/>
58+
<FIELD NAME="needs_updating" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="allownonor" NEXT="syncreport"/>
5959
<FIELD NAME="syncreport" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="needs_updating" NEXT="anongradebook"/>
6060
<FIELD NAME="anongradebook" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="syncreport" NEXT="legacy"/>
6161
<FIELD NAME="legacy" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="anongradebook"/>
@@ -79,8 +79,8 @@
7979
<FIELD NAME="maxmarks" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" PREVIOUS="dtpost" NEXT="deleted"/>
8080
<FIELD NAME="deleted" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" PREVIOUS="maxmarks" NEXT="migrated"/>
8181
<FIELD NAME="migrated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="deleted" NEXT="unanon"/>
82-
<FIELD NAME="unanon" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="migrated" NEXT="submitted"/>
83-
<FIELD NAME="submitted" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="unanon" NEXT="gradesupdated"/>
82+
<FIELD NAME="unanon" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="migrated" NEXT="submitted"/>
83+
<FIELD NAME="submitted" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="unanon" NEXT="gradesupdated"/>
8484
<FIELD NAME="gradesupdated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" UNSIGNED="false" SEQUENCE="false" PREVIOUS="submitted"/>
8585
</FIELDS>
8686
<KEYS>

db/upgrade.php

+52-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
4545
if (!$dbman->field_exists($table, $field2)) {
4646
$dbman->add_field($table, $field2);
4747
}
48+
upgrade_mod_savepoint(true, 2014012401, 'turnitintooltwo');
4849
}
4950

5051
if ($oldversion < 2014012404) {
@@ -54,6 +55,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
5455
if (!$dbman->field_exists($table, $field)) {
5556
$dbman->add_field($table, $field);
5657
}
58+
upgrade_mod_savepoint(true, 2014012404, 'turnitintooltwo');
5759
}
5860

5961
if ($oldversion < 2014012405) {
@@ -89,6 +91,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
8991
if (!$dbman->index_exists($table, $index)) {
9092
$dbman->add_index($table, $index);
9193
}
94+
upgrade_mod_savepoint(true, 2014012405, 'turnitintooltwo');
9295
}
9396

9497
if ($oldversion < 2014012412) {
@@ -97,6 +100,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
97100
if (!$dbman->field_exists($table, $field)) {
98101
$dbman->add_field($table, $field);
99102
}
103+
upgrade_mod_savepoint(true, 2014012412, 'turnitintooltwo');
100104
}
101105

102106
if ($oldversion < 2015040101) {
@@ -115,6 +119,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
115119
if (!$dbman->index_exists($table, $index)) {
116120
$dbman->add_index($table, $index);
117121
}
122+
upgrade_mod_savepoint(true, 2015040101, 'turnitintooltwo');
118123
}
119124

120125
if ($oldversion < 2015040104) {
@@ -128,6 +133,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
128133
} else {
129134
$dbman->change_field_unsigned($table, $field);
130135
}
136+
upgrade_mod_savepoint(true, 2015040104, 'turnitintooltwo');
131137
}
132138

133139
if ($oldversion < 2015040107) {
@@ -138,18 +144,21 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
138144
if (!$dbman->field_exists($table, $field)) {
139145
$dbman->add_field($table, $field);
140146
}
147+
upgrade_mod_savepoint(true, 2015040107, 'turnitintooltwo');
141148
}
142149

143150
if ($oldversion < 2015040109) {
144151
// Update URL for UK accounts.
145152
$apiurl = get_config('turnitintooltwo', 'apiurl');
146153
$newurl = str_replace('submit.ac.uk', 'api.turnitinuk.com', strtolower($apiurl));
147154
set_config('apiurl', $newurl, 'turnitintooltwo');
155+
upgrade_mod_savepoint(true, 2015040109, 'turnitintooltwo');
148156
}
149157

150158
if ($oldversion < 2015040111) {
151159
// Update gradedisplay value to be consistent with V1 plugin.
152160
$DB->set_field("turnitintooltwo", "gradedisplay", 2);
161+
upgrade_mod_savepoint(true, 2015040111, 'turnitintooltwo');
153162
}
154163

155164
if ($oldversion < 2016011101) {
@@ -165,6 +174,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
165174
if (!$dbman->field_exists($table, $field)) {
166175
$dbman->add_field($table, $field);
167176
}
177+
upgrade_mod_savepoint(true, 2016011101, 'turnitintooltwo');
168178
}
169179

170180
if ($oldversion < 2016011107) {
@@ -175,6 +185,7 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
175185
if (!$dbman->field_exists($table, $field)) {
176186
$dbman->add_field($table, $field);
177187
}
188+
upgrade_mod_savepoint(true, 2016011107, 'turnitintooltwo');
178189
}
179190

180191
if ($oldversion < 2017011301) {
@@ -236,6 +247,8 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
236247
// Add hash as key after update.
237248
$key = new xmldb_key('submission_hash', XMLDB_KEY_UNIQUE, array('submission_hash'));
238249
$dbman->add_key($table, $key);
250+
251+
upgrade_mod_savepoint(true, 2017011301, 'turnitintooltwo');
239252
}
240253

241254
if ($oldversion < 2017103001) {
@@ -251,7 +264,45 @@ function xmldb_turnitintooltwo_upgrade($oldversion) {
251264
if (!$dbman->field_exists($table, $field)) {
252265
$dbman->add_field($table, $field);
253266
}
267+
upgrade_mod_savepoint(true, 2017103001, 'turnitintooltwo');
268+
}
269+
270+
// This block is to solve a number of inconsistencies between the install and upgrade scripts
271+
if ($oldversion < 2020081401) {
272+
$table = new xmldb_table('turnitintooltwo');
273+
// Ensure default for institution check is 0.
274+
$field = new xmldb_field('institution_check', XMLDB_TYPE_INTEGER, '1', false, false, null, 0, 'journalcheck');
275+
if ($dbman->field_exists($table, $field)) {
276+
$dbman->change_field_default($table, $field);
277+
}
278+
279+
// Ensure needs_updating allows null and int length is 1.
280+
$field = new xmldb_field('needs_updating', XMLDB_TYPE_INTEGER, '1', null, false, null, 0, 'allownonor');
281+
if ($dbman->field_exists($table, $field)) {
282+
$dbman->change_field_notnull($table, $field);
283+
$dbman->change_field_precision($table, $field);
284+
}
285+
286+
$table = new xmldb_table('turnitintooltwo_parts');
287+
// Ensure unanon length is 1.
288+
$field = new xmldb_field('unanon', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0, 'migrated');
289+
if ($dbman->field_exists($table, $field)) {
290+
$dbman->change_field_precision($table, $field);
291+
}
292+
// Ensure submitted length is 1.
293+
$field = new xmldb_field('submitted', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, 0, 'unanon');
294+
if ($dbman->field_exists($table, $field)) {
295+
$dbman->change_field_precision($table, $field);
296+
}
297+
298+
$table = new xmldb_table('turnitintooltwo_users');
299+
// Ensure user_agreement_accepted allows null.
300+
$field = new xmldb_field('user_agreement_accepted', XMLDB_TYPE_INTEGER, '1', false, false, null, 0, 'instructor_rubrics');
301+
if ($dbman->field_exists($table, $field)) {
302+
$dbman->change_field_notnull($table, $field);
303+
}
304+
upgrade_mod_savepoint(true, 2020081401, 'turnitintooltwo');
254305
}
255306

256307
return true;
257-
}
308+
}

extras.php

+4-10
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,7 @@
3939

4040
// Get course and module data that we've linked to here from and set context accordingly.
4141
if ($id != 0) {
42-
// Pre 2.8 does not have the function get_course_and_cm_from_cmid.
43-
if ($CFG->branch >= 28) {
44-
list($course, $cm) = get_course_and_cm_from_cmid($id, 'turnitintooltwo');
45-
} else {
46-
$cm = get_coursemodule_from_id('turnitintooltwo', $id, 0, false, MUST_EXIST);
47-
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
48-
}
42+
list($course, $cm) = get_course_and_cm_from_cmid($id, 'turnitintooltwo');
4943

5044
if (!$cm) {
5145
turnitintooltwo_print_error('coursemodidincorrect', 'turnitintooltwo');
@@ -91,7 +85,7 @@
9185
'name' => 'search_course_title'));
9286

9387
$coursesearchform .= html_writer::label(get_string('integration', 'turnitintooltwo').': ', 'search_course_integration');
94-
$coursesearchform .= html_writer::select($tiiintegrationids, 'search_course_integration', '', array('' => 'choosedots'),
88+
$coursesearchform .= html_writer::select(turnitintooltwo_get_integration_ids(), 'search_course_integration', '', array('' => 'choosedots'),
9589
array('id' => 'search_course_integration'));
9690

9791
$coursesearchform .= html_writer::label(get_string('ced', 'turnitintooltwo').': ', 'search_course_end_date');
@@ -127,12 +121,12 @@
127121
$output .= $OUTPUT->box($categoryselectlabel." ".$categoryselect.$createassign.$createbutton, 'create_checkboxes navbar');
128122

129123
$table = new html_table();
130-
$table->id = "courseBrowserTable";
124+
$table->id = "mod_turnitintooltwo_course_browser_table";
131125
$rows = array();
132126

133127
// Make up json array for drop down in table.
134128
$integrationidsjson = array();
135-
foreach ($tiiintegrationids as $k => $v) {
129+
foreach (turnitintooltwo_get_integration_ids() as $k => $v) {
136130
$integrationidsjson[] = array('value' => $k, 'label' => $v);
137131
}
138132
$output .= html_writer::script('var integration_ids = '.json_encode($integrationidsjson));

gulpfile.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var gulp = require('gulp');
22
var sass = require('gulp-sass');
33

4-
var minifyCss = require('gulp-minify-css');
4+
var minifyCss = require('gulp-clean-css');
55
var sourcemaps = require('gulp-sourcemaps');
66
var notify = require('gulp-notify');
77
var uglify = require('gulp-uglify');
@@ -30,8 +30,8 @@ gulp.task('jsmin', function() {
3030
});
3131

3232
gulp.task('watch', function() {
33-
gulp.watch('./sass/**/*.scss', ['sass']);
34-
gulp.watch('./jquery/turnitintooltwo*.js', ['jsmin']);
33+
gulp.watch('./sass/**/*.scss', gulp.series('sass'));
34+
gulp.watch('./jquery/turnitintooltwo*.js', gulp.series('jsmin'));
3535
});
3636

37-
gulp.task('default', ['sass', 'jsmin', 'watch']);
37+
gulp.task('default', gulp.series(['sass', 'jsmin', 'watch']));

jquery/plugins.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
$plugins = array(
2020
'turnitintooltwo-dataTables' => array('files' => array('jquery.dataTables.js', 'jquery.dataTables.css')),
2121
'turnitintooltwo-dataTables_plugins' => array('files' => array('jquery.dataTables.plugins.js')),
22-
'turnitintooltwo-turnitintooltwo' => array('files' => array('turnitintooltwo-2018102601.min.js')),
23-
'turnitintooltwo-turnitintooltwo_extra' => array('files' => array('turnitintooltwo_extra-2018102601.min.js')),
24-
'turnitintooltwo-turnitintooltwo_settings' => array('files' => array('turnitintooltwo_settings-2018102601.min.js')),
22+
'turnitintooltwo-turnitintooltwo' => array('files' => array('turnitintooltwo-2020111101.min.js')),
23+
'turnitintooltwo-turnitintooltwo_extra' => array('files' => array('turnitintooltwo_extra-2020111101.min.js')),
24+
'turnitintooltwo-turnitintooltwo_settings' => array('files' => array('turnitintooltwo_settings-2020111101.min.js')),
2525
'turnitintooltwo-datatables_columnfilter' => array('files' => array('jquery.dataTables.columnFilter.js')),
2626
'turnitintooltwo-cookie' => array('files' => array('jquery.cookie.js')),
2727
'turnitintooltwo-colorbox' => array('files' => array('jquery.colorbox.js', 'colorbox.css')),

jquery/turnitintooltwo-2018102601.min.js

-3
This file was deleted.

0 commit comments

Comments
 (0)