--- loncom/interface/loncommon.pm	2012/07/07 21:58:14	1.1086
+++ loncom/interface/loncommon.pm	2013/05/10 16:09:58	1.1127
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1086 2012/07/07 21:58:14 raeburn Exp $
+# $Id: loncommon.pm,v 1.1127 2013/05/10 16:09:58 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -67,9 +67,14 @@ use Apache::lonhtmlcommon();
 use Apache::loncoursedata();
 use Apache::lontexconvert();
 use Apache::lonclonecourse();
+use Apache::lonuserutils();
+use Apache::lonuserstate();
 use LONCAPA qw(:DEFAULT :match);
 use DateTime::TimeZone;
 use DateTime::Locale::Catalog;
+use Text::Aspell;
+use Authen::Captcha;
+use Captcha::reCAPTCHA;
 
 # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);
@@ -154,6 +159,7 @@ sub ssi_with_retries {
 # ----------------------------------------------- Filetypes/Languages/Copyright
 my %language;
 my %supported_language;
+my %supported_codes;
 my %latex_language;		# For choosing hyphenation in <transl..>
 my %latex_language_bykey;	# for choosing hyphenation from metadata
 my %cprtag;
@@ -188,14 +194,15 @@ BEGIN {
             while (my $line = <$fh>) {
                 next if ($line=~/^\#/);
                 chomp($line);
-                my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
+                my ($key,$code,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
                 $language{$key}=$val.' - '.$enc;
                 if ($sup) {
                     $supported_language{$key}=$sup;
+		    $supported_codes{$key}   = $code;
                 }
 		if ($latex) {
 		    $latex_language_bykey{$key} = $latex;
-		    $latex_language{$two} = $latex;
+		    $latex_language{$code} = $latex;
 		}
             }
             close($fh);
@@ -524,7 +531,8 @@ ENDAUTHORBRW
 }
 
 sub coursebrowser_javascript {
-    my ($domainfilter,$sec_element,$formname,$role_element,$crstype) = @_;
+    my ($domainfilter,$sec_element,$formname,$role_element,$crstype,
+        $credits_element) = @_;
     my $wintitle = 'Course_Browser';
     if ($crstype eq 'Community') {
         $wintitle = 'Community_Browser';
@@ -587,8 +595,9 @@ sub coursebrowser_javascript {
     }
 $id_functions
 ENDSTDBRW
-    if (($sec_element ne '') || ($role_element ne '')) {
-        $output .= &setsec_javascript($sec_element,$formname,$role_element);
+    if (($sec_element ne '') || ($role_element ne '') || ($credits_element ne '')) {
+        $output .= &setsec_javascript($sec_element,$formname,$role_element,
+                                      $credits_element);
     }
     $output .= '
 // ]]>
@@ -657,7 +666,7 @@ if (!Array.prototype.indexOf) {
         var n = 0;
         if (arguments.length > 0) {
             n = Number(arguments[1]);
-            if (n !== n) { // shortcut for verifying if it's NaN
+            if (n !== n) { // shortcut for verifying if it is NaN
                 n = 0;
             } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
                 n = (n > 0 || -1) * Math.floor(Math.abs(n));
@@ -745,7 +754,7 @@ ENDUSERBRW
 }
 
 sub setsec_javascript {
-    my ($sec_element,$formname,$role_element) = @_;
+    my ($sec_element,$formname,$role_element,$credits_element) = @_;
     my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
         $communityrolestr);
     if ($role_element ne '') {
@@ -840,6 +849,14 @@ function setRole(crstype) {
 }
 |;
     }
+    if ($credits_element) {
+        $setsections .= qq|
+function setCredits(defaultcredits) {
+    document.$formname.$credits_element.value = defaultcredits;
+    return;
+}
+|;
+    }
     return $setsections;
 }
 
@@ -885,10 +902,14 @@ sub check_uncheck_jscript {
 function checkAll(field) {
     if (field.length > 0) {
         for (i = 0; i < field.length; i++) {
-            field[i].checked = true ;
+            if (!field[i].disabled) { 
+                field[i].checked = true;
+            }
         }
     } else {
-        field.checked = true
+        if (!field.disabled) { 
+            field.checked = true;
+        }
     }
 }
  
@@ -990,11 +1011,39 @@ sub select_language {
             $langchoices{$code} = &plainlanguagedescription($id);
         }
     }
+    %langchoices = &Apache::lonlocal::texthash(%langchoices);
     return &select_form($selected,$name,\%langchoices);
 }
 
 =pod
 
+
+=item * &list_languages()
+
+Returns an array reference that is suitable for use in language prompters.
+Each array element is itself a two element array.  The first element
+is the language code.  The second element a descsriptiuon of the 
+language itself.  This is suitable for use in e.g.
+&Apache::edit::select_arg (once dereferenced that is).
+
+=cut 
+
+sub list_languages {
+    my @lang_choices;
+
+    foreach my $id (&languageids()) {
+	my $code = &supportedlanguagecode($id);
+	if ($code) {
+	    my $selector    = $supported_codes{$id};
+	    my $description = &plainlanguagedescription($id);
+	    push (@lang_choices, [$selector, $description]);
+	}
+    }
+    return \@lang_choices;
+}
+
+=pod
+
 =item * &linked_select_forms(...)
 
 linked_select_forms returns a string containing a <script></script> block
@@ -1021,6 +1070,12 @@ linked_select_forms takes the following
 
 =item * $menuorder, the order of values in the first menu
 
+=item * $onchangefirst, additional javascript call to execute for an onchange
+        event for the first <select> tag
+
+=item * $onchangesecond, additional javascript call to execute for an onchange
+        event for the second <select> tag
+
 =back 
 
 Below is an example of such a hash.  Only the 'text', 'default', and 
@@ -1074,6 +1129,8 @@ sub linked_select_forms {
         $secondselectname, 
         $hashref,
         $menuorder,
+        $onchangefirst,
+        $onchangesecond
         ) = @_;
     my $second = "document.$formname.$secondselectname";
     my $first = "document.$formname.$firstselectname";
@@ -1130,7 +1187,7 @@ function select1_changed() {
 </script>
 END
     # output the initial values for the selection lists
-    $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
+    $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed();$onchangefirst\">\n";
     my @order = sort(keys(%{$hashref}));
     if (ref($menuorder) eq 'ARRAY') {
         @order = @{$menuorder};
@@ -1143,7 +1200,11 @@ END
     $result .= "</select>\n";
     my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
     $result .= $middletext;
-    $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
+    $result .= "<select size=\"1\" name=\"$secondselectname\"";
+    if ($onchangesecond) {
+        $result .= ' onchange="'.$onchangesecond.'"';
+    }
+    $result .= ">\n";
     my $seconddefault = $hashref->{$firstdefault}->{'default'};
     
     my @secondorder = sort(keys(%select2));
@@ -2130,7 +2191,7 @@ sub select_level_form {
 
 =pod
 
-=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms)
+=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms)
 
 Returns a string containing a <select name='$name' size='1'> form to 
 allow a user to select the domain to preform an operation in.  
@@ -2143,25 +2204,31 @@ If the $showdomdesc flag is set, the dom
 
 The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
 
-The optional $incdoms is a reference to an array of domains which will be the only available options. 
+The optional $incdoms is a reference to an array of domains which will be the only available options.
+
+The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
 
 =cut
 
 #-------------------------------------------
 sub select_dom_form {
-    my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms) = @_;
+    my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms) = @_;
     if ($onchange) {
         $onchange = ' onchange="'.$onchange.'"';
     }
-    my @domains;
+    my (@domains,%exclude);
     if (ref($incdoms) eq 'ARRAY') {
         @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
     } else {
         @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
     }
     if ($includeempty) { @domains=('',@domains); }
+    if (ref($excdoms) eq 'ARRAY') {
+        map { $exclude{$_} = 1; } @{$excdoms}; 
+    }
     my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
     foreach my $dom (@domains) {
+        next if ($exclude{$dom});
         $selectdomain.="<option value=\"$dom\" ".
             ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
         if ($showdomdesc) {
@@ -2475,7 +2542,7 @@ END
     return $result;
 }
 
-sub authform_authorwarning{
+sub authform_authorwarning {
     my $result='';
     $result='<i>'.
         &mt('As a general rule, only authors or co-authors should be '.
@@ -2484,16 +2551,16 @@ sub authform_authorwarning{
     return $result;
 }
 
-sub authform_nochange{  
+sub authform_nochange {
     my %in = (
               formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',
               @_,
           );
-    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'}); 
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     my $result;
-    if (keys(%can_assign) == 0) {
-        $result = &mt('Under you current role you are not permitted to change login settings for this user');  
+    if (!$authnum) {
+        $result = &mt('Under your current role you are not permitted to change login settings for this user');
     } else {
         $result = '<label>'.&mt('[_1] Do not change login data',
                   '<input type="radio" name="login" value="nochange" '.
@@ -2513,7 +2580,7 @@ sub authform_kerberos {
               );
     my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
         $autharg,$jscall);
-    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if ($in{'kerb_def_auth'} eq 'krb5') {
        $check5 = ' checked="checked"';
     } else {
@@ -2563,7 +2630,7 @@ sub authform_kerberos {
         if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {
-                    $authtype = '<input type="hidden" name="login" value="krb" />';
+                    $authtype = '<input type="radio" name="login" value="krb" />';
                 }
             }
         }
@@ -2575,9 +2642,9 @@ sub authform_kerberos {
                     $krbcheck.' />';
     }
     if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
-        ($can_assign{'krb4'} && !$can_assign{'krb5'} && 
+        ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb5') ||
-        (!$can_assign{'krb4'} && $can_assign{'krb5'} && 
+        (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb4')) {
         $result .= &mt
         ('[_1] Kerberos authenticated with domain [_2] '.
@@ -2613,14 +2680,14 @@ sub authform_kerberos {
     return $result;
 }
 
-sub authform_internal{  
+sub authform_internal {
     my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
                 );
     my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
-    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'int') {
             if ($can_assign{'int'}) {
@@ -2649,7 +2716,7 @@ sub authform_internal{
         if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {
-                    $authtype = '<input type="hidden" name="login" value="int" />';
+                    $authtype = '<input type="radio" name="login" value="int" />';
                 }
             }
         }
@@ -2668,14 +2735,14 @@ sub authform_internal{
     return $result;
 }
 
-sub authform_local{  
+sub authform_local {
     my %in = (
               formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',
               @_,
               );
     my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
-    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'loc') {
             if ($can_assign{'loc'}) {
@@ -2704,7 +2771,7 @@ sub authform_local{
         if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {
-                    $authtype = '<input type="hidden" name="login" value="loc" />';
+                    $authtype = '<input type="radio" name="login" value="loc" />';
                 }
             }
         }
@@ -2722,14 +2789,14 @@ sub authform_local{
     return $result;
 }
 
-sub authform_filesystem{  
+sub authform_filesystem {
     my %in = (
               formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',
               @_,
               );
     my ($fsyscheck,$result,$authtype,$autharg,$jscall);
-    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'fsys') {
             if ($can_assign{'fsys'}) {
@@ -2755,7 +2822,7 @@ sub authform_filesystem{
         if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {
-                    $authtype = '<input type="hidden" name="login" value="fsys" />';
+                    $authtype = '<input type="radio" name="login" value="fsys" />';
                 }
             }
         }
@@ -2986,13 +3053,77 @@ sub get_related_words {
     untie %thesaurus_db;
     return @Words;
 }
+###############################################################
+#
+#  Spell checking
+#
 
 =pod
 
+=head1 Spell checking
+
+=over 4
+
+=item * &check_spelling($wordlist $language)
+
+Takes a string containing words and feeds it to an external
+spellcheck program via a pipeline. Returns a string containing
+them mis-spelled words.
+
+Parameters:
+
+=over 4
+
+=item - $wordlist
+
+String that will be fed into the spellcheck program.
+
+=item - $language
+
+Language string that specifies the language for which the spell
+check will be performed.
+
 =back
 
+=back
+
+Note: This sub assumes that aspell is installed.
+
+
 =cut
 
+
+=pod
+
+=back
+
+=cut
+
+sub check_spelling {
+    my ($wordlist, $language) = @_;
+    my @misspellings;
+    
+    # Generate the speller and set the langauge.
+    # if explicitly selected:
+
+    my $speller = Text::Aspell->new;
+    if ($language) {
+	$speller->set_option('lang', $language);
+    }
+
+    # Turn the word list into an array of words by splittingon whitespace
+
+    my @words = split(/\s+/, $wordlist);
+
+    foreach my $word (@words) {
+	if(! $speller->check($word)) {
+	    push(@misspellings, $word);
+	}
+    }
+    return join(' ', @misspellings);
+    
+}
+
 # -------------------------------------------------------------- Plaintext name
 =pod
 
@@ -3226,7 +3357,7 @@ sub aboutmewrapper {
     if (!defined($username)  && !defined($domain)) {
         return;
     }
-    return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.
+    return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
 	($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
 }
 
@@ -4879,7 +5010,7 @@ sub CSTR_pageheader {
 
     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
     my ($udom,$uname,$thisdisfn)=
-        ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)/(.*)$});
+        ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$});
     my $formaction = "/priv/$udom/$uname/$thisdisfn";
     $formaction =~ s{/+}{/}g;
 
@@ -4960,6 +5091,10 @@ Inputs:
                               should it have jsmath forced on by the
                               current page
 
+=item * $advtoolsref, optional argument, ref to an array containing
+            inlineremote items to be added in "Functions" menu below
+            breadcrumbs.
+
 =back
 
 Returns: A uniform header for LON-CAPA web pages.  
@@ -4971,7 +5106,7 @@ other decorations will be returned.
 
 sub bodytag {
     my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
-        $no_nav_bar,$bgcolor,$args)=@_;
+        $no_nav_bar,$bgcolor,$args,$advtoolsref)=@_;
 
     my $public;
     if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
@@ -5090,8 +5225,15 @@ sub bodytag {
             if ($env{'request.state'} eq 'construct') {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,
                                 $args->{'bread_crumbs'});
-            } elsif ($forcereg) { 
-                $bodytag .= &Apache::lonmenu::innerregister($forcereg);
+            } elsif ($forcereg) {
+                $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
+                                                            $args->{'group'});
+            } else {
+                $bodytag .= 
+                    &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
+                                                        $forcereg,$args->{'group'},
+                                                        $args->{'bread_crumbs'},
+                                                        $advtoolsref);
             }
         }else{
             # this is to seperate menu from content when there's no secondary
@@ -5306,10 +5448,12 @@ form, .inline {
 
 .LC_error {
   color: red;
-  font-size: larger;
 }
 
-.LC_warning,
+.LC_warning {
+  color: darkorange;
+}
+
 .LC_diff_removed {
   color: red;
 }
@@ -5472,11 +5616,11 @@ td.LC_table_cell_checkbox {
   text-align: left;
 }
 
-.LC_head_subbox {
+.LC_head_subbox, .LC_actionbox {
   clear:both;
   background: #F8F8F8; /* $sidebg; */
   border: 1px solid $sidebg;
-  margin: 0 0 10px 0;      
+  margin: 0 0 10px 0;
   padding: 3px;
   text-align: left;
 }
@@ -5609,7 +5753,8 @@ table.LC_nested tr.LC_empty_row td {
   padding: 8px;
 }
 
-table.LC_data_table tr.LC_empty_row td {
+table.LC_data_table tr.LC_empty_row td,
+table.LC_data_table tr.LC_footer_row td {
   background-color: $sidebg;
 }
 
@@ -6171,7 +6316,6 @@ div.LC_docs_entry_move {
 
 table.LC_data_table tr > td.LC_docs_entry_commands,
 table.LC_data_table tr > td.LC_docs_entry_parameter {
-  background: #DDDDDD;
   font-size: x-small;
 }
 
@@ -6336,6 +6480,11 @@ div.LC_edit_problem_saves {
   padding-bottom: 5px;
 }
 
+.LC_edit_opt {
+  padding-left: 1em;
+  white-space: nowrap;
+}
+
 img.stift {
   border-width: 0;
   vertical-align: middle;
@@ -6544,7 +6693,7 @@ ol.LC_docs_parameters li.LC_docs_paramet
 }
 
 ul#LC_secondary_menu {
-  clear: both;
+  clear: right;
   color: $fontmenu;
   background: $tabbg;
   list-style: none;
@@ -6552,15 +6701,52 @@ ul#LC_secondary_menu {
   margin: 0;
   width: 100%;
   text-align: left;
+  float: left;
 }
 
 ul#LC_secondary_menu li {
   font-weight: bold;
   line-height: 1.8em;
+  border-right: 1px solid black;
+  float: left;
+}
+
+ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
+  background-color: $data_table_light;
+}
+
+ul#LC_secondary_menu li a {
   padding: 0 0.8em;
+}
+
+ul#LC_secondary_menu li ul {
+  display: none;
+}
+
+ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
+  display: block;
+  position: absolute;
+  margin: 0;
+  padding: 0;
+  list-style:none;
+  float: none;
+  background-color: $data_table_light;
+  z-index: 2;
+  margin-left: -1px;
+}
+
+ul#LC_secondary_menu li ul li {
+  font-size: 90%;
+  vertical-align: top;
+  border-left: 1px solid black;
   border-right: 1px solid black;
-  display: inline;
-  vertical-align: middle;
+  background-color: $data_table_light;
+  list-style:none;
+  float: none;
+}
+
+ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
+  background-color: $data_table_dark;
 }
 
 ul.LC_TabContent {
@@ -7007,6 +7193,27 @@ ul.LC_funclist li {
 		cursor:pointer;
 }
 
+/*
+  styles used by TTH when "Default set of options to pass to tth/m
+  when converting TeX" in course settings has been set
+
+  option passed: -t
+
+*/
+
+td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
+td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
+td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
+td div.norm {line-height:normal;}
+
+/*
+  option passed -y3
+*/
+
+span.roman {font-family: serif; font-style: normal; font-weight: normal;}
+span.overacc2 {position: relative;  left: .8em; top: -1.2ex;}
+span.overacc1 {position: relative;  left: .6em; top: -1.2ex;}
+
 END
 }
 
@@ -7276,6 +7483,8 @@ $args - additional optional args support
                                     current page
              bread_crumbs ->             Array containing breadcrumbs
              bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs
+             group          -> includes the current group, if page is for a 
+                               specific group  
 
 =back
 
@@ -7288,7 +7497,7 @@ sub start_page {
     #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
 
     $env{'internal.start_page'}++;
-    my $result;
+    my ($result,@advtools);
 
     if (! exists($args->{'skip_phases'}{'head'}) ) {
         $result .= &xml_begin() . &headtag($title, $head_extra, $args);
@@ -7305,7 +7514,8 @@ sub start_page {
                          $args->{'function'},       $args->{'add_entries'},
                          $args->{'only_body'},      $args->{'domain'},
                          $args->{'force_register'}, $args->{'no_nav_bar'},
-                         $args->{'bgcolor'},        $args);
+                         $args->{'bgcolor'},        $args,
+                         \@advtools);
         }
     }
 
@@ -7334,6 +7544,10 @@ sub start_page {
 				&Apache::lonhtmlcommon::add_breadcrumb($crumb);
 			}
 		}
+                # if @advtools array contains items add then to the breadcrumbs
+                if (@advtools > 0) {
+                    &Apache::lonmenu::advtools_crumbs(@advtools);
+                }
 
 		#if bread_crumbs_component exists show it as headline else show only the breadcrumbs
 		if(exists($args->{'bread_crumbs_component'})){
@@ -7729,7 +7943,7 @@ sub simple_error_page {
     my ($r,$title,$msg) = @_;
     my $page =
 	&Apache::loncommon::start_page($title).
-	&mt($msg).
+	'<p class="LC_error">'.&mt($msg).'</p>'.
 	&Apache::loncommon::end_page();
     if (ref($r)) {
 	$r->print($page);
@@ -8022,7 +8236,19 @@ sub get_sections {
     my %sectioncount;
     my $now = time;
 
-    if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
+    my $check_students = 1;
+    my $only_students = 0;
+    if (ref($possible_roles) eq 'ARRAY') {
+        if (grep(/^st$/,@{$possible_roles})) {
+            if (@{$possible_roles} == 1) {
+                $only_students = 1;
+            }
+        } else {
+            $check_students = 0;
+        }
+    }
+
+    if ($check_students) { 
 	my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
 	my $sec_index = &Apache::loncoursedata::CL_SECTION();
 	my $status_index = &Apache::loncoursedata::CL_STATUS();
@@ -8049,6 +8275,9 @@ sub get_sections {
 	    }
 	}
     }
+    if ($only_students) {
+        return %sectioncount;
+    }
     my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
     foreach my $user (sort(keys(%courseroles))) {
 	if ($user !~ /^(\w{2})/) { next; }
@@ -8196,7 +8425,7 @@ sub get_course_users {
                               active   => 'Active',
                               future   => 'Future',
                             );
-        my %nothide;
+        my (%nothide,@possdoms);
         if ($hidepriv) {
             my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
             foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
@@ -8206,6 +8435,10 @@ sub get_course_users {
                     $nothide{$user} = 1;
                 }
             }
+            my @possdoms = ($cdom);
+            if ($coursehash{'checkforpriv'}) {
+                push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
+            }
         }
         foreach my $person (sort(keys(%coursepersonnel))) {
             my $match = 0;
@@ -8241,7 +8474,7 @@ sub get_course_users {
                 }
                 if ($uname ne '' && $udom ne '') {
                     if ($hidepriv) {
-                        if ((&Apache::lonnet::privileged($uname,$udom)) &&
+                        if ((&Apache::lonnet::privileged($uname,$udom,\@possdoms)) &&
                             (!$nothide{$uname.':'.$udom})) {
                             next;
                         }
@@ -8846,7 +9079,10 @@ sub user_rule_formats {
     my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
     if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
         if (@{$ruleorder} > 0) {
-            $output = '<br />'.&mt("$text{$check} with the following format(s) may <span class=\"LC_cusr_emph\">only</span> be used for verified users at [_1]:",$domdesc).' <ul>';
+            $output = '<br />'.
+                      &mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:',
+                          '<span class="LC_cusr_emph">','</span>',$domdesc).
+                      ' <ul>';
             foreach my $rule (@{$ruleorder}) {
                 if (ref($curr_rules) eq 'ARRAY') {
                     if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
@@ -9329,18 +9565,23 @@ sub ask_for_embedded_content {
     my $heading = &mt('Upload embedded files');
     my $buttontext = &mt('Upload');
 
-    my $navmap;
+    my ($navmap,$cdom,$cnum);
     if ($env{'request.course.id'}) {
-        $navmap = Apache::lonnavmaps::navmap->new();
+        if ($actionurl eq '/adm/dependencies') {
+            $navmap = Apache::lonnavmaps::navmap->new();
+        }
+        $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     }
-    if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
+    if (($actionurl eq '/adm/portfolio') || 
+        ($actionurl eq '/adm/coursegrp_portfolio')) {
         my $current_path='/';
         if ($env{'form.currentpath'}) {
             $current_path = $env{'form.currentpath'};
         }
         if ($actionurl eq '/adm/coursegrp_portfolio') {
-            $udom = $env{'course.'.$env{'request.course.id'}.'.domain'};
-            $uname = $env{'course.'.$env{'request.course.id'}.'.num'};
+            $udom = $cdom;
+            $uname = $cnum;
             $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';
         } else {
             $udom = $env{'user.domain'};
@@ -9372,24 +9613,42 @@ sub ask_for_embedded_content {
         }
     } elsif ($actionurl eq '/adm/dependencies')  {
         if ($env{'request.course.id'} ne '') {
-            $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
-            $cnum =  $env{'course.'.$env{'request.course.id'}.'.num'};
             if (ref($args) eq 'HASH') {
                 $url = $args->{'docs_url'};
                 $title = $args->{'docs_title'};
-                $toplevel = "/$url";
+                $toplevel = $url; 
+                unless ($toplevel =~ m{^/}) {
+                    $toplevel = "/$url";
+                }
                 ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
-                ($path) =  
-                    ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
+                if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
+                    $path = $1;
+                } else {
+                    ($path) =
+                        ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
+                }
                 $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                 $fileloc =~ s{^/}{};
                 ($filename) = ($fileloc =~ m{.+/([^/]+)$});
                 $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
             }
         }
-    }
-    my $now = time();
-    foreach my $embed_file (keys(%{$allfiles})) {
+    } elsif ($actionurl eq "/public/$cdom/$cnum/syllabus") {
+        $udom = $cdom;
+        $uname = $cnum;
+        $url = "/uploaded/$cdom/$cnum/portfolio/syllabus";
+        $toplevel = $url;
+        $path = $url;
+        $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
+        $fileloc =~ s{^/}{};
+    }
+    foreach my $file (keys(%{$allfiles})) {
+        my $embed_file;
+        if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
+            $embed_file = $1;
+        } else {
+            $embed_file = $file;
+        }
         my $absolutepath;
         if ($embed_file =~ m{^\w+://}) {
             $newfiles{$embed_file} = 1;
@@ -9427,7 +9686,8 @@ sub ask_for_embedded_content {
     my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {
         $currsubfile{$path} = {};
-        if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { 
+        if (($actionurl eq '/adm/portfolio') || 
+            ($actionurl eq '/adm/coursegrp_portfolio')) {
             my ($sublistref,$listerror) =
                 &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
             if (ref($sublistref) eq 'ARRAY') {
@@ -9443,9 +9703,15 @@ sub ask_for_embedded_content {
             }
         } elsif (($actionurl eq '/adm/dependencies') ||
                  (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
-                  ($args->{'context'} eq 'paste'))) {
+                  ($args->{'context'} eq 'paste')) ||
+                 ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
             if ($env{'request.course.id'} ne '') {
-                my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
+                my $dir;
+                if ($actionurl eq "/public/$cdom/$cnum/syllabus") {
+                    $dir = $fileloc;
+                } else {
+                    ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
+                }
                 if ($dir ne '') {
                     my ($sublistref,$listerror) =
                         &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
@@ -9493,7 +9759,8 @@ sub ask_for_embedded_content {
         }
     }
     my %currfile;
-    if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
+    if (($actionurl eq '/adm/portfolio') ||
+        ($actionurl eq '/adm/coursegrp_portfolio')) {
         my ($dirlistref,$listerror) =
             &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
         if (ref($dirlistref) eq 'ARRAY') {
@@ -9509,7 +9776,8 @@ sub ask_for_embedded_content {
         }
     } elsif (($actionurl eq '/adm/dependencies') ||
              (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
-              ($args->{'context'} eq 'paste'))) {
+              ($args->{'context'} eq 'paste')) ||
+             ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
         if ($env{'request.course.id'} ne '') {
             my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
             if ($dir ne '') {
@@ -9544,12 +9812,14 @@ sub ask_for_embedded_content {
                 ($file eq $filename.'.bak') ||
                 ($dependencies{$file})) {
             if ($actionurl eq '/adm/dependencies') {
-                next if (($rem ne '') &&
-                         (($env{"httpref.$rem".$file} ne '') ||
-                          (ref($navmap) &&
-                          (($navmap->getResourceByUrl($rem.$file) ne '') ||
-                           (($file =~ /^(.*\.s?html?)\.bak$/i) &&
-                            ($navmap->getResourceByUrl($rem.$1)))))));
+                unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
+                    next if (($rem ne '') &&
+                             (($env{"httpref.$rem".$file} ne '') ||
+                              (ref($navmap) &&
+                              (($navmap->getResourceByUrl($rem.$file) ne '') ||
+                               (($file =~ /^(.*\.s?html?)\.bak$/i) &&
+                                ($navmap->getResourceByUrl($rem.$1)))))));
+                }
             }
             $unused{$file} = 1;
         }
@@ -9558,28 +9828,38 @@ sub ask_for_embedded_content {
         ($args->{'context'} eq 'paste')) {
         $counter = scalar(keys(%existing));
         $numpathchg = scalar(keys(%pathchanges));
-        return ($output,$counter,$numpathchg,\%existing); 
+        return ($output,$counter,$numpathchg,\%existing);
+    } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && 
+             (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {
+        $counter = scalar(keys(%existing));
+        $numpathchg = scalar(keys(%pathchanges));
+        return ($output,$counter,$numpathchg,\%existing,\%mapping);
     }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
         if ($actionurl eq '/adm/dependencies') {
             next if ($embed_file =~ m{^\w+://});
         }
         $upload_output .= &start_data_table_row().
-                          '<td><img src="'.&icon($embed_file).'" />&nbsp;'.
+                          '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
                           '<span class="LC_filename">'.$embed_file.'</span>';
         unless ($mapping{$embed_file} eq $embed_file) {
-            $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
+            $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.
+                              &mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
         }
-        $upload_output .= '</td><td>';
+        $upload_output .= '</td>';
         if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { 
-            $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
+            $upload_output.='<td align="right">'.
+                            '<span class="LC_info LC_fontsize_medium">'.
+                            &mt("URL points to web address").'</span>';
             $numremref++;
         } elsif ($args->{'error_on_invalid_names'}
             && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
-            $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';
+            $upload_output.='<td align="right"><span class="LC_warning">'.
+                            &mt('Invalid characters').'</span>';
             $numinvalid++;
         } else {
-            $upload_output .= &embedded_file_element('upload_embedded',$counter,
+            $upload_output .= '<td>'.
+                              &embedded_file_element('upload_embedded',$counter,
                                                      $embed_file,\%mapping,
                                                      $allfiles,$codebase,'upload');
             $counter ++;
@@ -9608,8 +9888,9 @@ sub ask_for_embedded_content {
             $counter ++;
         } else {
             $upload_output .= &start_data_table_row().
-                              '<td><span class="LC_filename">'.$embed_file.'</span></td>';
-                              '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.
+                              '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
+                              '<span class="LC_filename">'.$embed_file.'</span></td>'.
+                              '<td align="right"><span class="LC_info LC_fontsize_medium">'.&mt('Already exists').'</span></td>'.
                               &Apache::loncommon::end_data_table_row()."\n";
         }
     }
@@ -9704,7 +9985,7 @@ sub ask_for_embedded_content {
         $output = '<b>'.&mt('Referenced files').'</b>:<br />';
         if ($applies > 1) {
             $output .=  
-                &mt('No files need to be uploaded, as one of the following applies to each reference:').'<ul>';
+                &mt('No dependencies need to be uploaded, as one of the following applies to each reference:').'<ul>';
             if ($numremref) {
                 $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";
             }
@@ -9747,7 +10028,7 @@ sub ask_for_embedded_content {
             $chgcount ++;
         }
     }
-    if ($counter) {
+    if (($counter) || ($numunused)) {
         if ($numpathchg) {
             $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
                        $numpathchg.'" />'."\n";
@@ -9760,13 +10041,13 @@ sub ask_for_embedded_content {
         } elsif ($actionurl eq '/adm/dependencies') {
             $output .= '<input type="hidden" name="action" value="process_changes" />';
         }
-        $output .=  '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
+        $output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
     } elsif ($numpathchg) {
         my %pathchange = ();
         $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
             $output .= '<p>'.&mt('or').'</p>'; 
-        } 
+        }
     }
     return ($output,$counter,$numpathchg);
 }
@@ -9902,21 +10183,23 @@ sub upload_embedded {
             $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />';
             next;
         } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
-            $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
+            $output .= &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
             next;
         }
         $env{'form.embedded_item_'.$i.'.filename'}=$fname;
+        my $subdir = $path;
+        $subdir =~ s{/+$}{};
         if ($context eq 'portfolio') {
             my $result;
             if ($state eq 'existingfile') {
                 $result=
                     &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',
-                                                    $dirpath.$env{'form.currentpath'}.$path);
+                                                    $dirpath.$env{'form.currentpath'}.$subdir);
             } else {
                 $result=
                     &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
                                                     $dirpath.
-                                                    $env{'form.currentpath'}.$path);
+                                                    $env{'form.currentpath'}.$subdir);
                 if ($result !~ m|^/uploaded/|) {
                     $output .= '<span class="LC_error">'
                                .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
@@ -9928,10 +10211,11 @@ sub upload_embedded {
                                $path.$fname.'</span>').'<br />';     
                 }
             }
-        } elsif ($context eq 'coursedoc') {
+        } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {
+            my $extendedsubdir = $dirpath.'/'.$subdir;
+            $extendedsubdir =~ s{/+$}{};
             my $result =
-                &Apache::lonnet::userfileupload('embedded_item_'.$i,'coursedoc',
-                                                $dirpath.'/'.$path);
+                &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir);
             if ($result !~ m|^/uploaded/|) {
                 $output .= '<span class="LC_error">'
                            .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
@@ -9941,6 +10225,9 @@ sub upload_embedded {
             } else {
                 $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
                            $path.$fname.'</span>').'<br />';
+                if ($context eq 'syllabus') {
+                    &Apache::lonnet::make_public_indefinitely($result);
+                }
             }
         } else {
 # Save the file
@@ -10072,7 +10359,7 @@ sub modify_html_form {
 }
 
 sub modify_html_refs {
-    my ($context,$dirpath,$uname,$udom,$dir_root) = @_;
+    my ($context,$dirpath,$uname,$udom,$dir_root,$url) = @_;
     my $container;
     if ($context eq 'portfolio') {
         $container = $env{'form.container'};
@@ -10081,12 +10368,14 @@ sub modify_html_refs {
     } elsif ($context eq 'manage_dependencies') {
         (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
         $container = "/$container";
+    } elsif ($context eq 'syllabus') {
+        $container = $url;
     } else {
         $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
     }
     my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');
-    unless (@changes > 0) {
+    unless ((@changes > 0) || ($context eq 'syllabus')) {
         if (wantarray) {
             return ('',0,0); 
         } else {
@@ -10094,7 +10383,7 @@ sub modify_html_refs {
         }
     }
     if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
-        ($context eq 'manage_dependencies')) {
+        ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
         unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
             if (wantarray) {
                 return ('',0,0);
@@ -10150,6 +10439,7 @@ sub modify_html_refs {
                     if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
                         my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
                         $count += $numchg;
+                        $allfiles{$newname} = $allfiles{$ref};
                     }
                     if ($env{'form.embedded_codebase_'.$i} ne '') {
                         $codebase = &unescape($env{'form.embedded_codebase_'.$i});
@@ -10158,10 +10448,11 @@ sub modify_html_refs {
                     }
                 }
             }
+            my $skiprewrites;
             if ($count || $codebasecount) {
                 my $saveresult;
                 if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
-                    ($context eq 'manage_dependencies')) {
+                    ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
                     my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
                     if ($url eq $container) {
                         my ($fname) = ($container =~ m{/([^/]+)$});
@@ -10174,6 +10465,11 @@ sub modify_html_refs {
                                    '<span class="LC_filename">'.
                                    $container.'</span>').'</p>';
                     }
+                    if ($context eq 'syllabus') {
+                        unless ($saveresult eq 'ok') {
+                            $skiprewrites = 1;
+                        }
+                    }
                 } else {
                     if (open(my $fh,">$container")) {
                         print $fh $content;
@@ -10189,6 +10485,47 @@ sub modify_html_refs {
                     }
                 }
             }
+            if (($context eq 'syllabus') && (!$skiprewrites)) {
+                my ($actionurl,$state);
+                $actionurl = "/public/$udom/$uname/syllabus";
+                my ($ignore,$num,$numpathchanges,$existing,$mapping) =
+                    &ask_for_embedded_content($actionurl,$state,\%allfiles,
+                                              \%codebase,
+                                              {'context' => 'rewrites',
+                                               'ignore_remote_references' => 1,});
+                if (ref($mapping) eq 'HASH') {
+                    my $rewrites = 0;
+                    foreach my $key (keys(%{$mapping})) {
+                        next if ($key =~ m{^https?://});
+                        my $ref = $mapping->{$key};
+                        my $newname = "/uploaded/$udom/$uname/portfolio/syllabus/$key";
+                        my $attrib;
+                        if (ref($allfiles{$mapping->{$key}}) eq 'ARRAY') {
+                            $attrib = join('|',@{$allfiles{$mapping->{$key}}});
+                        }
+                        if ($content =~ m{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
+                            my $numchg = ($content =~ s{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
+                            $rewrites += $numchg;
+                        }
+                    }
+                    if ($rewrites) {
+                        my $saveresult; 
+                        my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
+                        if ($url eq $container) {
+                            my ($fname) = ($container =~ m{/([^/]+)$});
+                            $output .= '<p>'.&mt('Rewrote [quant,_1,link] as [quant,_1,absolute link] in [_2].',
+                                            $count,'<span class="LC_filename">'.
+                                            $fname.'</span>').'</p>';
+                        } else {
+                            $output .= '<p class="LC_error">'.
+                                       &mt('Error: could not update links in [_1].',
+                                       '<span class="LC_filename">'.
+                                       $container.'</span>').'</p>';
+
+                        }
+                    }
+                }
+            }
         } else {
             &logthis('Failed to parse '.$container.
                      ' to modify references: '.$parse_result);
@@ -10604,8 +10941,8 @@ 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)$/) {
-        $error = &mt('File name not a supported archive file type.').
-                 '<br />'.&mt('File name should end with one of: [_1].',
+        $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');
     } else {
         my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
@@ -11179,11 +11516,11 @@ sub process_extracted_files {
     if ($env{'form.folderpath'}) {
         my @items = split('&',$env{'form.folderpath'});
         $folders{'0'} = $items[-2];
-        $containers{'0'}='sequence';
-    } elsif ($env{'form.pagepath'}) {
-        my @items = split('&',$env{'form.pagepath'});
-        $folders{'0'} = $items[-2];
-        $containers{'0'}='page';
+        if ($env{'form.folderpath'} =~ /\:1$/) {
+            $containers{'0'}='page';
+        } else {  
+            $containers{'0'}='sequence';
+        }
     }
     my @archdirs = &get_env_multiple('form.archive_directory');
     if ($numitems) {
@@ -11258,7 +11595,7 @@ sub process_extracted_files {
                             my ($outtext,$errtext) =
                                 &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                         $docuname.'/'.$folders{$outer}.
-                                                        '.'.$containers{$outer},1);
+                                                        '.'.$containers{$outer},1,1);
                             $newseqid{$i} = $newidx;
                             unless ($errtext) {
                                 $result .=  '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
@@ -11291,7 +11628,7 @@ sub process_extracted_files {
                             my ($outtext,$errtext)=
                                 &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                         $docuname.'/'.$folders{$outer}.
-                                                        '.'.$containers{$outer},1);
+                                                        '.'.$containers{$outer},1,1);
                             unless ($errtext) {
                                 if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
                                     $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
@@ -11444,7 +11781,7 @@ sub cleanup_empty_dirs {
             my $numitems = 0;
             foreach my $item (@dircontents) {
                 if (-d "$path/$item") {
-                    &recurse_dirs("$path/$item");
+                    &cleanup_empty_dirs("$path/$item");
                     if (-e "$path/$item") {
                         $numitems ++;
                     }
@@ -12993,7 +13330,7 @@ sub commit_customrole {
 }
 
 sub commit_standardrole {
-    my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
+    my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_;
     my ($output,$logmsg,$linefeed);
     if ($context eq 'auto') {
         $linefeed = "\n";
@@ -13002,7 +13339,7 @@ sub commit_standardrole {
     }  
     if ($three eq 'st') {
         my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
-                                         $one,$two,$sec,$context);
+                                         $one,$two,$sec,$context,$credits);
         if (($result =~ /^error/) || ($result eq 'not_in_class') || 
             ($result eq 'unknown_course') || ($result eq 'refused')) {
             $output = $logmsg.' '.&mt('Error: ').$result."\n"; 
@@ -13033,7 +13370,8 @@ sub commit_standardrole {
 }
 
 sub commit_studentrole {
-    my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
+    my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,
+        $credits) = @_;
     my ($result,$linefeed,$oldsecurl,$newsecurl);
     if ($context eq 'auto') {
         $linefeed = "\n";
@@ -13080,7 +13418,11 @@ sub commit_studentrole {
             }
         }
         if (($expire_role_result eq 'ok') || ($secchange == 0)) {
-            $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);
+            $modify_section_result = 
+                &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,
+                                                           undef,undef,undef,$sec,
+                                                           $end,$start,'','',$cid,
+                                                           '',$context,$credits);
             if ($modify_section_result =~ /^ok/) {
                 if ($secchange == 1) {
                     if ($sec eq '') {
@@ -13102,7 +13444,7 @@ sub commit_studentrole {
                     }
                 }
             } else {
-                if ($secchange) {       
+                if ($secchange) { 
                     $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed;
                 } else {
                     $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
@@ -13111,7 +13453,7 @@ sub commit_studentrole {
             $result = $modify_section_result;
         } elsif ($secchange == 1) {
             if ($oldsec eq '') {
-                $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
+                $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_2] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
             } else {
                 $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;
             }
@@ -13137,6 +13479,26 @@ sub commit_studentrole {
     return $result;
 }
 
+sub show_role_extent {
+    my ($scope,$context,$role) = @_;
+    $scope =~ s{^/}{};
+    my @courseroles = &Apache::lonuserutils::roles_by_context('course',1);
+    push(@courseroles,'co');
+    my @authorroles = &Apache::lonuserutils::roles_by_context('author');
+    if (($context eq 'course') || (grep(/^\Q$role\E/,@courseroles))) {
+        $scope =~ s{/}{_};
+        return '<span class="LC_cusr_emph">'.$env{'course.'.$scope.'.description'}.'</span>';
+    } elsif (($context eq 'author') || (grep(/^\Q$role\E/,@authorroles))) {
+        my ($audom,$auname) = split(/\//,$scope);
+        return &mt('[_1] Author Space','<span class="LC_cusr_emph">'.
+                   &Apache::loncommon::plainname($auname,$audom).'</span>');
+    } else {
+        $scope =~ s{/$}{};
+        return &mt('Domain: [_1]','<span class="LC_cusr_emph">'.
+                   &Apache::lonnet::domain($scope,'description').'</span>');
+    }
+}
+
 ############################################################
 ############################################################
 
@@ -13300,6 +13662,7 @@ sub construct_course {
                    'pch.users.denied',
                    'plc.users.denied',
                    'hidefromcat',
+                   'checkforpriv',
                    'categories'],
                    $$crsudom,$$crsunum);
     }
@@ -13329,6 +13692,9 @@ sub construct_course {
     } else {
         $cenv{'internal.courseowner'} = $args->{'curruser'};
     }
+    if ($args->{'defaultcredits'}) {
+        $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
+    }
     my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
     if ($args->{'crssections'}) {
         $cenv{'internal.sectionnums'} = '';
@@ -13353,6 +13719,11 @@ sub construct_course {
 # do not hide course coordinator from staff listing, 
 # even if privileged
     $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
+# add course coordinator's domain to domains to check for privileged users
+# if different to course domain
+    if ($$crsudom ne $args->{'ccdomain'}) {
+        $cenv{'checkforpriv'} = $args->{'ccdomain'};
+    }
 # add crosslistings
     if ($args->{'crsxlist'}) {
         $cenv{'internal.crosslistings'}='';
@@ -13778,6 +14149,20 @@ sub init_user_environment {
                                                   \%userenv,\%domdef,\%is_adv);
         }
 
+        $userenv{'canrequest.author'} =
+            &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
+                                        'reload','requestauthor',
+                                        \%userenv,\%domdef,\%is_adv);
+        my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],
+                                             $domain,$username);
+        my $reqstatus = $reqauthor{'author_status'};
+        if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { 
+            if (ref($reqauthor{'author'}) eq 'HASH') {
+                $userenv{'requestauthorqueued'} = $reqstatus.':'.
+                                                  $reqauthor{'author'}{'timestamp'};
+            }
+        }
+
 	$env{'user.environment'} = "$lonids/$cookie.id";
 
 	if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
@@ -13929,6 +14314,32 @@ sub update_content_constraints {
     return;
 }
 
+sub allmaps_incourse {
+    my ($cdom,$cnum,$chome,$cid) = @_;
+    if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') {
+        $cid = $env{'request.course.id'};
+        $cdom = $env{'course.'.$cid.'.domain'};
+        $cnum = $env{'course.'.$cid.'.num'};
+        $chome = $env{'course.'.$cid.'.home'};
+    }
+    my %allmaps = ();
+    my $lastchange =
+        &Apache::lonnet::get_coursechange($cdom,$cnum);
+    if ($lastchange > $env{'request.course.tied'}) {
+        my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
+        unless ($ferr) {
+            &update_content_constraints($cdom,$cnum,$chome,$cid);
+        }
+    }
+    my $navmap = Apache::lonnavmaps::navmap->new();
+    if (defined($navmap)) {
+        foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) {
+            $allmaps{$res->src()} = 1;
+        }
+    }
+    return \%allmaps;
+}
+
 sub parse_supplemental_title {
     my ($title) = @_;
 
@@ -13952,6 +14363,232 @@ sub parse_supplemental_title {
     return $title;
 }
 
+sub symb_to_docspath {
+    my ($symb) = @_;
+    return unless ($symb);
+    my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
+    if ($resurl=~/\.(sequence|page)$/) {
+        $mapurl=$resurl;
+    } elsif ($resurl eq 'adm/navmaps') {
+        $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
+    }
+    my $mapresobj;
+    my $navmap = Apache::lonnavmaps::navmap->new();
+    if (ref($navmap)) {
+        $mapresobj = $navmap->getResourceByUrl($mapurl);
+    }
+    $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
+    my $type=$2;
+    my $path;
+    if (ref($mapresobj)) {
+        my $pcslist = $mapresobj->map_hierarchy();
+        if ($pcslist ne '') {
+            foreach my $pc (split(/,/,$pcslist)) {
+                next if ($pc <= 1);
+                my $res = $navmap->getByMapPc($pc);
+                if (ref($res)) {
+                    my $thisurl = $res->src();
+                    $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
+                    my $thistitle = $res->title();
+                    $path .= '&'.
+                             &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
+                             &Apache::lonhtmlcommon::entity_encode($thistitle).
+                             ':'.$res->randompick().
+                             ':'.$res->randomout().
+                             ':'.$res->encrypted().
+                             ':'.$res->randomorder().
+                             ':'.$res->is_page();
+                }
+            }
+        }
+        $path =~ s/^\&//;
+        my $maptitle = $mapresobj->title();
+        if ($mapurl eq 'default') {
+            $maptitle = 'Main Course Documents';
+        }
+        $path .= (($path ne '')? '&' : '').
+                 &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
+                 &Apache::lonhtmlcommon::entity_encode($maptitle).
+                 ':'.$mapresobj->randompick().
+                 ':'.$mapresobj->randomout().
+                 ':'.$mapresobj->encrypted().
+                 ':'.$mapresobj->randomorder().
+                 ':'.$mapresobj->is_page();
+    } else {
+        my $maptitle = &Apache::lonnet::gettitle($mapurl);
+        my $ispage = (($type eq 'page')? 1 : '');
+        if ($mapurl eq 'default') {
+            $maptitle = 'Main Course Documents';
+        }
+        $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
+                &Apache::lonhtmlcommon::entity_encode($maptitle).':::::'.$ispage;
+    }
+    unless ($mapurl eq 'default') {
+        $path = 'default&'.
+                &Apache::lonhtmlcommon::entity_encode('Main Course Documents').
+                ':::::&'.$path;
+    }
+    return $path;
+}
+
+sub captcha_display {
+    my ($context,$lonhost) = @_;
+    my ($output,$error);
+    my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
+    if ($captcha eq 'original') {
+        $output = &create_captcha();
+        unless ($output) {
+            $error = 'captcha'; 
+        }
+    } elsif ($captcha eq 'recaptcha') {
+        $output = &create_recaptcha($pubkey);
+        unless ($output) {
+            $error = 'recaptcha'; 
+        }
+    }
+    return ($output,$error);
+}
+
+sub captcha_response {
+    my ($context,$lonhost) = @_;
+    my ($captcha_chk,$captcha_error);
+    my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
+    if ($captcha eq 'original') {
+        ($captcha_chk,$captcha_error) = &check_captcha();
+    } elsif ($captcha eq 'recaptcha') {
+        $captcha_chk = &check_recaptcha($privkey);
+    } else {
+        $captcha_chk = 1;
+    }
+    return ($captcha_chk,$captcha_error);
+}
+
+sub get_captcha_config {
+    my ($context,$lonhost) = @_;
+    my ($captcha,$pubkey,$privkey,$hashtocheck);
+    my $hostname = &Apache::lonnet::hostname($lonhost);
+    my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
+    my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
+    if ($context eq 'usercreation') {
+        my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom);
+        if (ref($domconfig{$context}) eq 'HASH') {
+            $hashtocheck = $domconfig{$context}{'cancreate'};
+            if (ref($hashtocheck) eq 'HASH') {
+                if ($hashtocheck->{'captcha'} eq 'recaptcha') {
+                    if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') {
+                        $pubkey = $hashtocheck->{'recaptchakeys'}{'public'};
+                        $privkey = $hashtocheck->{'recaptchakeys'}{'private'};
+                    }
+                    if ($privkey && $pubkey) {
+                        $captcha = 'recaptcha';
+                    } else {
+                        $captcha = 'original';
+                    }
+                } elsif ($hashtocheck->{'captcha'} ne 'notused') {
+                    $captcha = 'original';
+                }
+            }
+        } else {
+            $captcha = 'captcha';
+        }
+    } elsif ($context eq 'login') {
+        my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom);
+        if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') {
+            $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'};
+            $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
+            if ($privkey && $pubkey) {
+                $captcha = 'recaptcha';
+            } else {
+                $captcha = 'original';
+            }
+        } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
+            $captcha = 'original';
+        }
+    }
+    return ($captcha,$pubkey,$privkey);
+}
+
+sub create_captcha {
+    my %captcha_params = &captcha_settings();
+    my ($output,$maxtries,$tries) = ('',10,0);
+    while ($tries < $maxtries) {
+        $tries ++;
+        my $captcha = Authen::Captcha->new (
+                                           output_folder => $captcha_params{'output_dir'},
+                                           data_folder   => $captcha_params{'db_dir'},
+                                          );
+        my $md5sum = $captcha->generate_code($captcha_params{'numchars'});
+
+        if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
+            $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
+                      &mt('Type in the letters/numbers shown below').'&nbsp;'.
+                     '<input type="text" size="5" name="code" value="" /><br />'.
+                     '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" />';
+            last;
+        }
+    }
+    return $output;
+}
+
+sub captcha_settings {
+    my %captcha_params = (
+                           output_dir     => $Apache::lonnet::perlvar{'lonCaptchaDir'},
+                           www_output_dir => "/captchaspool",
+                           db_dir         => $Apache::lonnet::perlvar{'lonCaptchaDb'},
+                           numchars       => '5',
+                         );
+    return %captcha_params;
+}
+
+sub check_captcha {
+    my ($captcha_chk,$captcha_error);
+    my $code = $env{'form.code'};
+    my $md5sum = $env{'form.crypt'};
+    my %captcha_params = &captcha_settings();
+    my $captcha = Authen::Captcha->new(
+                      output_folder => $captcha_params{'output_dir'},
+                      data_folder   => $captcha_params{'db_dir'},
+                  );
+    $captcha_chk = $captcha->check_code($code,$md5sum);
+    my %captcha_hash = (
+                        0       => 'Code not checked (file error)',
+                       -1      => 'Failed: code expired',
+                       -2      => 'Failed: invalid code (not in database)',
+                       -3      => 'Failed: invalid code (code does not match crypt)',
+    );
+    if ($captcha_chk != 1) {
+        $captcha_error = $captcha_hash{$captcha_chk}
+    }
+    return ($captcha_chk,$captcha_error);
+}
+
+sub create_recaptcha {
+    my ($pubkey) = @_;
+    my $captcha = Captcha::reCAPTCHA->new;
+    return $captcha->get_options_setter({theme => 'white'})."\n".
+           $captcha->get_html($pubkey).
+           &mt('If either word is hard to read, [_1] will replace them.',
+               '<image src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
+           '<br /><br />';
+}
+
+sub check_recaptcha {
+    my ($privkey) = @_;
+    my $captcha_chk;
+    my $captcha = Captcha::reCAPTCHA->new;
+    my $captcha_result =
+        $captcha->check_answer(
+                                $privkey,
+                                $ENV{'REMOTE_ADDR'},
+                                $env{'form.recaptcha_challenge_field'},
+                                $env{'form.recaptcha_response_field'},
+                              );
+    if ($captcha_result->{is_valid}) {
+        $captcha_chk = 1;
+    }
+    return $captcha_chk;
+}
+
 =pod
 
 =back