[LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm lonmodifycourse.pm /metadata_database cleanup_database.pl

raeburn raeburn at source.lon-capa.org
Mon Aug 15 14:01:15 EDT 2016


raeburn		Mon Aug 15 18:01:15 2016 EDT

  Modified files:              
    /loncom/interface	lonmodifycourse.pm domainprefs.pm 
    /loncom/metadata_database	cleanup_database.pl 
  Log:
  - Lifetime of temporary md5_* tables (used to speed up access to student
    performance data, e.g., for Chart or Statistics), can be set as domain 
    default (based on course type), and be overridden by a DC in a course.
  
  
-------------- next part --------------
Index: loncom/interface/lonmodifycourse.pm
diff -u loncom/interface/lonmodifycourse.pm:1.84 loncom/interface/lonmodifycourse.pm:1.85
--- loncom/interface/lonmodifycourse.pm:1.84	Sun Jul 24 14:34:59 2016
+++ loncom/interface/lonmodifycourse.pm	Mon Aug 15 18:01:08 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # handler for DC-only modifiable course settings
 #
-# $Id: lonmodifycourse.pm,v 1.84 2016/07/24 14:34:59 raeburn Exp $
+# $Id: lonmodifycourse.pm,v 1.85 2016/08/15 18:01:08 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -44,7 +44,8 @@
     if ($type eq 'Community') {
         return ('courseowner','selfenrollmgrdc','selfenrollmgrcc');
     } else {
-        my @items = ('courseowner','coursecode','authtype','autharg','selfenrollmgrdc','selfenrollmgrcc');
+        my @items = ('courseowner','coursecode','authtype','autharg','selfenrollmgrdc',
+                     'selfenrollmgrcc','mysqltables');
         if (&showcredits($cdom)) {
             push(@items,'defaultcredits');
         }
@@ -268,14 +269,15 @@
         $setquota_text = &mt('Total disk space allocated for storage of portfolio files in all groups in a course.');
         $setuploadquota_text = &mt('Disk space allocated for storage of content uploaded directly to a course via Content Editor.');
         if (($type ne 'Placement') && (&showcredits($dom))) {
-            $setparams_text = 'View/Modify course owner, institutional code, default authentication, credits, and self-enrollment';
+            $setparams_text = 'View/Modify course owner, institutional code, default authentication, credits, self-enrollment and table lifetime';
         } else {
-            $setparams_text = 'View/Modify course owner, institutional code, default authentication, and self-enrollment';
+            $setparams_text = 'View/Modify course owner, institutional code, default authentication, self-enrollment and table lifetime';
         }
         $cat_text = 'View/Modify catalog settings for course';
     }
     my $anon_text = &mt('Responder threshold required to display anonymous survey submissions.');
     my $postsubmit_text = &mt('Override defaults for submit button behavior post-submission for this specific course.'); 
+    my $mysqltables_text = &mt('Override default for lifetime of "temporary" MySQL tables containing student performance data.');
 
     my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$dom);
     my @additional_params = &catalog_settable($domconf{'coursecategories'},$type);
@@ -380,7 +382,8 @@
         }
         $menu_html .= ' <li>'.&mt('Override defaults for who configures self-enrollment for this specific course.').'</li>'."\n";
     }
-    $menu_html .= '<li>'.$setquota_text.'</li>'."\n".
+    $menu_html .= '<li>'.$mysqltables_text.'</li>'."\n".
+                  '<li>'.$setquota_text.'</li>'."\n".
                   '<li>'.$setuploadquota_text.'</li>'."\n".
                   '<li>'.$anon_text.'</li>'."\n".
                   '<li>'.$postsubmit_text.'</li>'."\n";
@@ -768,7 +771,8 @@
     my ($ownertable,$ccrole,$javascript_validations,$authenitems,$ccname);
     my %enrollvar = &get_enrollment_settings($cdom,$cnum);
     my %settings = &Apache::lonnet::get('environment',['internal.coursecode','internal.textbook',
-                                                       'internal.selfenrollmgrdc','internal.selfenrollmgrcc'],
+                                                       'internal.selfenrollmgrdc','internal.selfenrollmgrcc',
+                                                       'internal.mysqltables'],
                                         $cdom,$cnum);
     my $type = &Apache::lonuserutils::get_extended_type($cdom,$cnum,$crstype,\%settings);
     my @specific_managebydc = split(/,/,$settings{'internal.selfenrollmgrdc'});
