--- loncom/lonnet/perl/lonnet.pm	2016/03/02 18:23:17	1.1302
+++ loncom/lonnet/perl/lonnet.pm	2016/05/30 04:48:23	1.1310
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1302 2016/03/02 18:23:17 raeburn Exp $
+# $Id: lonnet.pm,v 1.1310 2016/05/30 04:48:23 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1288,7 +1288,7 @@ sub check_loadbalancing {
     my $uintdom = &Apache::lonnet::internet_dom($uprimary_id);
     my $intdom = &Apache::lonnet::internet_dom($lonhost);
     my $serverhomedom = &host_domain($lonhost);
-
+    my $domneedscache;
     my $cachetime = 60*60*24;
 
     if (($uintdom ne '') && ($uintdom eq $intdom)) {
@@ -1303,6 +1303,8 @@ sub check_loadbalancing {
             &Apache::lonnet::get_dom('configuration',['loadbalancing'],$dom_in_use);
         if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
             $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
+        } else {
+            $domneedscache = $dom_in_use;
         }
     }
     if (ref($result) eq 'HASH') {
@@ -1361,7 +1363,9 @@ sub check_loadbalancing {
             my %domconfig =
                 &Apache::lonnet::get_dom('configuration',['loadbalancing'],$serverhomedom);
             if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
-                $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
+                $result = &do_cache_new('loadbalancing',$serverhomedom,$domconfig{'loadbalancing'},$cachetime);
+            } else {
+                $domneedscache = $serverhomedom;
             }
         }
         if (ref($result) eq 'HASH') {
@@ -1381,12 +1385,21 @@ sub check_loadbalancing {
                 $is_balancer = 1;
                 $offloadto = &this_host_spares($dom_in_use);
             }
+            unless (defined($cached)) {
+                $domneedscache = $serverhomedom;
+            }
         }
     } else {
         if ($perlvar{'lonBalancer'} eq 'yes') {
             $is_balancer = 1;
             $offloadto = &this_host_spares($dom_in_use);
         }
+        unless (defined($cached)) {
+            $domneedscache = $serverhomedom;
+        }
+    }
+    if ($domneedscache) {
+        &do_cache_new('loadbalancing',$domneedscache,$is_balancer,$cachetime);
     }
     if ($is_balancer) {
         my $lowest_load = 30000;
@@ -1895,7 +1908,7 @@ sub retrieve_inst_usertypes {
 
 sub is_domainimage {
     my ($url) = @_;
-    if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo)/+-) {
+    if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo)/+[^/]-) {
         if (&domain($1) ne '') {
             return '1';
         }
@@ -2190,7 +2203,7 @@ sub get_domain_defaults {
                                   'coursedefaults','usersessions',
                                   'requestauthor','selfenrollment',
                                   'coursecategories'],$domain);
