[LON-CAPA-cvs] cvs: loncom / lond /enrollment Autoenroll.pl localenroll.pm /interface coursecatalog.pm loncommon.pm loncoursequeueadmin.pm lonmodifycourse.pm lonpopulate.pm selfenroll.pm /lonnet/perl lonnet.pm

raeburn raeburn at source.lon-capa.org
Tue Jun 15 16:52:28 EDT 2021


raeburn		Tue Jun 15 20:52:28 2021 EDT

  Modified files:              
    /loncom/interface	coursecatalog.pm loncommon.pm 
                     	loncoursequeueadmin.pm lonmodifycourse.pm 
                     	lonpopulate.pm selfenroll.pm 
    /loncom	lond 
    /loncom/enrollment	Autoenroll.pl localenroll.pm 
    /loncom/lonnet/perl	lonnet.pm 
  Log:
  - Support customization in localenroll.pm to eliminate ambiguity in extraction
    of institutional section from institutional course section for automated 
    enrollment.
  
  
-------------- next part --------------
Index: loncom/interface/coursecatalog.pm
diff -u loncom/interface/coursecatalog.pm:1.104 loncom/interface/coursecatalog.pm:1.105
--- loncom/interface/coursecatalog.pm:1.104	Fri Apr 30 18:19:41 2021
+++ loncom/interface/coursecatalog.pm	Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler for displaying the course catalog interface
 #
-# $Id: coursecatalog.pm,v 1.104 2021/04/30 18:19:41 raeburn Exp $
+# $Id: coursecatalog.pm,v 1.105 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1511,6 +1511,25 @@
     }
     my $count = 1;
     my $totalsec = 0;
