Skip to content

Commit fe306ca

Browse files
committed
Allow Canvas to set IMathAS due dates
Squashed commit of the following: commit 761435fa5e03d21835f331177372a3409c65b2cd Merge: 213b1fcf d196961 Author: drlippman <drlippman@yahoo.com> Date: Fri Mar 9 16:50:19 2018 -0800 Merge branch 'master' into feature.set_duedates_by_lti # Conflicts: # course/addassessment.php # includes/calendardata.php # includes/calendardisp.php # includes/copyiteminc.php # includes/loaditemshowdata.php commit 213b1fcfc63263f01555e9bf3aaa0eb59aedc62f Author: drlippman <drlippman@yahoo.com> Date: Thu Mar 8 22:46:28 2018 -0800 Add latepass note to manage exceptions page commit 1a6411d49417730566ffa533a3ebedbfc90a9cd7 Author: drlippman <drlippman@yahoo.com> Date: Thu Mar 8 21:50:50 2018 -0800 Bug fix latepass after due date not working commit 199b82b7252abfd74e6bd1fff14cadf1f3d91b56 Merge: e18653b2 c37c3b95 Author: drlippman <drlippman@yahoo.com> Date: Thu Mar 8 19:59:22 2018 -0800 Merge branch 'feature.set_duedates_by_lti' of github.com:drlippman/IMathAS into feature.set_duedates_by_lti commit e18653b227205a5982d192a609b631b03e31b57f Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 15:08:07 2018 -0800 Add necessary database migration commit d3145efa136a893e8274332b2e094662e8033782 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 11:17:48 2018 -0800 typo fix commit 5c6a89536c753d288363b8bb565f85cfbdc73724 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 11:09:40 2018 -0800 Add pseudo-exceptions for instructor LTI launches with different due date Try to not confuse the teacher by showing the LMS-reported launch date, though there may be some cases where this gets confusing too. commit 2c792c6e73aa0b27431242c40625eebb75e10d00 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 10:32:10 2018 -0800 Adjust handling to distinguish instructor-set date from student-set For teachers, Canvas sends the due date of the first due date rule, which will be a single student's custom due date if one is set. To handle this, instructor launches will change the existing default due date in OHM, but only until a student launches. At that point, the student launch due date will be used, and the due date will become fixed. Later instructor launches won't change the default due date. commit 261cd9314bffa28ff720e7c8e3120cd6d4ea0b96 Author: drlippman <drlippman@yahoo.com> Date: Sat Feb 3 14:56:51 2018 -0800 Change model to not use avail=0 Hide assessments with date_by_lti=1 from GB, calendar commit df9f6586c511dc4ed9cf495409bc7a5a8e81d0e8 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 18:13:07 2018 -0800 Bug fixes. Hide Redeem LatePass link if enddate=always commit dec6613c263239ca0167aa2dbd1d4d30c0516267 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 18:01:46 2018 -0800 clear is_lti exceptiosn when course setting disabled commit 5f008f6de02ae27f277e13f0893ef84497862162 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 17:54:40 2018 -0800 Adjust ccexport for date_by_lti commit 215b48ebc7f77aa078bc761a670d42d09017ab85 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 12:49:51 2018 -0800 More work on dates by lti commit 35308daf82b6fceb98073ae66dc1206a20d2c07d Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 10:55:31 2018 -0800 Initial work on setting due dates by LTI commit c37c3b954877741325011c6cc6f8e4ccb50f4b0a Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 15:08:07 2018 -0800 Add necessary database migration commit c5db2fa1d5ccde2032b0faf7c40fc9f771f10f68 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 11:17:48 2018 -0800 typo fix commit 443500cb1f0e274e7db8a8f8e0b734d508b41467 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 11:09:40 2018 -0800 Add pseudo-exceptions for instructor LTI launches with different due date Try to not confuse the teacher by showing the LMS-reported launch date, though there may be some cases where this gets confusing too. commit 92bb67129b1c0da1912dfa1267115d42e963b143 Author: drlippman <drlippman@yahoo.com> Date: Sun Feb 4 10:32:10 2018 -0800 Adjust handling to distinguish instructor-set date from student-set For teachers, Canvas sends the due date of the first due date rule, which will be a single student's custom due date if one is set. To handle this, instructor launches will change the existing default due date in OHM, but only until a student launches. At that point, the student launch due date will be used, and the due date will become fixed. Later instructor launches won't change the default due date. commit 835175070fc0b312ef8131435ce0cda04c870969 Merge: 50731b1c e4ee0651 Author: drlippman <drlippman@yahoo.com> Date: Sat Feb 3 14:57:51 2018 -0800 Merge branch 'experiment.un_lti_on_homepage' into feature.set_duedates_by_lti commit 50731b1c62fea2986f3e77222ee978f239dd55ef Author: drlippman <drlippman@yahoo.com> Date: Sat Feb 3 14:56:51 2018 -0800 Change model to not use avail=0 Hide assessments with date_by_lti=1 from GB, calendar commit 6f7dbfcfcaccf4ce3e6725b1c154b9e28a281004 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 18:13:07 2018 -0800 Bug fixes. Hide Redeem LatePass link if enddate=always commit d956d65502fc514d1481781093c5622f2c625127 Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 18:01:46 2018 -0800 clear is_lti exceptiosn when course setting disabled commit 54679f71650cec7f54a4d49a496aea305a3372fb Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 17:54:40 2018 -0800 Adjust ccexport for date_by_lti commit 676781b16815e2e0ada54c4d6f05b3713579839d Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 12:49:51 2018 -0800 More work on dates by lti commit fc2549b654380a943306fb74566faab0b2ee649b Author: drlippman <drlippman@yahoo.com> Date: Fri Feb 2 10:55:31 2018 -0800 Initial work on setting due dates by LTI commit e4ee0651b3dbc8df6d40c780304adb9868aa7a50 Author: drlippman <drlippman@yahoo.com> Date: Fri Jan 5 17:18:58 2018 -0800 For teachers, move user out of LTI mode if they visit the homepage
1 parent d196961 commit fe306ca