@@ -917,7 +921,12 @@
                   &Apache::loncommon::end_data_table_row()."\n");
     }
     $r->print(&Apache::loncommon::end_data_table()."\n".
-              '<br />'.&Apache::lonhtmlcommon::row_closure(1).
+              '<br />'.&Apache::lonhtmlcommon::row_closure().
+              &Apache::lonhtmlcommon::row_title(
+              &Apache::loncommon::help_open_topic('Modify_Course_Table_Lifetime').
+              ' '.&mt('"Temporary" Tables Lifetime (s)'))."\n".
+              '<input type="text" size="10" name="mysqltables" value="'.$settings{'internal.mysqltables'}.'" />'.
+              &Apache::lonhtmlcommon::row_closure(1).
               &Apache::lonhtmlcommon::end_pick_box().'</p><p>'.$hidden_elements.
               '<input type="button" onclick="javascript:changePage(this.form,'."'processparms'".');');
     if ($crstype eq 'Community') {
@@ -1039,7 +1048,7 @@
     my %longtype = &course_settings_descrip($type);
     my @items = ('internal.courseowner','description','internal.co-owners',
                  'internal.pendingco-owners','internal.selfenrollmgrdc',
-                 'internal.selfenrollmgrcc');
+                 'internal.selfenrollmgrcc','internal.mysqltables');
     my ($selfenrollrows,$selfenrolltitles) = &Apache::lonuserutils::get_selfenroll_titles();
     unless (($type eq 'Community') || ($type eq 'Placement')) {
         push(@items,('internal.coursecode','internal.authtype','internal.autharg',
@@ -1110,10 +1119,13 @@
                 $changed{'code'} = 1;
             }
         }
-
+        if ( exists($env{'form.mysqltables'}) ) {
+            $newattr{'mysqltables'} = $env{'form.mysqltables'};
+            $newattr{'mysqltables'} =~ s/\D+//g;
+        }
         if (($type ne 'Placement') && (&showcredits($cdom) && exists($env{'form.defaultcredits'}))) {
-            $newattr{'defaultcredits'} =~ s/[^\d\.]//g;
             $newattr{'defaultcredits'}=$env{'form.defaultcredits'};
+            $newattr{'defaultcredits'} =~ s/[^\d\.]//g;
         }
     }
 
@@ -1205,6 +1217,8 @@
                         $shown = &selfenroll_config_status(\@newmgrcc,$selfenrolltitles);
                     } elsif (($attr eq 'defaultcredits') && ($shown eq '')) {
                         $shown = &mt('None');
+                    } elsif (($attr eq 'mysqltables') && ($shown eq '')) {
+                        $shown = &mt('domain default');
                     }
                     $chgresponse .= '<li>'.&mt('[_1] now set to: [_2]',$longtype{$attr},$shown).'</li>';
                 } else {
@@ -1215,6 +1229,8 @@
                         $shown = &selfenroll_config_status(\@currmgrcc,$selfenrolltitles);
                     } elsif (($attr eq 'defaultcredits') && ($shown eq '')) {
                         $shown = &mt('None');
+                    } elsif (($attr eq 'mysqltables') && ($shown eq '')) {
+                        $shown = &mt('domain default');
                     }
                     $nochgresponse .= '<li>'.&mt('[_1] still set to: [_2]',$longtype{$attr},$shown).'</li>';
                 }
@@ -1286,6 +1302,8 @@
                 $shown = &selfenroll_config_status(\@currmgrcc,$selfenrolltitles);
             } elsif (($attr eq 'defaultcredits') && ($shown eq '')) {
                 $shown = &mt('None');
+            } elsif (($attr eq 'mysqltables') && ($shown eq '')) {
+                $shown = &mt('domain default');
             }
             $nochgresponse .= '<li>'.&mt('[_1] still set to: [_2]',$longtype{$attr},$shown).'</li>';
         }
@@ -2112,6 +2130,7 @@
                       'co-owners'        => "Username:domain of each co-owner",
                       'selfenrollmgrdc'  => "Community-specific self-enrollment configuration by Domain Coordinator",
                       'selfenrollmgrcc'  => "Community-specific self-enrollment configuration by Community personnel",