-    my @coursetypes = ('official','unofficial','community','textbook');
+    my @coursetypes = ('official','unofficial','community','textbook','placement');
     if (ref($domconfig{'defaults'}) eq 'HASH') {
         $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; 
         $domdefaults{'auth_def'} = $domconfig{'defaults'}{'auth_def'};
@@ -2220,7 +2233,7 @@ sub get_domain_defaults {
         }
     }
     if (ref($domconfig{'requestcourses'}) eq 'HASH') {
-        foreach my $item ('official','unofficial','community','textbook') {
+        foreach my $item ('official','unofficial','community','textbook','placement') {
             $domdefaults{$item} = $domconfig{'requestcourses'}{$item};
         }
     }
@@ -4633,9 +4646,10 @@ my %cachedtimes=();
 my $cachedtime='';
 
 sub load_all_first_access {
-    my ($uname,$udom)=@_;
+    my ($uname,$udom,$ignorecache)=@_;
     if (($cachedkey eq $uname.':'.$udom) &&
-        (abs($cachedtime-time)<5) && (!$env{'form.markaccess'})) {
+        (abs($cachedtime-time)<5) && (!$env{'form.markaccess'}) &&
+        (!$ignorecache)) {
         return;
     }
     $cachedtime=time;
@@ -4644,7 +4658,7 @@ sub load_all_first_access {
 }
 
 sub get_first_access {
-    my ($type,$argsymb,$argmap)=@_;
+    my ($type,$argsymb,$argmap,$ignorecache)=@_;
     my ($symb,$courseid,$udom,$uname)=&whichuser();
     if ($argsymb) { $symb=$argsymb; }
     my ($map,$id,$res)=&decode_symb($symb);
@@ -4656,7 +4670,7 @@ sub get_first_access {
     } else {
 	$res=$symb;
     }
-    &load_all_first_access($uname,$udom);
+    &load_all_first_access($uname,$udom,$ignorecache);
     return $cachedtimes{"$courseid\0$res"};
 }
 
@@ -6530,6 +6544,7 @@ sub usertools_access {
                       unofficial => 1,
                       community  => 1,
                       textbook   => 1,
+                      placement  => 1,
                  );
     } elsif ($context eq 'requestauthor') {
         %tools = (
@@ -7263,7 +7278,7 @@ sub allowed {
        my $unamedom=$env{'user.name'}.':'.$env{'user.domain'};
        if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.roles.denied'}
 	   =~/\Q$rolecode\E/) {
-	   if (($priv ne 'pch') && ($priv ne 'plc')) { 
+	   if (($priv ne 'pch') && ($priv ne 'plc') && ($priv ne 'pac')) {
 	       &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'.
 			'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '.
 			$env{'request.course.id'});
@@ -7273,7 +7288,7 @@ sub allowed {
 
        if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.users.denied'}
 	   =~/\Q$unamedom\E/) {
-	   if (($priv ne 'pch') && ($priv ne 'plc')) { 
+	   if (($priv ne 'pch') && ($priv ne 'plc') && ($priv ne 'pac')) {
 	       &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.
 			'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '.
 			$env{'request.course.id'});
@@ -7504,8 +7519,8 @@ sub get_commblock_resources {
                             }
                         }
                     }
-                    if ($interval[0] =~ /^\d+/) {
-                        my ($timelimit) = split(/_/,$interval[0]);
+                    if ($interval[0] =~ /^(\d+)/) {
+                        my $timelimit = $1; 
                         my $first_access;
                         if ($type eq 'resource') {
                             $first_access=&get_first_access($interval[1],$item);
@@ -8277,6 +8292,33 @@ sub auto_crsreq_update {
     return \%crsreqresponse;
 }
 
+sub auto_export_grades {
+    my ($cdom,$cnum,$inforef,$gradesref) = @_;
+    my ($homeserver,%exportresponse);
+    if ($cdom =~ /^$match_domain$/) {
+        $homeserver = &domain($cdom,'primary');
+    }
+    unless (($homeserver eq 'no_host') || ($homeserver eq '')) {
+        my $info;
+        if (ref($inforef) eq 'HASH') {
+            $info = &freeze_escape($inforef);
+        }
+        if (ref($gradesref) eq 'HASH') {
+            my $grades = &freeze_escape($gradesref);
+            my $response=&reply('encrypt:autoexportgrades:'.$cdom.':'.$cnum.':'.
+                                $info.':'.$grades,$homeserver);
+            unless ($response =~ /(con_lost|error|no_such_host|refused|unknown_command)/) {
+                my @items = split(/&/,$response);
+                foreach my $item (@items) {
+                    my ($key,$value) = split('=',$item);
+                    $exportresponse{&unescape($key)} = &thaw_unescape($value);
+                }
+            }
+        }
+    }
+    return \%exportresponse;
+}
+
 sub check_instcode_cloning {
     my ($codedefaults,$code_order,$cloner,$clonefromcode,$clonetocode) = @_;
     unless ((ref($codedefaults) eq 'HASH') && (ref($code_order) eq 'ARRAY')) {
@@ -8498,6 +8540,7 @@ sub plaintext {
     my %rolenames = (
                       Course    => 'std',
                       Community => 'alt1',
+                      Placement => 'std',
                     );
     if ($cid ne '') {
         if ($env{'course.'.$cid.'.'.$short.'.plaintext'} ne '') {
@@ -13084,10 +13127,17 @@ BEGIN {
                 my $name = $token->[2]{'name'};
                 my $value = $token->[2]{'value'};
                 my $valuematch = $token->[2]{'valuematch'};
-                if ($item ne '' && $name ne '' && ($value ne '' || $valuematch ne '')) {
+                my $namematch = $token->[2]{'namematch'};
+                if ($item eq 'parameter') {
+                    if (($namematch ne '') || (($name ne '') && ($value ne '' || $valuematch ne ''))) {
+                        my $release = $parser->get_text();
+                        $release =~ s/(^\s*|\s*$ )//gx;
+                        $needsrelease{$item.':'.$name.':'.$value.':'.$valuematch.':'.$namematch} = $release;
+                    }
+                } elsif ($item ne '' && $name ne '') {
                     my $release = $parser->get_text();
                     $release =~ s/(^\s*|\s*$ )//gx;
-                    $needsrelease{$item.':'.$name.':'.$value.':'.$valuematch} = $release;
+                    $needsrelease{$item.':'.$name.':'.$value} = $release;
                 }
             }
         }
@@ -14147,7 +14197,7 @@ requestcourses: ability to request cours
 =over
 
 =item
-official, unofficial, community, textbook
+official, unofficial, community, textbook, placement
 
 =back
 
@@ -14169,7 +14219,7 @@ for course's uploaded content.
 
 =item
 canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, 
-communityquota, textbookquota
+communityquota, textbookquota, placementquota
 
 =back