+    my %clutteredxlists;
+    foreach my $course (keys(%courseinfo)) {
+        if (ref($courseinfo{$course}) eq 'HASH') {
+            if ($courseinfo{$course}{'xlist'} ne '') {
+                my $crskey = $courseinfo{$course}{'cnum'}.':'.$courseinfo{$course}{'code'};
+                my @xlists = split(/,\s/,$courseinfo{$course}{'xlist'});
+                $clutteredxlists{$crskey} = \@xlists;
+            }
+        }
+    }
+    if (keys(%clutteredxlists)) {
+        my %reformattedxlists = &Apache::lonnet::auto_instsec_reformat($domain,'declutter',\%clutteredxlists);
+        foreach my $crskey (keys(%reformattedxlists)) {
+            if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
+                my $course = $domain.'_'.(split(/:/,$crskey))[0];
+                $courseinfo{$course}{'xlist'} = join(', ',@{$reformattedxlists{$crskey}});
+            }
+        }
+    }
     foreach my $item (@sorted_courses) {
         foreach my $course (@{$Sortby{$item}}) {
             $output.=&Apache::loncommon::start_data_table_row(); 
@@ -1971,13 +1990,19 @@
 sub get_valid_classes {
     my ($seclist,$xlist_items,$crscode,$owners,$cdom,$cnum) = @_;
     my $response;
-    my (@sections, at xlists,%possclasses,%okclasses,%validations);
+    my (@sections, at format_sections, at xlists,%possclasses,%okclasses,%validations);
     @{$validations{'sections'}} = ();
     @{$validations{'xlists'}} = ();
     my $totalitems = 0;
     if ($seclist) {
         @sections = split(/,\s+/,$seclist);
-        map { $possclasses{$crscode.$_} = 1; } @sections;
+        my $crskey = $cnum.':'.$crscode;
+        my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',
+                                                                  {$crskey => \@sections});
+        if (ref($formattedsec{$crskey}) eq 'ARRAY') {
+            @format_sections = @{$formattedsec{$crskey}};
+            map { $possclasses{$crscode.$_} = 1; } @format_sections;
+        }
     }
     if ($xlist_items) {
         @xlists = split(/,\s+/,$xlist_items);
@@ -1986,9 +2011,10 @@
     my %okclasses = &Apache::lonnet::auto_validate_instclasses($cdom,$cnum,$owners,
                                                                \%possclasses);
     if (keys(%okclasses)) {
-        foreach my $sec (@sections) {
-            if ($okclasses{$crscode.$sec}) {
-                if (!grep(/^\Q$sec$\E/,@{$validations{'sections'}})) {
+        for (my $i=0; $i<@sections; $i++) {
+            if ($okclasses{$crscode.$format_sections[$i]}) {
+                my $sec = $sections[$i];
+                if (!grep(/^\Q$sec\E$/,@{$validations{'sections'}})) {
                     push(@{$validations{'sections'}},$sec);
                     $totalitems ++;
                 }
@@ -2009,6 +2035,13 @@
                         join(', ',@{$validations{'sections'}}).'<br />';
         }
         if (@{$validations{'xlists'}}) {
+            my $crskey = $cnum.':'.$crscode;
+            my %reformattedxlists =
+                &Apache::lonnet::auto_instsec_reformat($cdom,'declutter',
+                                                       {$crskey => $validations{'xlists'}});
+            if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
+                $validations{'xlists'} = $reformattedxlists{$crskey};
+            }
             $response .= &mt('Courses:').' '.
                         join(', ',@{$validations{'xlists'}});
         }
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1360 loncom/interface/loncommon.pm:1.1361
--- loncom/interface/loncommon.pm:1.1360	Sat Jun 12 20:51:38 2021
+++ loncom/interface/loncommon.pm	Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1360 2021/06/12 20:51:38 raeburn Exp $
+# $Id: loncommon.pm,v 1.1361 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -11156,11 +11156,15 @@
 }
 
 sub get_institutional_codes {
-    my ($settings,$allcourses,$LC_code) = @_;
+    my ($cdom,$crs,$settings,$allcourses,$LC_code) = @_;
 # Get complete list of course sections to update
     my @currsections = ();
     my @currxlists = ();
+    my (%unclutteredsec,%unclutteredlcsec);
     my $coursecode = $$settings{'internal.coursecode'};
+    my $crskey = $crs.':'.$coursecode;
+    @{$unclutteredsec{$crskey}} = ();
+    @{$unclutteredlcsec{$crskey}} = ();
 
     if ($$settings{'internal.sectionnums'} ne '') {
         @currsections = split(/,/,$$settings{'internal.sectionnums'});
@@ -11171,8 +11175,8 @@
     }
 
     if (@currxlists > 0) {
-        foreach (@currxlists) {
-            if (m/^([^:]+):(\w*)$/) {
+        foreach my $xl (@currxlists) {
+            if ($xl =~ /^([^:]+):(\w*)$/) {
                 unless (grep/^$1$/,@{$allcourses}) {
                     push(@{$allcourses},$1);
                     $$LC_code{$1} = $2;
@@ -11180,15 +11184,28 @@
             }
         }
     }
- 
+
     if (@currsections > 0) {
-        foreach (@currsections) {
-            if (m/^(\w+):(\w*)$/) {
-                my $sec = $coursecode.$1;
+        foreach my $sec (@currsections) {
+            if ($sec =~ m/^(\w+):(\w*)$/ ) {
+                my $instsec = $1;
                 my $lc_sec = $2;
-                unless (grep/^$sec$/,@{$allcourses}) {
+                unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {
+                    push(@{$unclutteredsec{$crskey}},$instsec);
+                    push(@{$unclutteredlcsec{$crskey}},$lc_sec);
+                }
+            }
+        }
+    }
+
+    if (@{$unclutteredsec{$crskey}} > 0) {
+        my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',\%unclutteredsec);
+        if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {
+            for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {
+                my $sec = $coursecode.$formattedsec{$crskey}[$i];
+                unless (grep/^\Q$sec\E$/,@{$allcourses}) {
                     push(@{$allcourses},$sec);
-                    $$LC_code{$sec} = $lc_sec;
+                    $$LC_code{$sec} = $unclutteredlcsec{$crskey}[$i];
                 }
             }
         }
Index: loncom/interface/loncoursequeueadmin.pm
diff -u loncom/interface/loncoursequeueadmin.pm:1.60 loncom/interface/loncoursequeueadmin.pm:1.61
--- loncom/interface/loncoursequeueadmin.pm:1.60	Fri Aug 21 21:59:20 2020
+++ loncom/interface/loncoursequeueadmin.pm	Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Utilities to administer domain course requests and course self-enroll requests
 #
-# $Id: loncoursequeueadmin.pm,v 1.60 2020/08/21 21:59:20 raeburn Exp $
+# $Id: loncoursequeueadmin.pm,v 1.61 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1647,7 +1647,7 @@
         $owneremail = $emails{$email};
         last if ($owneremail ne '');
     }
-    my %reqdetails = &build_batchcreatehash($dom,$context,$details,$owneremail,$domdefs);
+    my %reqdetails = &build_batchcreatehash($dom,$cnum,$context,$details,$owneremail,$domdefs);
     my $cid = &LONCAPA::batchcreatecourse::build_course($dom,$cnum,'requestcourses',
                   \%reqdetails,$longroles,$logmsg,$clonemsg,$newusermsg,$addresult,
                   $enrollcount,$output,$keysmsg,$ownerdom,$ownername,$cnum,$crstype,
@@ -1669,7 +1669,7 @@
 }
 
 sub build_batchcreatehash {
-    my ($dom,$context,$details,$owneremail,$domdefs) = @_;
+    my ($dom,$cnum,$context,$details,$owneremail,$domdefs) = @_;
     my %batchhash;
     my @items = qw{owner domain coursehome clonecrs clonedom datemode dateshift tinyurls enrollstart enrollend accessstart accessend sections users uniquecode};
     if ((ref($details) eq 'HASH') && (ref($domdefs) eq 'HASH')) {
@@ -1681,7 +1681,14 @@
         if (ref($details->{'crosslists'}) eq 'HASH') {
             foreach my $key (keys(%{$details->{'crosslists'}})) {
                 if (ref($details->{'crosslists'}->{$key}) eq 'HASH') {
-                    $batchhash{'crosslists'}{$key}{'inst'} = $details->{crosslists}->{$key}->{instcode}.$details->{crosslists}->{$key}->{instsec};
+                    my $instsec = $details->{crosslists}->{$key}->{instsec};
+                    $batchhash{'crosslists'}{$key}{'inst'} = $details->{crosslists}->{$key}->{instcode};
+                    my $crskey = $cnum.':'.$batchhash{'crosslists'}{$key}{'inst'};
+                    my %formatted = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',
+                                                                           {$crskey => [$instsec]});
+                    if (ref($formatted{$crskey}) eq 'ARRAY') {
+                        $batchhash{'crosslists'}{$key}{'inst'} .= $formatted{$crskey}->[0];
+                    }
                     $batchhash{'crosslists'}{$key}{'loncapa'} = $details->{crosslists}->{$key}->{loncapa};
                 }
             }
Index: loncom/interface/lonmodifycourse.pm
diff -u loncom/interface/lonmodifycourse.pm:1.95 loncom/interface/lonmodifycourse.pm:1.96
--- loncom/interface/lonmodifycourse.pm:1.95	Thu Jul 25 20:23:52 2019
+++ loncom/interface/lonmodifycourse.pm	Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # handler for DC-only modifiable course settings
 #
-# $Id: lonmodifycourse.pm,v 1.95 2019/07/25 20:23:52 raeburn Exp $
+# $Id: lonmodifycourse.pm,v 1.96 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -684,9 +684,34 @@
                      "<th>$lt{'dcon'}</th>\n".
                      &Apache::loncommon::end_data_table_header_row()."\n";
     foreach my $item (@items) {
+        my $shown = $enrollvar{$item};
+        if ($item eq 'crosslistings') {
+            my (@xlists, at lcsecs);
+            foreach my $entry (split(/,/,$enrollvar{$item})) {
+                my ($xlist,$lc_sec) = split(/:/,$entry);
+                push(@xlists,$xlist);
+                push(@lcsecs,$lc_sec);
+            }
+            if (@xlists) {
+                my $crskey = $cnum.':'.$enrollvar{'coursecode'};
+                my %reformatted =
+                    &Apache::lonnet::auto_instsec_reformat($cdom,'declutter',
+                                                           {$crskey => \@xlists});
+                if (ref($reformatted{$crskey}) eq 'ARRAY') {
+                    my @show;
+                    my @xlcodes = @{$reformatted{$crskey}};
+                    for (my $i=0; $i<@xlcodes; $i++) {
+                        push(@show,$xlcodes[$i].':'.$lcsecs[$i]);
+                    }
+                    if (@show) {
+                        $shown = join(',', at show);
+                    }
+                }
+            }
+        }
         $disp_table .= &Apache::loncommon::start_data_table_row()."\n".
                        "<td><b>$longtype{$item}</b></td>\n".
-                       "<td>$enrollvar{$item}</td>\n";
+                       "<td>$shown</td>\n";
         if (grep(/^\Q$item\E$/, at modifiable_params)) {
             $disp_table .= '<td align="right">'.&mt('Yes').'</td>'."\n";
         } else {
Index: loncom/interface/lonpopulate.pm
diff -u loncom/interface/lonpopulate.pm:1.86 loncom/interface/lonpopulate.pm:1.87
--- loncom/interface/lonpopulate.pm:1.86	Wed Mar 31 02:19:59 2021
+++ loncom/interface/lonpopulate.pm	Tue Jun 15 20:52:26 2021
@@ -1,5 +1,5 @@
 # automated enrollment configuration handler
-# $Id: lonpopulate.pm,v 1.86 2021/03/31 02:19:59 raeburn Exp $
+# $Id: lonpopulate.pm,v 1.87 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -37,6 +37,7 @@
 use Apache::Constants qw(:common :http REDIRECT);
 use Time::Local;
 use LONCAPA::Enrollment;
+use LONCAPA qw(:DEFAULT :match);
 
 ###############################################################
 sub header {
@@ -903,10 +904,12 @@
                  <th>'.&mt('LON-CAPA section ID').'</th>
           ');
           $r->print(&Apache::loncommon::end_data_table_row());
-          for (my $i=0; $i<@xlists; $i++) {
+          my @showable;
+          &reformat_xlists($dom,$crs,$enrollvar{'coursecode'},\@xlists,\@showable);
+          for (my $i=0; $i<@showable; $i++) {
               my $xl = ' ';
               my $lc_sec = ' ';
-              if ($xlists[$i] =~ /^([^:]+):?(.*)$/) {
+              if ($showable[$i] =~ /^([^:]+):?(.*)$/) {
                   $xl = $1;
                   $lc_sec = $2;
               }               
@@ -2063,8 +2066,10 @@
 	if ($crosscount > 0) {
 	    $response .= &mt('The [quant,_1,course] listed below remain crosslisted with this LON-CAPA course, and students enrolling in these course sections will be automatically added to the class roster for the course, if you have chosen to enable a nightly automated enrollment update.',$crosscount).
                          '<br /><ul>'."\n";
-	    foreach my $xl (@xlists) {
-		my ($xlist,$lc_sec) = split(/:/,$xl);
+            my @showable;
+            &reformat_xlists($dom,$crs,$coursecode,\@xlists,\@showable);
+            foreach my $item (@showable) {
+                my ($xlist,$lc_sec) = split(/:/,$item);
 		$response .= 
                     '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'."\n";
 	    }
@@ -2074,26 +2079,86 @@
     if ( exists($env{'form.numcross'}) ) {
 	my $numcross = $env{'form.numcross'};
 	if ($numcross) {
-	    $response .= 
-                &mt('You indicated that you wish to add an additional [quant,_1,crosslisting].',$numcross).' '.
-                &mt('For each new crosslisting enter the institutional course section code (e.g., fs03zol101001, for section 001 of zol101 for fs03 semester), and the LON-CAPA section ID you wish to assign to students who will be enrolled in your LON-CAPA class as a result of their registration in the crosslisted course section.').' '.
-                &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
-                &mt("The institutional course section code should only contain letters and/or numbers, and must be consistent with the scheme adopted by your Domain Coordinator to map course codes (and section numbers) to your institution's student information system.").
-                '<br /><br />
-           <form name="enter" method="post" action="">'.
-           &Apache::loncommon::start_data_table().
-           &Apache::loncommon::start_data_table_row().'
-                 <th>'.&mt('Crosslisting').'</th>
-                 <th>'.&mt('LON-CAPA section ID').'</th>'."\n".
-           &Apache::loncommon::end_data_table_row();
-	   for (my $i=0; $i<$numcross; $i++) {
-               $response .= 
-                   &Apache::loncommon::start_data_table_row().'
-                   <td><input type="text" size="15" name="newcross_'.$i.'" /></td>
-                    <td align="right"><input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+            my (@codetitles,%cat_titles,%cat_order, at code_order);
+            &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles,
+                                                     \%cat_order,\@code_order);       
+	    $response .=
+                &mt('You indicated that you wish to add an additional [quant,_1,crosslisting].',$numcross).' ';
+            if (@codetitles > 0) {
+                my $lastitem = pop(@codetitles);
+                $response .=
+                    &mt('For each new crosslisting select [_1], and enter the [_2] and the LON-CAPA section ID.',join(', ', at codetitles),$lastitem).' '.
+                    &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
+                    '<br /><br />'.
+                    '<form name="enter" method="post" action="">'."\n".
+                    &Apache::loncommon::start_data_table()."\n".
+                    &Apache::loncommon::start_data_table_header_row()."\n";
+                foreach my $title (@codetitles) {
+                    if (ref($cat_order{$title}) eq 'ARRAY') {
+                        if (@{$cat_order{$title}} > 0) {
+                            $response .= '<th>'.$title.'</th>';
+                        }
+                    }
+                }
+                $response .= '<th>'.$lastitem.'</th>'."\n".
+                             '<th>'.&mt('Institutional section').'</th>'."\n".
+                             '<th>'.&mt('LON-CAPA section').'</th>'."\n".
+                             &Apache::loncommon::end_data_table_header_row()."\n";
+                for (my $i=0; $i<$numcross; $i++) {
+                    $response .=
+                        &Apache::loncommon::start_data_table_row()."\n";
+                    foreach my $title (@codetitles) {
+                        if (ref($cat_order{$title}) eq 'ARRAY') {
+                            if (@{$cat_order{$title}} > 0) {
+                                $response .= '<td align="center">'.
+                                             '<select name="newcross_'.$i.'_'.$title.'">'."\n".
+                                             ' <option value="" selected="selected">'.
+                                             &mt('Select').'</option>'."\n";
+                                foreach my $item (@{$cat_order{$title}}) {
+                                    my $longitem = $item;
+                                    if (ref($cat_titles{$title}) eq 'HASH') {
+                                        if ($cat_titles{$title}{$item} ne '') {
+                                            $longitem = $cat_titles{$title}{$item};
+                                        }
+                                    }
+                                    $response .= '<option value="'.$item.'">'.$longitem.
+                                                 '</option>'."\n";
+                                }
+                                $response .= '</select></td>'."\n";
+                            }
+                        }
+                    }
+                    $response .= '<td align="center">'.
+                                 '<input type="text" size="5" name="newcross_'.$i.'_'.$lastitem.'" />'.
+                                 '</td>'."\n".'<td align="center">'.
+                                 '<input type="text" size="10" name="newcross_'.$i.'_instsec" />'.
+                                 '</td>'."\n".'<td align="center">'.
+                                 '<input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+                                 &Apache::loncommon::end_data_table_row()."\n";
+                }
+                $response .= &Apache::loncommon::end_data_table()."\n";
+            } else {
+                $response .=              
+                    &mt('For each new crosslisting enter the institutional course section code (e.g., fs03zol101001, for section 001 of zol101 for fs03 semester), and the LON-CAPA section ID you wish to assign to students who will be enrolled in your LON-CAPA class as a result of their registration in the crosslisted course section.').' '.
+                    &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
+                    &mt("The institutional course section code should only contain letters and/or numbers, and must be consistent with the scheme adopted by your Domain Coordinator to map course codes (and section numbers) to your institution's student information system.").
+                    '<br /><br />'.
+                    '<form name="enter" method="post" action="">'."\n".
+                    &Apache::loncommon::start_data_table()."\n".
+                    &Apache::loncommon::start_data_table_row()."\n".
+                    '<th>'.&mt('Crosslisting').'</th>'."\n".
+                    '<th>'.&mt('LON-CAPA section ID').'</th>'."\n".
                     &Apache::loncommon::end_data_table_row();
-	    }
-            $response .= &Apache::loncommon::end_data_table().'
+	       for (my $i=0; $i<$numcross; $i++) {
+                   $response .= 
+                       &Apache::loncommon::start_data_table_row().'
+                       <td><input type="text" size="15" name="newcross_'.$i.'" /></td>
+                       <td align="right"><input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+                       &Apache::loncommon::end_data_table_row();
+	        }
+                $response .= &Apache::loncommon::end_data_table();
+            }
+            $response .= '
               </td>
              </tr>
              <tr>
@@ -2134,32 +2199,64 @@
     }
     if ($numcross) {
         my %curr_groups = &Apache::longroup::coursegroups();
+        my (@codetitles,%cat_titles,%cat_order, at code_order);
+        &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles,
+                                                 \%cat_order,\@code_order);
+        my $lastitem = $codetitles[-1];
 	for (my $i=0; $i<$numcross; $i++) {
-	    my $xl = "newcross_".$i;
+	    my $xl = '';
+            if (@code_order > 0) {
+                foreach my $item (@code_order) {
+                    my $possval = $env{'form.newcross_'.$i.'_'.$item};
+                    if ($item eq $lastitem) {
+                        $xl .= $possval;
+                    } else {
+                        my $possval = $env{'form.newcross_'.$i.'_'.$item};
+                        if (ref($cat_order{$item}) eq 'ARRAY') {
+                            if (grep(/^\Q$possval\E$/,@{$cat_order{$item}})) {
+                                $xl .= $possval;
+                            }
+                        }
+                    }
+                }
+                if ($xl ne '') {
+                    my $crskey = $crs.':'.$xl;
+                    if ($env{'form.newcross_'.$i.'_instsec'} ne '') {
+                        my $poss_sec = $env{'form.newcross_'.$i.'_instsec'};
+                        my %formatted = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',
+                                                                               {$crskey => [$poss_sec]});
+                        if (ref($formatted{$crskey}) eq 'ARRAY') {
+                            $xl .= $formatted{$crskey}->[0];
+                        }
+                    }
+                }
+            } else {
+                $xl = $env{'form.newcross_'.$i};
+            }
 	    my $lc_sec = "newlcsec_".$i;
-	    if ( exists($env{"form.$xl"}) ) {
+	    if ($xl ne '') {
                 if (exists($env{"form.$lc_sec"})) {
                     my $lc_sec_check = &validate_lcsec(\%curr_groups,
                                                     $env{"form.$lc_sec"});
                     if ($lc_sec_check eq 'reserved') {
-                        push(@reserved,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+                        push(@reserved,$xl.':'.$env{"form.$lc_sec"});
                         next;
                     } elsif ($lc_sec_check eq 'group') {
-                        push(@matchgroup,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+                        push(@matchgroup,$xl.':'.$env{"form.$lc_sec"});
                         next;
                     }
                 }
 		my $coursecheck =
-                    &Apache::lonnet::auto_validate_courseID($crs,$dom,$env{"form.$xl"});
+                    &Apache::lonnet::auto_validate_courseID($crs,$dom,$xl);
 		if ($coursecheck eq 'ok') {
 		    my $addcheck = '';
-		    $addcheck = &Apache::lonnet::auto_new_course($crs,$dom,$env{"form.$xl"},$owner,$coowners);
+		    $addcheck = &Apache::lonnet::auto_new_course($crs,$dom,$xl,$owner,$coowners);
 		    unless ($addcheck eq 'ok') {
                         if ($coowners) {
                             foreach my $user (split(/,/,$coowners)) {
                                 if ($user =~ /^($match_username):($match_domain)$/) {
                                     if (&Apache::lonnet::auto_validate_inst_crosslist($crs,$dom,$coursecode,
-                                                                                      $env{"form.$xl"},$user) eq 'valid') {
+                                                                                      $xl,$user) eq 'valid') {
                                         $addcheck = 'ok';
                                         last;
                                     }
@@ -2168,12 +2265,12 @@
                         }
                     }
                     if ($addcheck eq 'ok') {
-                        push(@xlists,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+                        push(@xlists,$xl.':'.$env{"form.$lc_sec"});
                     } else { 
-			push(@badowner,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+			push(@badowner,$xl.':'.$env{"form.$lc_sec"});
 		    }
 		} else {
-		    push(@badxlists,$env{"form.$xl"}.":".$env{"form.$lc_sec"}.":".$coursecheck);
+		    push(@badxlists,$xl.':'.$env{"form.$lc_sec"}.":".$coursecheck);
 		}
 	    }
 	}
@@ -2193,7 +2290,9 @@
                 '<br /><br />';
 	} else {
 	    $response = &mt('The courses listed below are now crosslisted with this LON-CAPA course, and students enrolling in these course sections will be automatically added to the class roster for the course, if you have chosen to enable a nightly automated enrollment update.').'<br /><ul>'."\n";
-	    foreach my $item (@allxlists) {
+            my @showable;
+            &reformat_xlists($dom,$crs,$coursecode,\@allxlists,\@showable);
+            foreach my $item (@showable) {
 		my ($xlist,$lc_sec) = split(/:/,$item);
 		$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
                               "\n";
@@ -2205,7 +2304,9 @@
 	    my @oldxlists = split(/,/,$xliststr);
 	    $response .= &mt('Although no new crosslistings were added, the courses listed below continue to be crosslisted with your LON-CAPA course.').
                          '<br /><ul>'."\n";
-	    foreach my $xl (@oldxlists) {
+            my @showable;
+            &reformat_xlists($dom,$crs,$coursecode,\@oldxlists,\@showable);
+            foreach my $item (@showable) {
 		my ($xlist,$lc_sec) = split(/:/,$xl);
 		$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
                              "\n";
@@ -2216,7 +2317,9 @@
     if (@badxlists > 0) {
 	$response .= &mt("The courses listed below could not be included in the crosslistings for this LON-CAPA course, because they are not valid courses according to your institution's official schedule of classes and sections.").
                      '<br /><ul>'."\n";
-	foreach my $item (@badxlists) {
+        my @showable;
+        &reformat_xlists($dom,$crs,$coursecode,\@badxlists,\@showable);
+        foreach my $item (@showable) {
 	    my ($xlist,$lc_sec,$prob) = split(/:/,$item);
 	    $response .= '<li>'.
                          &mt('[_1] - ID: [_2] - Error: [_3]',
@@ -2228,7 +2331,9 @@
     if (@badowner > 0) {
 	$response .= &mt("The courses listed below could not be included in the crosslistings for this LON-CAPA course, because the owner of this course - [_1] - does not have rights to view enrollment in those classes, as determined by your instititution's policies on access to official classlists.",$owner).
                      '<br /><ul>'."\n";
-	foreach my $item (@badowner) {
+        my @showable;
+        &reformat_xlists($dom,$crs,$coursecode,\@badowner,\@showable);
+        foreach my $item (@showable) {
 	    my ($xlist,$lc_sec) = split(/:/,$item);
 	    $response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
                          "\n";
@@ -2240,7 +2345,9 @@
                      &mt('Please [_1]go back[_2]</a> and change the section ID for each of these courses.',
                          '<a href="javascript:history(-1)">','>/a>').
                      '<br /><ul>'."\n";  
-        foreach my $item (@reserved) {
+        my @showable;
+        &reformat_xlists($dom,$crs,$coursecode,\@reserved,\@showable);
+        foreach my $item (@showable) {
             my ($xlist,$lc_sec) = split(/:/,$item);
             $response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
                          "\n";
@@ -2252,7 +2359,9 @@
         $response .= &mt('The courses listed below could not be included in the crosslistings for this LON-CAPA course, because the section ID associated with the crosslisted course is the name of a group in this course.').' '.
                      &mt('Please [_1]go back[_2] and change the section ID for each of these courses.','<a href="javascript:history(-1)">','</a>').
                      '<br /><ul>'."\n";
-        foreach my $item (@matchgroup) {
+        my @showable;
+        &reformat_xlists($dom,$crs,$coursecode,\@matchgroup,\@showable);
+        foreach my $item (@showable) {
             my ($xlist,$lc_sec) = split(/:/,$item);
             $response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
                          "\n";
@@ -2272,6 +2381,33 @@
     return;
 }
 
+sub reformat_xlists {
+    my ($dom,$crs,$coursecode,$xlistsref,$showxlistsref) = @_;
+    return unless ((ref($xlistsref) eq 'ARRAY') && (ref($showxlistsref) eq 'ARRAY'));
+    my $crskey = $crs.':'.$coursecode;
+    my (@xlcodes, at lcsecs, at extras);
+    foreach my $xl (@{$xlistsref}) {
+        my ($instcodesec,$lc_sec,$extra) = split(/:/,$xl);
+        push(@xlcodes,$instcodesec);
+        push(@lcsecs,$lc_sec);
+        push(@extras,$extra);
+    }
+    my %reformatted =
+        &Apache::lonnet::auto_instsec_reformat($dom,'declutter',
+                                               {$crskey => \@xlcodes});
+    if (ref($reformatted{$crskey}) eq 'ARRAY') {
+        @xlcodes = @{$reformatted{$crskey}};
+        for (my $i=0; $i<@xlcodes; $i++) {
+            my $value = $xlcodes[$i].':'.$lcsecs[$i];
+            if ($extras[$i] ne '') {
+                $value .= ':'.$extras[$i];
+            }
+            push(@{$showxlistsref},$value);
+        }
+    }
+    return;
+}
+
 sub print_sections_menu {
     my ($r,$realm,$dom,$crs,$action,$tasktitleref) = @_;
     my %settings = 
@@ -2814,7 +2950,7 @@
 					 'internal.sectionnums',
 					 'internal.crosslistings'],
 					$dom,$crs);
-    &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+    &Apache::loncommon::get_institutional_codes($dom,$crs,\%settings,\@allcourses,\%LC_code);
     if (@allcourses > 0) {
         @{$affiliates{$crs}} = @allcourses;
         $outcome = &Apache::lonnet::auto_photoupdate(\%affiliates,$dom,$crs,\%changes);
@@ -2944,7 +3080,7 @@
 	$response = &mt('There was a problem retrieving the course code for this LON-CAPA course.').' '.
                     &mt('An update of the class roster has not been carried out, and enrollment remains unchanged.');
     } else {
-        &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+        &Apache::loncommon::get_institutional_codes($dom,$crs,\%settings,\@allcourses,\%LC_code);
 	if (@allcourses > 0) {
 	    @{$affiliates{$crs}} = @allcourses;
 	    my $outcome = &Apache::lonnet::fetch_enrollment_query('updatenow',\%affiliates,\%reply,$dom,$crs);
Index: loncom/interface/selfenroll.pm
diff -u loncom/interface/selfenroll.pm:1.36 loncom/interface/selfenroll.pm:1.37
--- loncom/interface/selfenroll.pm:1.36	Tue May  4 18:47:36 2021
+++ loncom/interface/selfenroll.pm	Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Allow users to self-enroll in a course
 #
-# $Id: selfenroll.pm,v 1.36 2021/05/04 18:47:36 raeburn Exp $
+# $Id: selfenroll.pm,v 1.37 2021/06/15 20:52:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -794,7 +794,7 @@
                                         'internal.sectionnums',
                                         'internal.crosslistings'],$cdom,$cnum);
     my (@allcourses,%LC_code,%affiliates,%reply);
-    &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+    &Apache::loncommon::get_institutional_codes($cdom,$cnum,\%settings,\@allcourses,\%LC_code);
     if (@allcourses > 0) {
         @{$affiliates{$cnum}} = @allcourses;
         my $outcome = &Apache::lonnet::fetch_enrollment_query('updatenow',\%affiliates,\%reply,$cdom,$cnum);
Index: loncom/lond
diff -u loncom/lond:1.566 loncom/lond:1.567
--- loncom/lond:1.566	Wed Mar 31 02:19:58 2021
+++ loncom/lond	Tue Jun 15 20:52:27 2021
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.566 2021/03/31 02:19:58 raeburn Exp $
+# $Id: lond,v 1.567 2021/06/15 20:52:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -65,7 +65,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.566 $'; #' stupid emacs
+my $VERSION='$Revision: 1.567 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -214,6 +214,7 @@
                autovalidatecourse => {remote => 1, enroll => 1},
                autovalidateinstcode => {domroles => 1, remote => 1, enroll => 1},
                autovalidateinstcrosslist => {remote => 1, enroll => 1},
+               autoinstsecreformat => {remote => 1, enroll => 1},
                changeuserauth => {remote => 1, domroles => 1},
                chatretr => {remote => 1, enroll => 1},
                chatsend => {remote => 1, enroll => 1},
@@ -6106,6 +6107,62 @@
 &register_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0);
 
 #
+#    Modify institutional sections (using customized &instsec_reformat()
+#    routine in localenroll.pm), to either clutter or declutter, for  
+#    purposes of ensuring an institutional course section (string) can
+#    be unambiguously separated into institutional course and section.
+#
+# Formal Parameters:
+#    $cmd     - The command request that got us dispatched.
+#    $tail    - The tail of the command.   In this case this is a colon separated
+#               set of values that will be split into:
+#               $cdom        - The LON-CAPA domain of the course.
+#               $action      - Either: clutter or declutter
+#                              clutter adds character(s) to eliminate ambiguity
+#                              declutter removes the added characters (e.g., for
+#                              display of the institutional course section string.
+#               $info        - A frozen hash in which keys are: 
+#                              LON-CAPA course number:Institutional course code
+#                              and values are a reference to an array of the
+#                              items to modify -- either institutional sections,
+#                              or institutional course sections (for crosslistings). 
+#    $client  - The socket open on the client.
+# Returns:
+#    1 - continue processing.
+#   
+
+sub instsec_reformat_handler {
+    my ($cmd, $tail, $client) = @_;
+    my $userinput = "$cmd:$tail";
+    my ($cdom,$action,$info) = split(/:/,$tail);
+    my $instsecref = &Apache::lonnet::thaw_unescape($info);
+    my ($outcome,$result);
+    eval {
+        local($SIG{__DIE__})='DEFAULT';
+        $outcome=&localenroll::instsec_reformat($cdom,$action,$instsecref);
+        if ($outcome eq 'ok') {
+            if (ref($instsecref) eq 'HASH') {
+                foreach my $key (keys(%{$instsecref})) {
+                    $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($instsecref->{$key}).'&';
+                }
+                $result =~ s/\&$//;
+            }
+        }
+    };
+    if (!$@) {
+        if ($outcome eq 'ok') {
+            &Reply( $client, \$result, $userinput);
+        } else {
+            &Reply($client,\$outcome, $userinput);
+        }
+    } else {
+        &Failure($client,"unknown_cmd\n",$userinput);
+    }
+    return 1;
+}
+&register_handler("autoinstsecreformat",\&instsec_reformat_handler, 0, 1, 0);
+
+#
 #   Validate course owner or co-owners(s) access to enrollment data for all sections
 #   and crosslistings for a particular course.
 #
Index: loncom/enrollment/Autoenroll.pl
diff -u loncom/enrollment/Autoenroll.pl:1.34 loncom/enrollment/Autoenroll.pl:1.35
--- loncom/enrollment/Autoenroll.pl:1.34	Wed Sep 14 20:58:27 2016
+++ loncom/enrollment/Autoenroll.pl	Tue Jun 15 20:52:27 2021
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 #
 #Automated Enrollment script
-# $Id: Autoenroll.pl,v 1.34 2016/09/14 20:58:27 raeburn Exp $
+# $Id: Autoenroll.pl,v 1.35 2021/06/15 20:52:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -74,6 +74,8 @@
         # Determine the courses
         my %courses = &Apache::lonnet::courseiddump($dom,'.',1,'.','.','.',1,\@hostids,'Course'); 
         my %affiliates = ();
+        my %unclutteredsec = ();
+        my %unclutteredlcsec = ();
         my %enrollvar = ();
         my %reply = ();
         my %LC_code = ();
@@ -120,17 +122,21 @@
                         $sections[0] = $enrollvar{$crs}{sectionnums};
                     }
                     if ($enrollvar{$crs}{crosslistings} =~ m/,/) {
-                        @crosslistings = split/,/,$enrollvar{$crs}{crosslistings}
+                        @crosslistings = split/,/,$enrollvar{$crs}{crosslistings};
                     } else {
                         @crosslistings = $enrollvar{$crs}{crosslistings};
                     }
+                    my $crscode = $enrollvar{$crs}{coursecode}; 
+                    my $crskey = $crs.':'.$crscode;
+                    @{$unclutteredsec{$crskey}} = ();
+                    @{$unclutteredlcsec{$crskey}} = (); 
                     foreach my $sec (@sections) {
                         if ($sec =~ m/^(\w+):(\w*)$/ ) {
-                            my $course_id = $enrollvar{$crs}{coursecode}.$1;
+                            my $instsec = $1; 
                             my $gp = $2;
-                            if (!grep/^\Q$course_id\E$/,@{$affiliates{$crs}}) {
-                                push @{$affiliates{$crs}}, $course_id;
-                                $LC_code{$crs}{$course_id} = $gp; 
+                            unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {
+                                push(@{$unclutteredsec{$crskey}},$instsec);
+                                push(@{$unclutteredlcsec{$crskey}},$gp);
                             }
                         }
                     }
@@ -147,6 +153,19 @@
                 }
             }
         }
+        my %formattedsec = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',\%unclutteredsec);
+        foreach my $crskey (keys(%formattedsec)) {
+            my ($crs,$instcode) = split(/:/,$crskey);
+            if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {
+                for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {
+                    my $course_id = $instcode.$formattedsec{$crskey}[$i]; 
+                    unless (grep/^\Q$course_id\E$/,@{$affiliates{$crs}}) {
+                        push(@{$affiliates{$crs}},$course_id);
+                        $LC_code{$crs}{$course_id} = $unclutteredlcsec{$crskey}[$i];
+                    }
+                }
+            }
+        }
         my $outcome = &Apache::lonnet::fetch_enrollment_query('automated',\%affiliates,\%reply,$dom);
 
 # Now go through classes and perform required enrollment changes.
Index: loncom/enrollment/localenroll.pm
diff -u loncom/enrollment/localenroll.pm:1.60 loncom/enrollment/localenroll.pm:1.61
--- loncom/enrollment/localenroll.pm:1.60	Wed Mar 31 02:19:58 2021
+++ loncom/enrollment/localenroll.pm	Tue Jun 15 20:52:27 2021
@@ -1,6 +1,6 @@
 # functions to glue school database system into Lon-CAPA for 
 # automated enrollment
-# $Id: localenroll.pm,v 1.60 2021/03/31 02:19:58 raeburn Exp $
+# $Id: localenroll.pm,v 1.61 2021/06/15 20:52:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -655,6 +655,101 @@
     return 'ok';
 }
 
+=pod
+
+=item instsec_reformat()
+
+ Inputs: $dom, $action, $instsecref
+
+ $dom is the course's domain
+ $action is either: clutter or declutter
+ $instsecref is a reference to a hash, in which each key is
+ course num:course code, and each value is either an array of 
+ institutional sections, or (in the case of crosslisted courses)
+ an array of institutional course sections.
+
+ Returns: ok
+
+ Side effects: will modify the items in the array as determined by
+ code implemented for the domain.  Modification will differ depending
+ on whether the action is clutter or declutter.
+
+ The idea is that "clutter" will modify the name of the section such
+ that a concatenation of institutional code then (modified) section
+ will result in a string that other customized routines in localenroll.pm
+ can separate without ambiguity into instituional code then (real)
+ institutional section using a regular expression.
+
+ Conversely, "declutter" will modify the name of an already modified
+ item such that display of the concatenated string (e.g., for a 
+ crosslisting in the course catalog) does not include the "added"
+ characters used to eliminate ambiguity. 
+
+ Examples (MSU):
+
+ Starting in Fall 2021 at MSU, institution section numbers are no
+ longer guaranteed to be three digit numbers (including leading zeroes).
+
+ So, for example the course code: fs21phy183b might have sections:
+ 001, 002, LEC1, LEC2, and be crosslisted with fs21phy233b (with 
+ sections: 730, LEC3, LEC4).
+
+ The sections: LEC1, and LEC2 should be changed to _LEC1, and _LEC2
+ before creating the inner keys in the %affiliates hash of a hash,
+ passed to fetch_enrollment() in Enrollment.pm.  They will however
+ be stored in the course's environment as LEC1 and LEC2.
+
+ For the crosslistings, LEC3 and LEC4 should be changed to 
+ _LEC3 and _LEC4 before storing in the course's environment.db file.
+
+ In both cases when it comes time to extract the various components
+ of an institutional section code (i.e., the concatenated string) in
+ fetch_enrollment(), for example, the regexp used at MSU would be:
+ 
+ if ($class =~ m/^([suf]s)(\d{2})(\w{2,4})(\d{3,4}[A-Za-z]?)(\d{3}|_[A-Za-z0-9]{1,5})$/) {
+     my ($sem,$yr,$subj,$crse,$sec) = ($1,$2,$3,$4,$5);
+
+ The three digit sections would match the \d{3} and the other sections
+ (LEC1, LEC2 etc.) would match the _[A-Za-z0-9]{1,5}.
+
+ The customization in &instsec_reformat() would be:
+
+     if ($action eq 'clutter') {
+         unless ($item =~ /^\d{3}$/) {
+             $item = '_'.$item;
+         }
+     } elsif ($action eq 'declutter') {
+         if ($item =~ /^([suf]s\d{2}\w{2,4}\d{3,4}[A-Za-z]?)(\d{3}|_[A-Za-z0-9]{1,5})$/) {
+             my ($instcode,$instsec) = ($1,$2);
+             $instsec =~ s/^_//;
+             $item = $instcode.$instsec;
+         } elsif ($item =~ /^_[A-Za-z0-9]{1,5}$/) {
+             $item =~ s/^_//;
+         }
+     }
+
+=cut
+
+sub instsec_reformat {
+    my ($dom,$action,$instsecref) = @;
+    if ((ref($instsecref) eq 'HASH') &&
+        (($action eq 'clutter') || ($action eq 'declutter'))) {
+        foreach my $key (keys(%{$instsecref})) {
+            if (ref($instsecref->{$key}) eq 'ARRAY') {
+                foreach my $sec (@{$instsecref->{$key}}) {
+                    if ($action eq 'clutter') {
+                        # modify the section, as needed.
+                        next;
+                    } elsif ($action eq 'declutter') {
+                        # modify the section, as needed.
+                        next;
+                    }
+                }
+            }
+        }
+    }
+    return 'ok';
+}
 
 =pod
 
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1459 loncom/lonnet/perl/lonnet.pm:1.1460
--- loncom/lonnet/perl/lonnet.pm:1.1459	Sat Jun 12 21:37:36 2021
+++ loncom/lonnet/perl/lonnet.pm	Tue Jun 15 20:52:28 2021
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1459 2021/06/12 21:37:36 raeburn Exp $
+# $Id: lonnet.pm,v 1.1460 2021/06/15 20:52:28 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -9788,6 +9788,38 @@
     return $response;
 }
 
+sub auto_instsec_reformat {
+    my ($cdom,$action,$instsecref) = @_;
+    return unless(($action eq 'clutter') || ($action eq 'declutter'));
+    my @homeservers;
+    if (defined(&domain($cdom,'primary'))) {
+        push(@homeservers,&domain($cdom,'primary'));
+    } else {
+        my %servers = &get_servers($cdom,'library');
+        foreach my $tryserver (keys(%servers)) {
+            if (!grep(/^\Q$tryserver\E$/, at homeservers)) {
+                push(@homeservers,$tryserver);
+            }
+        }
+    }
+    my $response;
+    my %reformatted = %{$instsecref};
+    foreach my $server (@homeservers) {
+        if (ref($instsecref) eq 'HASH') {
+            my $info = &freeze_escape($instsecref);
+            my $response=&reply('autoinstsecreformat:'.$cdom.':'.
+                                $action.':'.$info,$server);
+            next if ($response =~ /(con_lost|error|no_such_host|refused|unknown_command)/);
+            my @items = split(/&/,$response);
+            foreach my $item (@items) {
+                my ($key,$value) = split(/=/,$item);
+                $reformatted{&unescape($key)} = &thaw_unescape($value);
+            }
+        }
+    }
+    return %reformatted;
+}
+
 sub auto_validate_instclasses {
     my ($cdom,$cnum,$owners,$classesref) = @_;
     my ($homeserver,%validations);


More information about the LON-CAPA-cvs mailing list