+                      'mysqltables'      => '"Temporary" student performance tables lifetime (seconds)',
          );
     } else {
          %longtype = &Apache::lonlocal::texthash(
@@ -2133,7 +2152,7 @@
                       'autodropfailsafe' => "Failsafe section enrollment count",
                       'selfenrollmgrdc'  => "Course-specific self-enrollment configuration by Domain Coordinator",
                       'selfenrollmgrcc'  => "Course-specific self-enrollment configuration by Course personnel",
-
+                      'mysqltables'      => '"Temporary" student performance tables lifetime (seconds)',
          );
     }
     return %longtype;
@@ -2146,7 +2165,7 @@
           'locarg','krbarg','krbver','counter','hidefromcat','usecategory',
           'threshold','postsubmit','postsubtimeout','defaultcredits','uploadquota',
           'selfenrollmgrdc','selfenrollmgrcc','action','state','currsec_st',
-          'sections','newsec'],['^selfenrollmgr_'])."\n".
+          'sections','newsec','mysqltables'],['^selfenrollmgr_','^selfenroll_'])."\n".
           '<input type="hidden" name="prevphase" value="'.$env{'form.phase'}.'" />';
     return $hidden_elements;
 }
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.275 loncom/interface/domainprefs.pm:1.276
--- loncom/interface/domainprefs.pm:1.275	Mon Jul 25 19:50:30 2016
+++ loncom/interface/domainprefs.pm	Mon Aug 15 18:01:09 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.275 2016/07/25 19:50:30 raeburn Exp $
+# $Id: domainprefs.pm,v 1.276 2016/08/15 18:01:09 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -3359,12 +3359,14 @@
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
         usejsme              => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
         postsubmit           => 'Disable submit button/keypress following student submission',
-        canclone             => "People who may clone a course (besides course's owner and coordinators)",     
+        canclone             => "People who may clone a course (besides course's owner and coordinators)",
+        mysqltables          => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver',
     );
     my %staticdefaults = (
                            anonsurvey_threshold => 10,
                            uploadquota          => 500,
                            postsubmit           => 60,
+                           mysqltables          => 172800,
                          );
     if ($position eq 'top') {
         %defaultchecked = (
@@ -3449,7 +3451,7 @@
         $itemcount ++;
     } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
-        my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout);
+        my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
         my $currusecredits = 0;
         my $postsubmitclient = 1;
         my @types = ('official','unofficial','community','textbook','placement');
@@ -3493,6 +3495,15 @@
                     $deftimeout{$type} = $staticdefaults{'postsubmit'};
                 }
             }
+            if (ref($settings->{'mysqltables'}) eq 'HASH') {
+                foreach my $type (keys(%{$settings->{'mysqltables'}})) {
+                    $currmysql{$type} = $settings->{'mysqltables'}{$type};
+                }
+            } else {
+                foreach my $type (@types) {
+                    $currmysql{$type} = $staticdefaults{'mysqltables'};
+                }
+            }
         } else {
             foreach my $type (@types) {
                 $deftimeout{$type} = $staticdefaults{'postsubmit'};
@@ -3577,6 +3588,20 @@
             &radiobutton_prefs($current,\@toggles,\%defaultchecked,
                                \%choices,$itemcount,$onclick,$additional,'left');
         $datatable .= $table;
+        $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+        $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
+                      $choices{'mysqltables'}.
+                      '</span></td>'.
+                      '<td align="right" class="LC_right_item">'.
+                      '<table><tr>';
+        foreach my $type (@types) {
+            $datatable .= '<td align="center">'.&mt($type).'<br />'.
+                           '<input type="text" name="mysqltables_'.$type.'"'.
+                           ' value="'.$currmysql{$type}.'" size="5" /></td>';
+        }
+        $datatable .= '</tr></table></td></tr>'."\n";
+        $itemcount ++;
+
     }
     $$rowtotal += $itemcount;
     return $datatable;
@@ -11629,12 +11654,15 @@
                          );
     my @toggles = ('canuse_pdfforms','uselcmath','usejsme');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
-                   'uploadquota_community','uploadquota_textbook','uploadquota_placement');
+                   'uploadquota_community','uploadquota_textbook','uploadquota_placement',
+                   'mysqltables_official','mysqltables_unofficial','mysqltables_community',
+                   'mysqltables_textbook','mysqltables_placement');
     my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (
                            anonsurvey_threshold => 10,
                            uploadquota          => 500,
                            postsubmit           => 60,
+                           mysqltables          => 172800,
                          );
 
     $defaultshash{'coursedefaults'} = {};