19 files changed

Lines changed: 319 additions & 74 deletions

admin/actions.php

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,17 +537,22 @@
537537
}
538538

539539
$_POST['ltisecret'] = trim($_POST['ltisecret']);
540+
if (isset($_POST['setdatesbylti']) && $_POST['setdatesbylti']==1) {
541+
$setdatesbylti = 1;
542+
} else {
543+
$setdatesbylti = 0;
544+
}
540545

541546
if ($_POST['action']=='modify') {
542547
$query = "UPDATE imas_courses SET name=:name,enrollkey=:enrollkey,hideicons=:hideicons,available=:available,lockaid=:lockaid,picicons=:picicons,showlatepass=:showlatepass,";
543548
if ($updateJsonData) {
544549
$query .= "jsondata=:jsondata,";
545550
}
546-
$query .= "allowunenroll=:allowunenroll,copyrights=:copyrights,msgset=:msgset,toolset=:toolset,theme=:theme,ltisecret=:ltisecret,istemplate=:istemplate,deftime=:deftime,deflatepass=:deflatepass WHERE id=:id";
551+
$query .= "allowunenroll=:allowunenroll,copyrights=:copyrights,msgset=:msgset,toolset=:toolset,theme=:theme,ltisecret=:ltisecret,istemplate=:istemplate,deftime=:deftime,deflatepass=:deflatepass,dates_by_lti=:ltidates WHERE id=:id";
547552
$qarr = array(':name'=>$_POST['coursename'], ':enrollkey'=>$_POST['ekey'], ':hideicons'=>$hideicons, ':available'=>$avail, ':lockaid'=>$_POST['lockaid'],
548553
':picicons'=>$picicons, ':showlatepass'=>$showlatepass, ':allowunenroll'=>$unenroll, ':copyrights'=>$copyrights, ':msgset'=>$msgset,
549554
':toolset'=>$toolset, ':theme'=>$theme, ':ltisecret'=>$_POST['ltisecret'], ':istemplate'=>$istemplate,
550-
':deftime'=>$deftime, ':deflatepass'=>$deflatepass, ':id'=>$_GET['id']);
555+
':deftime'=>$deftime, ':deflatepass'=>$deflatepass, ':ltidates'=>$setdatesbylti, ':id'=>$_GET['id']);
551556
if ($myrights<75) {
552557
$query .= " AND ownerid=:ownerid";
553558
$qarr[':ownerid']=$userid;
@@ -557,17 +562,40 @@
557562
}
558563
$stm = $DBH->prepare($query);
559564
$stm->execute($qarr);
565+
if ($stm->rowCount()>0) {
566+
if ($setdatesbylti==1) {
567+
$stm = $DBH->prepare("UPDATE imas_assessments SET date_by_lti=1 WHERE date_by_lti=0 AND courseid=:cid");
568+
$stm->execute(array(':cid'=>$_GET['id']));
569+
} else {
570+
//undo it - doesn't restore dates
571+
$stm = $DBH->prepare("UPDATE imas_assessments SET date_by_lti=0 WHERE date_by_lti>0 AND courseid=:cid");
572+
$stm->execute(array(':cid'=>$_GET['id']));
573+
//remove is_lti from exceptions with latepasses
574+
$query = "UPDATE imas_exceptions JOIN imas_assessments ";
575+
$query .= "ON imas_exceptions.assessmentid=imas_assessments.id ";
576+
$query .= "SET imas_exceptions.is_lti=0 ";
577+
$query .= "WHERE imas_exceptions.is_lti>0 AND imas_exceptions.islatepass>0 AND imas_assessments.courseid=:cid";
578+
$stm = $DBH->prepare($query);
579+
$stm->execute(array(':cid'=>$_GET['id']));
580+
//delete any other is_lti exceptions
581+
$query = "DELETE imas_exceptions FROM imas_exceptions JOIN imas_assessments ";
582+
$query .= "ON imas_exceptions.assessmentid=imas_assessments.id ";
583+
$query .= "WHERE imas_exceptions.is_lti>0 AND imas_exceptions.islatepass=0 AND imas_assessments.courseid=:cid";
584+
$stm = $DBH->prepare($query);
585+
$stm->execute(array(':cid'=>$_GET['id']));
586+
}
587+
}
560588
} else {
561589
$blockcnt = 1;
562590
$itemorder = serialize(array());
563591
$DBH->beginTransaction();
564-
$query = "INSERT INTO imas_courses (name,ownerid,enrollkey,hideicons,picicons,allowunenroll,copyrights,msgset,toolset,showlatepass,itemorder,available,istemplate,deftime,deflatepass,theme,ltisecret,blockcnt) VALUES ";
565-
$query .= "(:name, :ownerid, :enrollkey, :hideicons, :picicons, :allowunenroll, :copyrights, :msgset, :toolset, :showlatepass, :itemorder, :available, :istemplate, :deftime, :deflatepass, :theme, :ltisecret, :blockcnt);";
592+
$query = "INSERT INTO imas_courses (name,ownerid,enrollkey,hideicons,picicons,allowunenroll,copyrights,msgset,toolset,showlatepass,itemorder,available,istemplate,deftime,deflatepass,theme,ltisecret,dates_by_lti,blockcnt) VALUES ";
593+
$query .= "(:name, :ownerid, :enrollkey, :hideicons, :picicons, :allowunenroll, :copyrights, :msgset, :toolset, :showlatepass, :itemorder, :available, :istemplate, :deftime, :deflatepass, :theme, :ltisecret, :ltidates, :blockcnt);";
566594
$stm = $DBH->prepare($query);
567595
$stm->execute(array(':name'=>$_POST['coursename'], ':ownerid'=>$userid, ':enrollkey'=>$_POST['ekey'], ':hideicons'=>$hideicons, ':picicons'=>$picicons,
568596
':allowunenroll'=>$unenroll, ':copyrights'=>$copyrights, ':msgset'=>$msgset, ':toolset'=>$toolset, ':showlatepass'=>$showlatepass,
569597
':itemorder'=>$itemorder, ':available'=>$avail, ':istemplate'=>$istemplate, ':deftime'=>$deftime,
570-
':deflatepass'=>$deflatepass, ':theme'=>$theme, ':ltisecret'=>$_POST['ltisecret'], ':blockcnt'=>$blockcnt));
598+
':deflatepass'=>$deflatepass, ':theme'=>$theme, ':ltisecret'=>$_POST['ltisecret'], ':ltidates'=>$setdatesbylti, ':blockcnt'=>$blockcnt));
571599
$cid = $DBH->lastInsertId();
572600
//if ($myrights==40) {
573601
$stm = $DBH->prepare("INSERT INTO imas_teachers (userid,courseid) VALUES (:userid, :courseid)");
@@ -700,6 +728,10 @@ function updateoutcomes(&$arr) {
700728
copyrubrics();
701729

702730
}
731+
if ($setdatesbylti==1) {
732+
$stm = $DBH->prepare("UPDATE imas_assessments SET date_by_lti=1 WHERE date_by_lti=0 AND courseid=:cid");
733+
$stm->execute(array(':cid'=>$cid));
734+
}
703735
$DBH->commit();
704736

