--- loncom/interface/loncommon.pm	2014/02/19 15:50:56	1.1176
+++ loncom/interface/loncommon.pm	2014/06/16 05:12:31	1.1193
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1176 2014/02/19 15:50:56 raeburn Exp $
+# $Id: loncommon.pm,v 1.1193 2014/06/16 05:12:31 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -69,6 +69,7 @@ use Apache::lontexconvert();
 use Apache::lonclonecourse();
 use Apache::lonuserutils();
 use Apache::lonuserstate();
+use Apache::courseclassifier();
 use LONCAPA qw(:DEFAULT :match);
 use DateTime::TimeZone;
 use DateTime::Locale::Catalog;
@@ -1315,8 +1316,10 @@ sub helpLatexCheatsheet {
 	  .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
 	  .'</span>';
     unless ($not_author) {
-        $out .= ' <span>'
-	       .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
+        $out .= '<span>'
+               .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
+               .'</span> <span>'
+               .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600)
 	       .'</span>';
     }
     $out .= '</span>'; # End cheatsheet
@@ -2382,7 +2385,7 @@ sub decode_user_agent {
     my $clientunicode='0';
     my $clientmobile=0;
     for (my $i=0;$i<=$#browsertype;$i++) {
-        my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
+        my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\%/,$browsertype[$i]);
 	if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {
 	    $clientbrowser=$bname;
             $httpbrowser=~/$vreg/i;
@@ -4319,23 +4322,20 @@ sub findallcourses {
 ###############################################
 
 sub blockcheck {
-    my ($setters,$activity,$uname,$udom,$url) = @_;
+    my ($setters,$activity,$uname,$udom,$url,$is_course) = @_;
 
-    if (!defined($udom)) {
+    if (defined($udom) && defined($uname)) {
+        # If uname and udom are for a course, check for blocks in the course.
+        if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
+            my ($startblock,$endblock,$triggerblock) =
+                &get_blocks($setters,$activity,$udom,$uname,$url);
+            return ($startblock,$endblock,$triggerblock);
+        }
+    } else {
         $udom = $env{'user.domain'};
-    }
-    if (!defined($uname)) {
         $uname = $env{'user.name'};
     }
 
-    # If uname and udom are for a course, check for blocks in the course.
-
-    if (&Apache::lonnet::is_course($udom,$uname)) {
-        my ($startblock,$endblock,$triggerblock) = 
-            &get_blocks($setters,$activity,$udom,$uname,$url);
-        return ($startblock,$endblock,$triggerblock);
-    }
-
     my $startblock = 0;
     my $endblock = 0;
     my $triggerblock = '';
@@ -4345,7 +4345,8 @@ sub blockcheck {
     # boards, chat or groups, check for blocking in current course only.
 
     if (($activity eq 'boards' || $activity eq 'chat' ||
-         $activity eq 'groups') && ($env{'request.course.id'})) {
+         $activity eq 'groups' || $activity eq 'printout') &&
+        ($env{'request.course.id'})) {
         foreach my $key (keys(%live_courses)) {
             if ($key ne $env{'request.course.id'}) {
                 delete($live_courses{$key});
@@ -4609,12 +4610,12 @@ sub parse_block_record {
 }
 
 sub blocking_status {
-    my ($activity,$uname,$udom,$url) = @_;
+    my ($activity,$uname,$udom,$url,$is_course) = @_;
     my %setters;
 
 # check for active blocking
     my ($startblock,$endblock,$triggerblock) = 
-        &blockcheck(\%setters,$activity,$uname,$udom,$url);
+        &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course);
     my $blocked = 0;
     if ($startblock && $endblock) {
         $blocked = 1;
@@ -5151,7 +5152,10 @@ sub bodytag {
     @design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; 
 
  # role and realm
-    my ($role,$realm) = split(/\./,$env{'request.role'},2);
+    my ($role,$realm) = split(m{\./},$env{'request.role'},2);
+    if ($realm) {
+        $realm = '/'.$realm;
+    }
     if ($role  eq 'ca') {
         my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
         $realm = &plainname($rname,$rdom);
@@ -7298,7 +7302,10 @@ sub headtag {
 	'<head>'.
 	&font_settings($args);
 
-    my $inhibitprint = &print_suppression();
+    my $inhibitprint;
+    if ($args->{'print_suppress'}) {
+        $inhibitprint = &print_suppression();
+    }
 
     if (!$args->{'frameset'}) {
 	$result .= &Apache::lonhtmlcommon::htmlareaheaders();
@@ -7424,7 +7431,7 @@ sub print_suppression {
         }
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
-        my $blocked = &blocking_status('printout',$cnum,$cdom);
+        my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1);
         if ($blocked) {
             my $checkrole = "cm./$cdom/$cnum";
             if ($env{'request.course.sec'} ne '') {
@@ -8967,10 +8974,10 @@ sub excess_filesize_warning {
     }
     $disk_quota = int($disk_quota * 1000);
     if (($current_disk_usage + $filesize) > $disk_quota) {
-        return '<p><span class="LC_warning">'.
+        return '<p class="LC_warning">'.
                 &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.",
-                    '<span class="LC_filename">'.$filename.'</span>',$filesize).'</span>'.
-               '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
+                    '<span class="LC_filename">'.$filename.'</span>',$filesize).'</p>'.
+               '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
                             $disk_quota,$current_disk_usage).
                '</p>';
     }
@@ -9423,7 +9430,14 @@ sub personal_data_fieldtitles {
 
 sub sorted_inst_types {
     my ($dom) = @_;
-    my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
+    my ($usertypes,$order);
+    my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
+    if (ref($domdefaults{'inststatus'}) eq 'HASH') {
+        $usertypes = $domdefaults{'inststatus'}{'inststatustypes'};
+        $order = $domdefaults{'inststatus'}{'inststatusorder'};
+    } else {
+        ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
+    }
     my $othertitle = &mt('All users');
     if ($env{'request.course.id'}) {
         $othertitle  = &mt('Any users');
@@ -10917,11 +10931,11 @@ sub check_for_upload {
                     if ($currsize < $filesize) {
                         my $extra = $filesize - $currsize;
                         if (($current_disk_usage + $extra) > $disk_quota) {
-                            my $msg = '<span class="LC_error">'.
+                            my $msg = '<p class="LC_warning">'.
                                       &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',
-                                          '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'.
-                                      '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
-                                                   $disk_quota,$current_disk_usage);
+                                          '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</p>'.
+                                      '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
+                                                   $disk_quota,$current_disk_usage).'</p>';
                             return ('will_exceed_quota',$msg);
                         }
                     }
@@ -10930,21 +10944,21 @@ sub check_for_upload {
         }
     }
     if (($current_disk_usage + $filesize) > $disk_quota){
-        my $msg = '<span class="LC_error">'.
-                &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.
-                  '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
+        my $msg = '<p class="LC_warning">'.
+                &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</p>'.
+                  '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'</p>';
         return ('will_exceed_quota',$msg);
     } elsif ($found_file) {
         if ($locked_file) {
-            my $msg = '<span class="LC_error">';
+            my $msg = '<p class="LC_warning">';
             $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>','<span class="LC_filename">'.$port_path.$env{'form.currentpath'}.'</span>');
-            $msg .= '</span><br />';
+            $msg .= '</p>';
             $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
             return ('file_locked',$msg);
         } else {
-            my $msg = '<span class="LC_error">';
+            my $msg = '<p class="LC_error">';
             $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});
-            $msg .= '</span>';
+            $msg .= '</p>';
             return ('existingfile',$msg);
         }
     }
@@ -11269,7 +11283,7 @@ sub decompress_uploaded_file {
 sub process_decompression {
     my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
     my ($dir,$error,$warning,$output);
-    if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) {
+    if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {
         $error = &mt('Filename not a supported archive file type.').
                  '<br />'.&mt('Filename should end with one of: [_1].',
                               '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
@@ -13660,6 +13674,12 @@ sub assign_category_rows {
     return $text;
 }
 
+=pod
+
+=back
+
+=cut
+
 ############################################################
 ############################################################
 
@@ -14679,36 +14699,535 @@ sub clean_symb {
     return ($symb,$enc);
 }
 
-sub build_release_hashes {
-    my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_;
-    return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') &&
-                  (ref($checkcrstypes) eq 'HASH') && (ref($anonsurvey) eq 'HASH') &&
-                  (ref($randomizetry) eq 'HASH'));
-    foreach my $key (keys(%Apache::lonnet::needsrelease)) {
-        my ($item,$name,$value) = split(/:/,$key);
-        if ($item eq 'parameter') {
-            if (ref($checkparms->{$name}) eq 'ARRAY') {
-                unless(grep(/^\Q$name\E$/,@{$checkparms->{$name}})) {
-                    push(@{$checkparms->{$name}},$value);
-                }
+############################################################
+############################################################
+
+=pod
+
+=head1 Routines for building display used to search for courses
+
+
+=over 4
+
+=item * &build_filters()
+
+Create markup for a table used to set filters to use when selecting
+courses in a domain.  Used by lonpickcourse.pm, lonmodifycourse.pm
+and quotacheck.pl
+
+
+Inputs:
+
+filterlist - anonymous array of fields to include as potential filters 
+
+crstype - course type
+
+roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used
+              to pop-open a course selector (will contain "extra element"). 
+
+multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1
+
+filter - anonymous hash of criteria and their values
+
+action - form action
+
+numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number)
+
+caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm)
+
+cloneruname - username of owner of new course who wants to clone
+
+clonerudom - domain of owner of new course who wants to clone
+
+typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community) 
+
+codetitlesref - reference to array of titles of components in institutional codes (official courses)
+
+codedom - domain
+
+formname - value of form element named "form". 
+
+fixeddom - domain, if fixed.
+
+prevphase - value to assign to form element named "phase" when going back to the previous screen  
+
+cnameelement - name of form element in form on opener page which will receive title of selected course 
+
+cnumelement - name of form element in form on opener page which will receive courseID  of selected course
+
+cdomelement - name of form element in form on opener page which will receive domain of selected course
+
+setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file
+
+clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course
+
+clonewarning - warning message about missing information for intended course owner when DC creates a course
+
+
+Returns: $output - HTML for display of search criteria, and hidden form elements.
+
+
+Side Effects: None
+
+=cut
+
+# ---------------------------------------------- search for courses based on last activity etc.
+
+sub build_filters {
+    my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action,
+        $numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement,
+        $codetitlesref,$codedom,$formname,$fixeddom,$prevphase,
+        $cnameelement,$cnumelement,$cdomelement,$setroles,
+        $clonetext,$clonewarning) = @_;
+    my ($list,$jscript);
+    my $onchange = 'javascript:updateFilters(this)';
+    my ($domainselectform,$sincefilterform,$createdfilterform,
+        $ownerdomselectform,$persondomselectform,$instcodeform,
+        $typeselectform,$instcodetitle);
+    if ($formname eq '') {
+        $formname = $caller;
+    }
+    foreach my $item (@{$filterlist}) {
+        unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') ||
+                ($item eq 'sincefilter') || ($item eq 'createdfilter')) {
+            if ($item eq 'domainfilter') {
+                $filter->{$item} = &LONCAPA::clean_domain($filter->{$item});
+            } elsif ($item eq 'coursefilter') {
+                $filter->{$item} = &LONCAPA::clean_courseid($filter->{$item});
+            } elsif ($item eq 'ownerfilter') {
+                $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
+            } elsif ($item eq 'ownerdomfilter') {
+                $filter->{'ownerdomfilter'} =
+                    &LONCAPA::clean_domain($filter->{$item});
+                $ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'},
+                                                       'ownerdomfilter',1);
+            } elsif ($item eq 'personfilter') {
+                $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
+            } elsif ($item eq 'persondomfilter') {
+                $persondomselectform = &select_dom_form($filter->{'persondomfilter'},
+                                                        'persondomfilter',1);
             } else {
-                push(@{$checkparms->{$name}},$value);
+                $filter->{$item} =~ s/\W//g;
             }
-        } elsif ($item eq 'resourcetag') {
-            if ($name eq 'responsetype') {
-                $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key}
+            if (!$filter->{$item}) {
+                $filter->{$item} = '';
             }
-        } elsif ($item eq 'course') {
-            if ($name eq 'crstype') {
-                $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key};
+        }
+        if ($item eq 'domainfilter') {
+            my $allow_blank = 1;
+            if ($formname eq 'portform') {
+                $allow_blank=0;
+            } elsif ($formname eq 'studentform') {
+                $allow_blank=0;
             }
+            if ($fixeddom) {
+                $domainselectform = '<input type="hidden" name="domainfilter"'.
+                                    ' value="'.$codedom.'" />'.
+                                    &Apache::lonnet::domain($codedom,'description');
+            } else {
+                $domainselectform = &select_dom_form($filter->{$item},
+                                                     'domainfilter',
+                                                      $allow_blank,'',$onchange);
+            }
+        } else {
+            $list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"');
+        }
+    }
+
+    # last course activity filter and selection
+    $sincefilterform = &timebased_select_form('sincefilter',$filter);
+
+    # course created filter and selection
+    if (exists($filter->{'createdfilter'})) {
+        $createdfilterform = &timebased_select_form('createdfilter',$filter);
+    }
+
+    my %lt = &Apache::lonlocal::texthash(
+                'cac' => "$crstype Activity",
+                'ccr' => "$crstype Created",
+                'cde' => "$crstype Title",
+                'cdo' => "$crstype Domain",
+                'ins' => 'Institutional Code',
+                'inc' => 'Institutional Categorization',
+                'cow' => "$crstype Owner/Co-owner",
+                'cop' => "$crstype Personnel Includes",
+                'cog' => 'Type',
+             );
+
+    if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
+        my $typeval = 'Course';
+        if ($crstype eq 'Community') {
+            $typeval = 'Community';
+        }
+        $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';
+    } else {
+        $typeselectform =  '<select name="type" size="1"';
+        if ($onchange) {
+            $typeselectform .= ' onchange="'.$onchange.'"';
+        }
+        $typeselectform .= '>'."\n";
+        foreach my $posstype ('Course','Community') {
+            $typeselectform.='<option value="'.$posstype.'"'.
+                ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n";
+        }
+        $typeselectform.="</select>";
+    }
+
+    my ($cloneableonlyform,$cloneabletitle);
+    if (exists($filter->{'cloneableonly'})) {
+        my $cloneableon = '';
+        my $cloneableoff = ' checked="checked"';
+        if ($filter->{'cloneableonly'}) {
+            $cloneableon = $cloneableoff;
+            $cloneableoff = '';
+        }
+        $cloneableonlyform = '<span class="LC_nobreak"><label><input type="radio" name="cloneableonly" value="1" '.$cloneableon.'/>&nbsp;'.&mt('Required').'</label>'.('&nbsp;'x3).'<label><input type="radio" name="cloneableonly" value="" '.$cloneableoff.' />&nbsp;'.&mt('No restriction').'</label></span>';
+        if ($formname eq 'ccrs') {
+            $cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom);
+        } else {
+            $cloneabletitle = &mt('Cloneable by you');
+        }
+    }
+    my $officialjs;
+    if ($crstype eq 'Course') {
+        if (exists($filter->{'instcodefilter'})) {
+#            if (($fixeddom) || ($formname eq 'requestcrs') ||
+#                ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {
+            if ($codedom) { 
+                $officialjs = 1;
+                ($instcodeform,$jscript,$$numtitlesref) =
+                    &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',
+                                                                  $officialjs,$codetitlesref);
+                if ($jscript) {
+                    $jscript = '<script type="text/javascript">'."\n".
+                               '// <![CDATA['."\n".
+                               $jscript."\n".
+                               '// ]]>'."\n".
+                               '</script>'."\n";
+                }
+            }
+            if ($instcodeform eq '') {
+                $instcodeform =
+                    '<input type="text" name="instcodefilter" size="10" value="'.
+                    $list->{'instcodefilter'}.'" />';
+                $instcodetitle = $lt{'ins'};
+            } else {
+                $instcodetitle = $lt{'inc'};
+            }
+            if ($fixeddom) {
+                $instcodetitle .= '<br />('.$codedom.')';
+            }
+        }
+    }
+    my $output = qq|
+<form method="post" name="filterpicker" action="$action">
+<input type="hidden" name="form" value="$formname" />
+|;
+    if ($formname eq 'modifycourse') {
+        $output .= '<input type="hidden" name="phase" value="courselist" />'."\n".
+                   '<input type="hidden" name="prevphase" value="'.
+                   $prevphase.'" />'."\n";
+    } elsif ($formname ne 'quotacheck') {
+        my $name_input;
+        if ($cnameelement ne '') {
+            $name_input = '<input type="hidden" name="cnameelement" value="'.
+                          $cnameelement.'" />';
+        }
+        $output .= qq|
+<input type="hidden" name="cnumelement" value="$cnumelement" />
+<input type="hidden" name="cdomelement" value="$cdomelement" />
+$name_input
+$roleelement
+$multelement
+$typeelement
+|;
+        if ($formname eq 'portform') {
+            $output .= '<input type="hidden" name="setroles" value="'.$setroles.'" />'."\n";
         }
     }
-    ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'});
-    ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'});
+    if ($fixeddom) {
+        $output .= '<input type="hidden" name="fixeddom" value="'.$fixeddom.'" />'."\n";
+    }
+    $output .= "<br />\n".&Apache::lonhtmlcommon::start_pick_box();
+    if ($sincefilterform) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'cac'})
+                  .$sincefilterform
+                  .&Apache::lonhtmlcommon::row_closure();
+    }
+    if ($createdfilterform) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'})
+                  .$createdfilterform
+                  .&Apache::lonhtmlcommon::row_closure();
+    }
+    if ($domainselectform) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'})
+                  .$domainselectform
+                  .&Apache::lonhtmlcommon::row_closure();
+    }
+    if ($typeselectform) {
+        if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
+            $output .= $typeselectform;
+        } else {
+            $output .= &Apache::lonhtmlcommon::row_title($lt{'cog'})
+                      .$typeselectform
+                      .&Apache::lonhtmlcommon::row_closure();
+        }
+    }
+    if ($instcodeform) {
+        $output .= &Apache::lonhtmlcommon::row_title($instcodetitle)
+                  .$instcodeform
+                  .&Apache::lonhtmlcommon::row_closure();
+    }
+    if (exists($filter->{'ownerfilter'})) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}).
+                   '<table><tr><td>'.&mt('Username').'<br />'.
+                   '<input type="text" name="ownerfilter" size="20" value="'.
+                   $list->{'ownerfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
+                   $ownerdomselectform.'</td></tr></table>'.
+                   &Apache::lonhtmlcommon::row_closure();
+    }
+    if (exists($filter->{'personfilter'})) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}).
+                   '<table><tr><td>'.&mt('Username').'<br />'.
+                   '<input type="text" name="personfilter" size="20" value="'.
+                   $list->{'personfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
+                   $persondomselectform.'</td></tr></table>'.
+                   &Apache::lonhtmlcommon::row_closure();
+    }
+    if (exists($filter->{'coursefilter'})) {
+        $output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID'))
+                  .'<input type="text" name="coursefilter" size="25" value="'
+                  .$list->{'coursefilter'}.'" />'
+                  .&Apache::lonhtmlcommon::row_closure();
+    }
+    if ($cloneableonlyform) {
+        $output .= &Apache::lonhtmlcommon::row_title($cloneabletitle).
+                   $cloneableonlyform.&Apache::lonhtmlcommon::row_closure();
+    }
+    if (exists($filter->{'descriptfilter'})) {
+        $output .= &Apache::lonhtmlcommon::row_title($lt{'cde'})
+                  .'<input type="text" name="descriptfilter" size="40" value="'
+                  .$list->{'descriptfilter'}.'" />'
+                  .&Apache::lonhtmlcommon::row_closure(1);
+    }
+    $output .= &Apache::lonhtmlcommon::end_pick_box().'<p>'.$clonetext."\n".
+               '<input type="hidden" name="updater" value="" />'."\n".
+               '<input type="submit" name="gosearch" value="'.
+               &mt('Search').'" /></p>'."\n".'</form>'."\n".'<hr />'."\n";
+    return $jscript.$clonewarning.$output;
+}
+
+=pod 
+
+=item * &timebased_select_form()
+
+Create markup for a dropdown list used to select a time-based
+filter e.g., Course Activity, Course Created, when searching for courses
+or communities
+
+Inputs:
+
+item - name of form element (sincefilter or createdfilter)
+
+filter - anonymous hash of criteria and their values
+
+Returns: HTML for a select box contained a blank, then six time selections,
+         with value set in incoming form variables currently selected. 
+
+Side Effects: None
+
+=cut
+
+sub timebased_select_form {
+    my ($item,$filter) = @_;
+    if (ref($filter) eq 'HASH') {
+        $filter->{$item} =~ s/[^\d-]//g;
+        if (!$filter->{$item}) { $filter->{$item}=-1; }
+        return &select_form(
+                            $filter->{$item},
+                            $item,
+                            {      '-1' => '',
+                                '86400' => &mt('today'),
+                               '604800' => &mt('last week'),
+                              '2592000' => &mt('last month'),
+                              '7776000' => &mt('last three months'),
+                             '15552000' => &mt('last six months'),
+                             '31104000' => &mt('last year'),
+                    'select_form_order' =>
+                           ['-1','86400','604800','2592000','7776000',
+                            '15552000','31104000']});
+    }
+}
+
+=pod
+
+=item * &js_changer()
+
+Create script tag containing Javascript used to submit course search form
+when course type or domain is changed, and also to hide 'Searching ...' on
+page load completion for page showing search result.
+
+Inputs: None
+
+Returns: markup containing updateFilters() and hideSearching() javascript functions. 
+
+Side Effects: None
+
+=cut
+
+sub js_changer {
+    return <<ENDJS;
+<script type="text/javascript">
+// <![CDATA[
+function updateFilters(caller) {
+    if (typeof(caller) != "undefined") {
+        document.filterpicker.updater.value = caller.name;
+    }
+    document.filterpicker.submit();
+}
+
+function hideSearching() {
+    if (document.getElementById('searching')) {
+        document.getElementById('searching').style.display = 'none';
+    }
     return;
 }
 
+// ]]>
+</script>
+
+ENDJS
+}
+
+=pod
+
+=item * &search_courses()
+
+Process selected filters form course search form and pass to lonnet::courseiddump
+to retrieve a hash for which keys are courseIDs which match the selected filters.
+
+Inputs:
+
+dom - domain being searched 
+
+type - course type ('Course' or 'Community' or '.' if any).
+
+filter - anonymous hash of criteria and their values
+
+numtitles - for institutional codes - number of categories
+
+cloneruname - optional username of new course owner
+
+clonerudom - optional domain of new course owner
+
+domcloner - Optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, 
+            (used when DC is using course creation form)
+
+codetitles - reference to array of titles of components in institutional codes (official courses).
+
+
+Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.
+
+
+Side Effects: None
+
+=cut
+
+
+sub search_courses {
+    my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_;
+    my (%courses,%showcourses,$cloner);
+    if (($filter->{'ownerfilter'} ne '') ||
+        ($filter->{'ownerdomfilter'} ne '')) {
+        $filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'.
+                                       $filter->{'ownerdomfilter'};
+    }
+    foreach my $item ('descriptfilter','coursefilter','combownerfilter') {
+        if (!$filter->{$item}) {
+            $filter->{$item}='.';
+        }
+    }
+    my $now = time;
+    my $timefilter =
+       ($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'});
+    my ($createdbefore,$createdafter);
+    if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) {
+        $createdbefore = $now;
+        $createdafter = $now-$filter->{'createdfilter'};
+    }
+    my ($instcodefilter,$regexpok);
+    if ($numtitles) {
+        if ($env{'form.official'} eq 'on') {
+            $instcodefilter =
+                &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
+            $regexpok = 1;
+        } elsif ($env{'form.official'} eq 'off') {
+            $instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
+            unless ($instcodefilter eq '') {
+                $regexpok = -1;
+            }
+        }
+    } else {
+        $instcodefilter = $filter->{'instcodefilter'};
+    }
+    if ($instcodefilter eq '') { $instcodefilter = '.'; }
+    if ($type eq '') { $type = '.'; }
+
+    if (($clonerudom ne '') && ($cloneruname ne '')) {
+        $cloner = $cloneruname.':'.$clonerudom;
+    }
+    %courses = &Apache::lonnet::courseiddump($dom,
+                                             $filter->{'descriptfilter'},
+                                             $timefilter,
+                                             $instcodefilter,
+                                             $filter->{'combownerfilter'},
+                                             $filter->{'coursefilter'},
+                                             undef,undef,$type,$regexpok,undef,undef,
+                                             undef,undef,$cloner,$env{'form.cc_clone'},
+                                             $filter->{'cloneableonly'},
+                                             $createdbefore,$createdafter,undef,
+                                             $domcloner);
+    if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) {
+        my $ccrole;
+        if ($type eq 'Community') {
+            $ccrole = 'co';
+        } else {
+            $ccrole = 'cc';
+        }
+        my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'},
+                                                     $filter->{'persondomfilter'},
+                                                     'userroles',undef,
+                                                     [$ccrole,'in','ad','ep','ta','cr'],
+                                                     $dom);
+        foreach my $role (keys(%rolehash)) {
+            my ($cnum,$cdom,$courserole) = split(':',$role);
+            my $cid = $cdom.'_'.$cnum;
+            if (exists($courses{$cid})) {
+                if (ref($courses{$cid}) eq 'HASH') {
+                    if (ref($courses{$cid}{roles}) eq 'ARRAY') {
+                        if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {
+                            push (@{$courses{$cid}{roles}},$courserole);
+                        }
+                    } else {
+                        $courses{$cid}{roles} = [$courserole];
+                    }
+                    $showcourses{$cid} = $courses{$cid};
+                }
+            }
+        }
+        %courses = %showcourses;
+    }
+    return %courses;
+}
+
+
+=pod
+
+=back
+
+=cut
+
+
 sub update_content_constraints {
     my ($cdom,$cnum,$chome,$cid) = @_;
     my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
@@ -15051,7 +15570,7 @@ sub check_recaptcha {
 }
 
 sub emailusername_info {
-    my @fields = ('lastname','firstname','institution','web','location','officialemail');
+    my @fields = ('firstname','lastname','institution','web','location','officialemail');
     my %titles = &Apache::lonlocal::texthash (
                      lastname      => 'Last Name',
                      firstname     => 'First Name',
@@ -15085,6 +15604,26 @@ sub cleanup_html {
     return $outgoing;
 }
 
+# Checks for critical messages and returns a redirect url if one exists.
+# $interval indicates how often to check for messages.
+sub critical_redirect {
+    my ($interval) = @_;
+    if ((time-$env{'user.criticalcheck.time'})>$interval) {
+        my @what=&Apache::lonnet::dump('critical', $env{'user.domain'}, 
+                                        $env{'user.name'});
+        &Apache::lonnet::appenv({'user.criticalcheck.time'=>time});
+        my $redirecturl;
+        if ($what[0]) {
+	    if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
+	        $redirecturl='/adm/email?critical=display';
+	        my $url=&Apache::lonnet::absolute_url().$redirecturl;
+                return (1, $url);
+            }
+        }
+    } 
+    return ();
+}
+
 # Use:
 #   my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
 #
@@ -15127,12 +15666,6 @@ sub des_decrypt {
     return $plaintext;
 }
 
-=pod
-
-=back
-
-=cut
-
 1;
 __END__;