@@ -11675,12 +11703,12 @@
                 }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {
-                my ($type) = ($item =~ /^\Quploadquota_\E(\w+)$/);
-                if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') {
-                    $currdef = $domconfig{'coursedefaults'}{'uploadquota'}{$type};
+                my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);
+                if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
+                    $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }
                 $newdef =~ s/[^\w.\-]//g;
-                $defaultshash{'coursedefaults'}{'uploadquota'}{$type} = $newdef;
+                $defaultshash{'coursedefaults'}{$setting}{$type} = $newdef;
             }
             if ($currdef ne $newdef) {
                 my $staticdef;
@@ -11688,9 +11716,10 @@
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;
                     }
-                } else {
-                    unless (($currdef eq '') && ($newdef == $staticdefaults{'uploadquota'})) {
-                        $changes{'uploadquota'} = 1;
+                } elsif ($item =~ /^(uploadquota|mysqltables)_/) {
+                    my $setting = $1; 
+                    unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
+                        $changes{$setting} = 1;
                     }
                 }
             }
@@ -11815,7 +11844,7 @@
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||
                 ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||
-                ($changes{'canclone'})) {
+                ($changes{'canclone'}) || ($changes{'mysqltables'})) {
                 foreach my $item ('canuse_pdfforms','uselcmath','usejsme') { 
                     if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
@@ -11900,6 +11929,19 @@
                     } else {
                         $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
                     }
+                } elsif ($item eq 'mysqltables') {
+                    if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
+                        $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
+                                       '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.
+                                       '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.
+                                       '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
+                                       '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
+                                       '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
+                                       '</ul>'.
+                                       '</li>';
+                    } else {
+                        $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver remains default: [_1] s',$staticdefaults{'uploadquota'}).'</li>';
+                    }
                 } elsif ($item eq 'postsubmit') {
                     if ($domdefaults{'postsubmit'} eq 'off') {
                         $resulttext .= '<li>'.&mt('Submit button(s) remain enabled on page after student makes submission.');
Index: loncom/metadata_database/cleanup_database.pl
diff -u loncom/metadata_database/cleanup_database.pl:1.7 loncom/metadata_database/cleanup_database.pl:1.8
--- loncom/metadata_database/cleanup_database.pl:1.7	Mon Nov 20 17:07:57 2006
+++ loncom/metadata_database/cleanup_database.pl	Mon Aug 15 18:01:14 2016
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # cleanup_database.pl Remove stale temporary search results.
 #
-# $Id: cleanup_database.pl,v 1.7 2006/11/20 17:07:57 albertel Exp $
+# $Id: cleanup_database.pl,v 1.8 2016/08/15 18:01:14 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -57,9 +57,10 @@
 
 =back
 
-The following invocation is equivalent to the default:
+The following invocation will drop all tables without updates in the past
+two days (the default).
 
- cleanup_database.pl --killtime 86400
+ cleanup_database.pl --killtime 172800
 
 If you desire the immediate cleanup of temporary tables, use the following:
 
@@ -74,12 +75,14 @@
 use strict;
 use lib '/home/httpd/lib/perl/';
 use LONCAPA::Configuration;
+use Apache::lonnet;
 use Getopt::Long;
 use Time::Local;
 use DBI;
+use Digest::MD5();
 
 my $help = 0;
-my $killtime = 86400*2;
+my $killtime;
 GetOptions( "killtime=s" => \$killtime, 
             "help"       => \$help );
 if ($help) {
@@ -88,7 +91,11 @@
                         temporary tables.
 Command line arguements
    --killtime  <number>     The number of seconds a temporary table is allowed
-                            to live.  Defaults to 86400 (1 day)
+                            to live. On a library server, specifying this argument
+                            also overrides any course-specific or domain-specific
+                            lifetimes which apply to the various md5_hash_* tables
+                            which contain student data for a course, for which the
+                            current server is the homeserver.
    --help                   Print out this help message.
 
 Examples:
@@ -121,14 +128,53 @@
 $sth->execute();
 my $results = $sth->fetchall_hashref('Name');
 
+my ($nokilltime,$gotconf,%coursetypes,%md5hashes,%domcrsdefs,%gotcourseenv,%crssetting);
+if ($killtime eq '') {
+    $killtime = 86400*2;
+    if ($perlvar{'lonRole'} eq 'library') {
+        $nokilltime = 1; 
+    }
+}
+
 foreach my $name (keys(%$results)) {
-    next if ($results->{$name}{Comment} ne 'temporary'); 
+    next if ($results->{$name}{Comment} ne 'temporary');
     my $tabletime = $results->{$name}{Update_time};
     # Times are like: 2002-07-25 10:17:08
     my ($year,$month,$day,$hour,$min,$sec)= 
         ($tabletime =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/);
     my $epoch_seconds = timelocal($sec,$min,$hour,$day,$month-1,$year-1900);
-    if ((time - $epoch_seconds) > $killtime) {
+    my $currkilltime = $killtime;
+    if ($nokilltime) {
+        if ($name =~ /^md5_(\w+)_(?:\w+)$/) {
+            my $hashid = $1;
+            unless ($gotconf) {
+                &get_config(\%coursetypes,\%md5hashes,\%domcrsdefs);
+                $gotconf = 1;
+            }
+            if (exists($md5hashes{$hashid})) {
+                my ($cdom,$cnum) = split(/_/,$md5hashes{$hashid});  
+                unless ($gotcourseenv{$md5hashes{$hashid}}) {
+                    my %envhash = &Apache::lonnet::dump('environment',$cdom,$cnum);
+                    $gotcourseenv{$md5hashes{$hashid}} = 1;
+                    if ($coursetypes{$md5hashes{$hashid}} eq 'unofficial') {
+                         if ($envhash{'internal.textbook'}) {
+                             $coursetypes{$md5hashes{$hashid}} = 'textbook';
+                         }
+                    }
+                    $crssetting{$md5hashes{$hashid}} = $envhash{'internal.mysqltables'};
+                }
+                if (($crssetting{$md5hashes{$hashid}} ne '') && ($crssetting{$md5hashes{$hashid}} !~ /^\D/)) {
+                    $currkilltime = $crssetting{$md5hashes{$hashid}};
+                } elsif (ref($domcrsdefs{$cdom}) eq 'HASH') {
+                    if (($domcrsdefs{$cdom}{$coursetypes{$md5hashes{$hashid}}} ne '') &&
+                        ($domcrsdefs{$cdom}{$coursetypes{$md5hashes{$hashid}}} !~ /^\D/)) {
+                        $currkilltime = $domcrsdefs{$cdom}{$coursetypes{$md5hashes{$hashid}}};
+                    }
+                }
+            }
+        }
+    }
+    if ((time - $epoch_seconds) > $currkilltime) {
         $dbh->do('DROP TABLE '.$name);
     }
 }
@@ -137,3 +183,39 @@
 # --------------------------------------------------- Close database connection
 $dbh->disconnect;
 
+sub get_config {
+    my ($coursetypes,$md5hashref,$domsettings) = @_;
+    my @domains = sort(&Apache::lonnet::current_machine_domains());
+    my @ids=&Apache::lonnet::current_machine_ids();
+    foreach my $dom (@domains) {
+        my %domconfig = &Apache::lonnet::get_dom('configuration',['coursedefaults'],$dom);
+        if (ref($domconfig{'coursedefaults'}) eq 'HASH') {
+            if (ref($domconfig{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
+                $domsettings->{$dom} = $domconfig{'coursedefaults'}{'mysqltables'};
+            }
+        }
+        my %currhash = &Apache::lonnet::courseiddump($dom,'.',1,'.','.','.',1,\@ids,'.');
+        if (keys(%currhash)) {
+            foreach my $key (keys(%currhash)) {
+                if ($key ne '') {
+                    if (ref($currhash{$key}) eq 'HASH') {
+                        my $digest = &Digest::MD5::md5_hex($key);
+                        $md5hashref->{$digest} = $key;
+                        my $crstype = $currhash{$key}{'type'}; 
+                        my $longcrstype = 'unofficial';
+                        if ($crstype eq 'Community') {
+                            $longcrstype = 'community';
+                        } elsif ($crstype eq 'Placement') {
+                            $longcrstype = 'placement';
+                        } elsif ($currhash{$key}{'inst_code'}) {
+                            $longcrstype = 'official';
+                        }
+                        $coursetypes->{$key} = $longcrstype;
+                    }
+                }
+            }
+        }
+    }
+    return;
+}
+


More information about the LON-CAPA-cvs mailing list