705737
require("../header.php");

admin/ccexport.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ function getorg($it,$parent,&$res,$ind) {
409409
if ($linktype=='canvas') {
410410
$canvout .= '<item identifier="'.$iteminfo[$item][0].$iteminfo[$item][1].'">'."\n";
411411
$canvout .= '<content_type>Assignment</content_type>'."\n";
412-
$canvout .= '<workflow_state>'.($row[6]==0?'unpublished':'active').'</workflow_state>'."\n";
412+
$canvout .= '<workflow_state>'.(row[6]==0?'unpublished':'active').'</workflow_state>'."\n";
413413
$canvout .= '<identifierref>RES'.$iteminfo[$item][0].$iteminfo[$item][1].'</identifierref>'."\n";
414414
$canvout .= '<title>'.htmlentities($row[0],ENT_XML1,'UTF-8',false).'</title>'."\n";
415415
$canvout .= "<position>$ccnt</position> <indent>".max(strlen($ind)/2 - 2, 0)."</indent> </item>";
@@ -439,7 +439,7 @@ function getorg($it,$parent,&$res,$ind) {
439439
fwrite($fp,'<workflow_state>'.($row[6]==0?'unpublished':'published').'</workflow_state>'."\n");
440440
fwrite($fp,'<points_possible>'.$row[8].'</points_possible>'."\n");
441441
fwrite($fp,'<grading_type>points</grading_type>'."\n");
442-
if (isset($_POST['includeduedates'])) {
442+
if (isset($_POST['includeduedates']) && $row[4]<2000000000) {
443443
fwrite($fp,'<due_at>'.gmdate("Y-m-d\TH:i:s", $row[4]).'</due_at>'."\n");
444444
}
445445
if ($row[7] > 0 && isset($_POST['includestartdates'])) {

admin/forms.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ function checkgroupisnew() {
296296
$deflatepass = $line['deflatepass'];
297297
$deftime = $line['deftime'];
298298
$jsondata = json_decode($line['jsondata'], true);
299+
$dates_by_lti = $line['dates_by_lti'];
299300
if ($jsondata===null || !isset($jsondata['browser'])) {
300301
$browser = array();
301302
} else {
@@ -325,6 +326,7 @@ function checkgroupisnew() {
325326
$deflatepass = isset($CFG['CPS']['deflatepass'])?$CFG['CPS']['deflatepass'][0]:0;
326327
$ltisecret = "";
327328
$browser = array();
329+
$dates_by_lti = 0;
328330
}
329331
$defetime = $deftime%10000;
330332
$hr = floor($defetime/60)%12;
@@ -545,6 +547,11 @@ function checkgroupisnew() {
545547
echo 'Course ID not yet set.';
546548
}
547549
echo '</span></span><br class="form" />';
550+
echo '<span class="form">Allow the LMS to set assessment due dates?<br/><span class="small">(Only supported by Canvas)</span></span>';
551+
echo '<span class="formright"><input type="checkbox" name="setdatesbylti" value="1" ';
552+
if ($dates_by_lti>0) { echo 'checked="checked"';}
553+
echo '/> </span><br class="form" />';
554+
548555
}
549556

550557
if (($myspecialrights&1)==1 || ($myspecialrights&2)==2 || $myrights==100) {

assessment/showtest.php

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,17 @@
7575

7676
if (!$actas) {
7777
if ($isRealStudent) {
78-
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
78+
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass,is_lti FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
7979
$stm2->execute(array(':userid'=>$userid, ':assessmentid'=>$aid));
8080
$row = $stm2->fetch(PDO::FETCH_NUM);
8181
if ($row!=null) {
8282
$useexception = $exceptionfuncs->getCanUseAssessException($row, $adata, true);
8383
}
84+
} else if (isset($_SESSION['lti_duedate']) && (isset($teacherid) || isset($tutorid)) && $_SESSION['lti_duedate']!=$adata['enddate']) {
85+
//teacher launch with lti duedate that's different than default
86+
//do a pseudo-exception
87+
$useexception = true;
88+
$row = array(0, $_SESSION['lti_duedate'], 0, 1);
8489
}
8590
if ($row!=null && $useexception) {
8691
if ($now<$row[0] || $row[1]<$now) { //outside exception dates
@@ -92,8 +97,8 @@
9297
}
9398
}
9499
} else { //inside exception dates exception
95-
if ($adata['enddate']<$now) { //exception is for past-due-date
96-
$inexception = true; //only trigger if past due date for penalty
100+
if ($adata['enddate']<$now && ($row[3]==0 || $row[2]>0)) { //exception is for past-due-date
101+
$inexception = true; //only trigger if past due date for penalty (and not a regular lti-set exception)
97102
}
98103
}
99104
$exceptionduedate = $row[1];
@@ -674,15 +679,23 @@
674679
leavetestmsg();
675680
exit;
676681
}
682+
$ltiexception = false;
677683
if (!$actas) {
678684
//DB $query = "SELECT startdate,enddate,islatepass,exceptionpenalty FROM imas_exceptions WHERE userid='$userid' AND assessmentid='{$line['assessmentid']}' AND itemtype='A'";
679685
//DB $result2 = mysql_query($query) or die("Query failed : " . mysql_error());
680686
//DB $row = mysql_fetch_row($result2);
681-
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass,exceptionpenalty FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
687+
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass,is_lti,exceptionpenalty FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
682688
$stm2->execute(array(':userid'=>$userid, ':assessmentid'=>$line['assessmentid']));
683689
$exceptionrow = $stm2->fetch(PDO::FETCH_NUM);
684690
if ($exceptionrow != null) {
685691
$useexception = $exceptionfuncs->getCanUseAssessException($exceptionrow, $testsettings, true);
692+
$ltiexception = ($row[3]>0 && $row[2]==0);
693+
} else if (isset($_SESSION['lti_duedate']) && $isteacher && $_SESSION['lti_duedate']!=$testsettings['enddate']) {
694+
//teacher launch with lti duedate that's different than default
695+
//do a pseudo-exception
696+
$useexception = true;
697+
$ltiexception = true;
698+
$exceptionrow = array(0, $_SESSION['lti_duedate'], 0, 1);
686699
}
687700
if ($exceptionrow!=null && $useexception) {
688701
if ($now<$exceptionrow[0] || $exceptionrow[1]<$now) { //outside exception dates
@@ -696,11 +709,11 @@
696709
}
697710
}
698711
} else { //in exception
699-
if ($testsettings['enddate']<$now) { //exception is for past-due-date
712+
if ($testsettings['enddate']<$now && ($row[3]==0 || $row[2]>0)) { //exception is for past-due-date
700713
$inexception = true;
701714
$exceptiontype = $exceptionrow[2];
702-
if ($exceptionrow[3]!==null) {
703-
$testsettings['exceptionpenalty'] = $exceptionrow[3];
715+
if ($exceptionrow[4]!==null) {
716+
$testsettings['exceptionpenalty'] = $exceptionrow[4];
704717
}
705718
}
706719
}
@@ -722,14 +735,15 @@
722735
//DB $query = "SELECT startdate,enddate FROM imas_exceptions WHERE userid='{$sessiondata['actas']}' AND assessmentid='{$line['assessmentid']}' AND itemtype='A'";
723736
//DB $result2 = mysql_query($query) or die("Query failed : " . mysql_error());
724737
//DB $row = mysql_fetch_row($result2);
725-
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
738+
$stm2 = $DBH->prepare("SELECT startdate,enddate,islatepass,is_lti FROM imas_exceptions WHERE userid=:userid AND assessmentid=:assessmentid AND itemtype='A'");
726739
$stm2->execute(array(':userid'=>$sessiondata['actas'], ':assessmentid'=>$line['assessmentid']));
727740
$row = $stm2->fetch(PDO::FETCH_NUM);
728741
if ($row!=null) {
729742
$useexception = $exceptionfuncs->getCanUseAssessException($row, $testsettings, true);
730743
if ($useexception) {
731744
$exceptionduedate = $row[1];
732745
}
746+
$ltiexception = ($row[3]>0 && $row[2]==0);
733747
}
734748
}
735749

@@ -1467,7 +1481,7 @@
14671481
$duetimenote = '';
14681482
if ($exceptionduedate > 0) {
14691483
$timebeforedue = $exceptionduedate - time();
1470-
if ($timebeforedue>0 && ($testsettings['enddate'] - time()) < 0) { //past original due date
1484+
if ($timebeforedue>0 && ($testsettings['enddate'] - time()) < 0 && !$ltiexception) { //past original due date
14711485
$duetimenote .= sprintf(_('This assignment is past the original due date of %s.'), tzdate('D m/d/Y g:i a',$testsettings['enddate'])).' ';
14721486
if ($exceptiontype>0) {
14731487
$duetimenote .= _('You have used a LatePass');
@@ -1502,10 +1516,12 @@
15021516
$duetimenote .= _('Due') . " " . tzdate('D m/d/Y g:i a',$testsettings['enddate']);
15031517
}
15041518
} else {
1505-
if ($testsettings['enddate']==2000000000) {
1519+
if ($exceptionduedate > 0) {
1520+
if ($exceptionduedate < 2000000000) {
1521+
$duetimenote .= _('Due') . " " . tzdate('D m/d/Y g:i a',$exceptionduedate);
1522+
}
1523+
} else if ($testsettings['enddate']==2000000000) {
15061524
$duetimenote .= '';
1507-
} else if ($exceptionduedate > 0) {
1508-
$duetimenote .= _('Due') . " " . tzdate('D m/d/Y g:i a',$exceptionduedate);
15091525
} else {
15101526
$duetimenote .= _('Due') . " " . tzdate('D m/d/Y g:i a',$testsettings['enddate']);
15111527
}

0 commit comments

Comments
 (0)