--- loncom/interface/loncommon.pm	2007/08/31 17:58:47	1.577
+++ loncom/interface/loncommon.pm	2008/02/01 23:03:13	1.639
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.577 2007/08/31 17:58:47 raeburn Exp $
+# $Id: loncommon.pm,v 1.639 2008/02/01 23:03:13 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -257,6 +257,7 @@ sub browser_and_searcher_javascript {
         }
         url += 'catalogmode=interactive&';
         url += 'mode=$mode&';
+        url += 'inhibitmenu=yes&';
         url += 'form=' + formname + '&';
         if (only != null) {
             url += 'only=' + only + '&';
@@ -367,7 +368,7 @@ sub selectstudent_link {
 	   return '';
        }
        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
-        '","'.$udomele.'","","1");'."'>".&mt('Select User')."</a>";
+        '","'.$udomele.'");'."'>".&mt('Select User')."</a>";
    }
    if ($env{'request.role'}=~/^(au|dc|su)/) {
        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
@@ -407,7 +408,7 @@ sub coursebrowser_javascript {
 	                            '&cdomelement='+udom+
                                     '&cnameelement='+desc;
         if (extra_element !=null && extra_element != '') {
-            if (formname == 'rolechoice') {
+            if (formname == 'rolechoice' || formname == 'studentform') {
                 url += '&roleelement='+extra_element;
                 if (domainfilter == null || domainfilter == '') {
                     url += '&domainfilter='+extra_element;
@@ -471,7 +472,10 @@ sub setsec_javascript {
     my ($sec_element,$formname) = @_;
     my $setsections = qq|
 function setSect(sectionlist) {
-    var sectionsArray = sectionlist.split(",");
+    var sectionsArray = new Array();
+    if ((sectionlist != '') && (typeof sectionlist != "undefined")) {
+        sectionsArray = sectionlist.split(",");
+    }
     var numSections = sectionsArray.length;
     document.$formname.$sec_element.length = 0;
     if (numSections == 0) {
@@ -544,7 +548,7 @@ linked_select_forms returns a string con
 and html for two <select> menus.  The select menus will be linked in that
 changing the value of the first menu will result in new values being placed
 in the second menu.  The values in the select menu will appear in alphabetical
-order.
+order unless a defined order is provided.
 
 linked_select_forms takes the following ordered inputs:
 
@@ -562,6 +566,8 @@ linked_select_forms takes the following
 
 =item * $hashref, a reference to a hash containing the data for the menus.
 
+=item * $menuorder, the order of values in the first menu
+
 =back 
 
 Below is an example of such a hash.  Only the 'text', 'default', and 
@@ -578,7 +584,8 @@ $menu{$choice1}->{'select2'}.
                            B2 => "Choice B2",
                            B3 => "Choice B3",
                            B4 => "Choice B4"
-                           }
+                           },
+                       order => ['B4','B3','B1','B2'],
                    },
                A2 => { text =>"Choice A2" ,
                        default => "C2",
@@ -586,7 +593,8 @@ $menu{$choice1}->{'select2'}.
                            C1 => "Choice C1",
                            C2 => "Choice C2",
                            C3 => "Choice C3"
-                           }
+                           },
+                       order => ['C2','C1','C3'],
                    },
                A3 => { text =>"Choice A3" ,
                        default => "D6",
@@ -598,7 +606,8 @@ $menu{$choice1}->{'select2'}.
                            D5 => "Choice D5",
                            D6 => "Choice D6",
                            D7 => "Choice D7"
-                           }
+                           },
+                       order => ['D4','D3','D2','D1','D7','D6','D5'],
                    }
                );
 
@@ -610,7 +619,8 @@ sub linked_select_forms {
         $firstdefault,
         $firstselectname,
         $secondselectname, 
-        $hashref
+        $hashref,
+        $menuorder,
         ) = @_;
     my $second = "document.$formname.$secondselectname";
     my $first = "document.$formname.$firstselectname";
@@ -624,8 +634,11 @@ sub linked_select_forms {
         $result.="select2data.d_$s1 = new Object();\n";        
         $result.="select2data.d_$s1.def = new String('".
             $hashref->{$s1}->{'default'}."');\n";
-        $result.="select2data.d_$s1.values = new Array(";        
+        $result.="select2data.d_$s1.values = new Array(";
         my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
+        if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
+            @s2values = @{$hashref->{$s1}->{'order'}};
+        }
         $result.="\"@s2values\");\n";
         $result.="select2data.d_$s1.texts = new Array(";        
         my @s2texts;
@@ -663,7 +676,11 @@ function select1_changed() {
 END
     # output the initial values for the selection lists
     $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
-    foreach my $value (sort(keys(%$hashref))) {
+    my @order = sort(keys(%{$hashref}));
+    if (ref($menuorder) eq 'ARRAY') {
+        @order = @{$menuorder};
+    }
+    foreach my $value (@order) {
         $result.="    <option value=\"$value\" ";
         $result.=" selected=\"selected\" " if ($value eq $firstdefault);
         $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
@@ -673,7 +690,12 @@ END
     $result .= $middletext;
     $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
     my $seconddefault = $hashref->{$firstdefault}->{'default'};
-    foreach my $value (sort(keys(%select2))) {
+    
+    my @secondorder = sort(keys(%select2));
+    if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') {
+        @secondorder = @{$hashref->{$firstdefault}->{'order'}};
+    }
+    foreach my $value (@secondorder) {
         $result.="    <option value=\"$value\" ";        
         $result.=" selected=\"selected\" " if ($value eq $seconddefault);
         $result.=">".&mt($select2{$value})."</option>\n";
@@ -760,10 +782,10 @@ sub helpLatexCheatsheet {
     }
     return '<table><tr><td>'.
 	$addOther .
-	&Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
+	&Apache::loncommon::help_open_topic("Greek_Symbols",&mt('Greek Symbols'),
 					    undef,undef,600)
 	.'</td><td>'.
-	&Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
+	&Apache::loncommon::help_open_topic("Other_Symbols",&mt('Other Symbols'),
 					    undef,undef,600)
 	.'</td></tr></table>';
 }
@@ -860,7 +882,7 @@ sub help_menu_js {
 					'js_ready'    => 1,
 					'add_entries' => {
 					    'border' => '0',
-					    'rows'   => "105,*",},});
+					    'rows'   => "110,*",},});
     my $end_page =
         &Apache::loncommon::end_page({'frameset' => 1,
 				      'js_ready' => 1,});
@@ -1074,6 +1096,77 @@ sub changable_area {
 
 =pod
 
+=item * viewport_geometry_js {
+
+Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
+
+=cut
+
+
+sub viewport_geometry_js { 
+    return <<"GEOMETRY";
+var Geometry = {};
+function init_geometry() {
+    if (Geometry.init) { return };
+    Geometry.init=1;
+    if (window.innerHeight) {
+        Geometry.getViewportHeight   = function() { return window.innerHeight; };
+        Geometry.getViewportWidth   = function() { return window.innerWidth; };
+        Geometry.getHorizontalScroll = function() { return window.pageXOffset; };
+        Geometry.getVerticalScroll   = function() { return window.pageYOffset; };
+    }
+    else if (document.documentElement && document.documentElement.clientHeight) {
+        Geometry.getViewportHeight =
+            function() { return document.documentElement.clientHeight; };
+        Geometry.getViewportWidth =
+            function() { return document.documentElement.clientWidth; };
+
+        Geometry.getHorizontalScroll =
+            function() { return document.documentElement.scrollLeft; };
+        Geometry.getVerticalScroll =
+            function() { return document.documentElement.scrollTop; };
+    }
+    else if (document.body.clientHeight) {
+        Geometry.getViewportHeight =
+            function() { return document.body.clientHeight; };
+        Geometry.getViewportWidth =
+            function() { return document.body.clientWidth; };
+        Geometry.getHorizontalScroll =
+            function() { return document.body.scrollLeft; };
+        Geometry.getVerticalScroll =
+            function() { return document.body.scrollTop; };
+    }
+}
+
+GEOMETRY
+}
+
+=pod
+
+=item * viewport_size_js {
+
+Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window. 
+
+=cut
+
+sub viewport_size_js {
+    my $geometry = &viewport_geometry_js();
+    return <<"DIMS";
+
+$geometry
+
+function getViewportDims(width,height) {
+    init_geometry();
+    width.value = Geometry.getViewportWidth();
+    height.value = Geometry.getViewportHeight();
+    return;
+}
+
+DIMS
+}
+
+=pod
+
 =item * resize_textarea_js
 
 emits the needed javascript to resize a textarea to be as big as possible
@@ -1087,37 +1180,41 @@ to be attached to the <body> for the onl
 =cut
 
 sub resize_textarea_js {
+    my $geometry = &viewport_geometry_js();
     return <<"RESIZE";
     <script type="text/javascript">
-var Geometry = {};
-function init_geometry() {
-    if (Geometry.init) { return };
-    Geometry.init=1;
-    if (window.innerHeight) {
-	Geometry.getViewportHeight = function() { return window.innerHeight; };
-    }
-    else if (document.documentElement && document.documentElement.clientHeight) {
-	Geometry.getViewportHeight = 
-	    function() { return document.documentElement.clientHeight; };
-    }
-    else if (document.body.clientHeight) {
-	Geometry.getViewportHeight = 
-	    function() { return document.body.clientHeight; };
+$geometry
+
+function getX(element) {
+    var x = 0;
+    while (element) {
+	x += element.offsetLeft;
+	element = element.offsetParent;
+    }
+    return x;
+}
+function getY(element) {
+    var y = 0;
+    while (element) {
+	y += element.offsetTop;
+	element = element.offsetParent;
     }
+    return y;
 }
 
+
 function resize_textarea(textarea_id,bottom_id) {
     init_geometry();
     var textarea        = document.getElementById(textarea_id);
     //alert(textarea);
 
-    var textarea_top    = textarea.offsetTop;
+    var textarea_top    = getY(textarea);
     var textarea_height = textarea.offsetHeight;
     var bottom          = document.getElementById(bottom_id);
-    var bottom_top      = bottom.offsetTop;
+    var bottom_top      = getY(bottom);
     var bottom_height   = bottom.offsetHeight;
     var window_height   = Geometry.getViewportHeight();
-    var fudge           = 23; 
+    var fudge           = 23;
     var new_height      = window_height-fudge-textarea_top-bottom_height;
     if (new_height < 300) {
 	new_height = 300;
@@ -1332,8 +1429,6 @@ sub domain_select {
 
 =over 4
 
-=cut
-
 =item * multiple_select_form($name,$value,$size,$hash,$order)
 
 Returns a string containing a <select> element int multiple mode
@@ -1511,24 +1606,68 @@ sub select_dom_form {
 
 =pod
 
-=item * home_server_option_list($domain)
+=item * home_server_form_item($domain,$name,$defaultflag)
+
+input: 4 arguments (two required, two optional) - 
+    $domain - domain of new user
+    $name - name of form element
+    $default - Value of 'default' causes a default item to be first 
+                            option, and selected by default. 
+    $hide - Value of 'hide' causes hiding of the name of the server, 
+                            if 1 server found, or default, if 0 found.
+output: returns 2 items: 
+(a) form element which contains either:
+   (i) <select name="$name">
+        <option value="$hostid1">$hostid $servers{$hostid}</option>
+        <option value="$hostid2">$hostid $servers{$hostid}</option>       
+       </select>
+       form item if there are multiple library servers in $domain, or
+   (ii) an <input type="hidden" name="$name" value="$hostid" /> form item 
+       if there is only one library server in $domain.
 
-returns a string which contains an <option> list to be used in a 
-<select> form input.  See loncreateuser.pm for an example.
+(b) number of library servers found.
+
+See loncreateuser.pm for example of use.
 
 =cut
 
 #-------------------------------------------
-sub home_server_option_list {
-    my $domain = shift;
+sub home_server_form_item {
+    my ($domain,$name,$default,$hide) = @_;
     my %servers = &Apache::lonnet::get_servers($domain,'library');
-    my $result = '';
-    foreach my $hostid (sort(keys(%servers))) {
-        $result.=
-            '<option value="'.$hostid.'">'.
-	    $hostid.' '.$servers{$hostid}."</option>\n";
+    my $result;
+    my $numlib = keys(%servers);
+    if ($numlib > 1) {
+        $result .= '<select name="'.$name.'" />'."\n";
+        if ($default) {
+            $result .= '<option value="default" selected>'.&mt('default').
+                       '</option>'."\n";
+        }
+        foreach my $hostid (sort(keys(%servers))) {
+            $result.= '<option value="'.$hostid.'">'.
+	              $hostid.' '.$servers{$hostid}."</option>\n";
+        }
+        $result .= '</select>'."\n";
+    } elsif ($numlib == 1) {
+        my $hostid;
+        foreach my $item (keys(%servers)) {
+            $hostid = $item;
+        }
+        $result .= '<input type="hidden" name="'.$name.'" value="'.
+                   $hostid.'" />';
+                   if (!$hide) {
+                       $result .= $hostid.' '.$servers{$hostid};
+                   }
+                   $result .= "\n";
+    } elsif ($default) {
+        $result .= '<input type="hidden" name="'.$name.
+                   '" value="default" />';
+                   if (!$hide) {
+                       $result .= &mt('default');
+                   }
+                   $result .= "\n";
     }
-    return $result;
+    return ($result,$numlib);
 }
 
 =pod
@@ -1681,19 +1820,16 @@ END
     }
 
     my $radioval = "'nochange'";
-    if (exists($in{'curr_authtype'}) &&
-        defined($in{'curr_authtype'}) &&
-        $in{'curr_authtype'} ne '') {
-        $radioval = "'$in{'curr_authtype'}arg'";
+    if (defined($in{'curr_authtype'})) {
+        if ($in{'curr_authtype'} ne '') {
+            $radioval = "'".$in{'curr_authtype'}."arg'";
+        }
     }
     my $argfield = 'null';
-    if ( grep/^mode$/,(keys %in) ) {
+    if (defined($in{'mode'})) {
         if ($in{'mode'} eq 'modifycourse')  {
-            if ( grep/^curr_authtype$/,(keys %in) ) {
-                $radioval = "'$in{'curr_authtype'}'";
-            }
-            if ( grep/^curr_autharg$/,(keys %in) ) {
-                unless ($in{'curr_autharg'} eq '') {
+            if (defined($in{'curr_autharg'})) {
+                if ($in{'curr_autharg'} ne '') {
                     $argfield = "'$in{'curr_autharg'}'";
                 }
             }
@@ -1776,79 +1912,181 @@ sub authform_nochange{
               kerb_def_dom => 'MSU.EDU',
               @_,
           );
-    my $result = '<label>'.&mt('[_1] Do not change login data',
-                     '<input type="radio" name="login" value="nochange" '.
-                     'checked="checked" onclick="'.
+    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');  
+    } else {
+        $result = '<label>'.&mt('[_1] Do not change login data',
+                  '<input type="radio" name="login" value="nochange" '.
+                  'checked="checked" onclick="'.
             "javascript:changed_radio('nochange',$in{'formname'});".'" />').
 	    '</label>';
+    }
     return $result;
 }
 
-sub authform_kerberos{  
+sub authform_kerberos {
     my %in = (
               formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',
               kerb_def_auth => 'krb4',
               @_,
               );
-    my ($check4,$check5,$krbarg);
+    my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
+        $autharg,$jscall);
+    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
     if ($in{'kerb_def_auth'} eq 'krb5') {
-       $check5 = " checked=\"on\"";
+       $check5 = ' checked="on"';
     } else {
-       $check4 = " checked=\"on\"";
+       $check4 = ' checked="on"';
     }
     $krbarg = $in{'kerb_def_dom'};
-
-    my $krbcheck = "";
-    if ( grep/^curr_authtype$/,(keys %in) ) {
-        if ($in{'curr_authtype'} =~ m/^krb/) {
-            $krbcheck = " checked=\"on\"";
-            if ( grep/^curr_autharg$/,(keys %in) ) {
+    if (defined($in{'curr_authtype'})) {
+        if ($in{'curr_authtype'} eq 'krb') {
+            $krbcheck = ' checked="on"';
+            if (defined($in{'mode'})) {
+                if ($in{'mode'} eq 'modifyuser') {
+                    $krbcheck = '';
+                }
+            }
+            if (defined($in{'curr_kerb_ver'})) {
+                if ($in{'curr_krb_ver'} eq '5') {
+                    $check5 = ' checked="on"';
+                    $check4 = '';
+                } else {
+                    $check4 = ' checked="on"';
+                    $check5 = '';
+                }
+            }
+            if (defined($in{'curr_autharg'})) {
                 $krbarg = $in{'curr_autharg'};
             }
+            if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
+                if (defined($in{'curr_autharg'})) {
+                    $result = 
+    &mt('Currently Kerberos authenticated with domain [_1] Version [_2].',
+        $in{'curr_autharg'},$krbver);
+                } else {
+                    $result =
+    &mt('Currently Kerberos authenticated, Version [_1].',$krbver);
+                }
+                return $result; 
+            }
+        }
+    } else {
+        if ($authnum == 1) {
+            $authtype = '<input type="hidden" name="login" value="krb">';
         }
     }
-
-    my $jscall = "javascript:changed_radio('krb',$in{'formname'});";
-    my $result .= &mt
+    if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
+        return;
+    } elsif ($authtype eq '') {
+        if (defined($in{'mode'})) {
+            if ($in{'mode'} eq 'modifycourse') {
+                if ($authnum == 1) {
+                    $authtype = '<input type="hidden" name="login" value="krb">';
+                }
+            }
+        }
+    }
+    $jscall = "javascript:changed_radio('krb',$in{'formname'});";
+    if ($authtype eq '') {
+        $authtype = '<input type="radio" name="login" value="krb" '.
+                    'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
+                    $krbcheck.' />';
+    }
+    if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
+        ($can_assign{'krb4'} && !$can_assign{'krb5'} && 
+         $in{'curr_authtype'} eq 'krb5') ||
+        (!$can_assign{'krb4'} && $can_assign{'krb5'} && 
+         $in{'curr_authtype'} eq 'krb4')) {
+        $result .= &mt
         ('[_1] Kerberos authenticated with domain [_2] '.
          '[_3] Version 4 [_4] Version 5 [_5]',
-         '<label><input type="radio" name="login" value="krb" '.
-             'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />',
+         '<label>'.$authtype,
          '</label><input type="text" size="10" name="krbarg" '.
              'value="'.$krbarg.'" '.
              'onchange="'.$jscall.'" />',
          '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
          '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
 	 '</label>');
+    } elsif ($can_assign{'krb4'}) {
+        $result .= &mt
+        ('[_1] Kerberos authenticated with domain [_2] '.
+         '[_3] Version 4 [_4]',
+         '<label>'.$authtype,
+         '</label><input type="text" size="10" name="krbarg" '.
+             'value="'.$krbarg.'" '.
+             'onchange="'.$jscall.'" />',
+         '<label><input type="hidden" name="krbver" value="4" />',
+         '</label>');
+    } elsif ($can_assign{'krb5'}) {
+        $result .= &mt
+        ('[_1] Kerberos authenticated with domain [_2] '.
+         '[_3] Version 5 [_4]',
+         '<label>'.$authtype,
+         '</label><input type="text" size="10" name="krbarg" '.
+             'value="'.$krbarg.'" '.
+             'onchange="'.$jscall.'" />',
+         '<label><input type="hidden" name="krbver" value="5" />',
+         '</label>');
+    }
     return $result;
 }
 
 sub authform_internal{  
-    my %args = (
+    my %in = (
                 formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',
                 @_,
                 );
-
-    my $intcheck = "";
-    my $intarg = 'value=""';
-    if ( grep/^curr_authtype$/,(keys %args) ) {
-        if ($args{'curr_authtype'} eq 'int') {
-            $intcheck = " checked=\"on\"";
-            if ( grep/^curr_autharg$/,(keys %args) ) {
-                $intarg = "value=\"$args{'curr_autharg'}\"";
+    my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
+    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    if (defined($in{'curr_authtype'})) {
+        if ($in{'curr_authtype'} eq 'int') {
+            if ($can_assign{'int'}) {
+                $intcheck = 'checked="on" ';
+                if (defined($in{'mode'})) {
+                    if ($in{'mode'} eq 'modifyuser') {
+                        $intcheck = '';
+                    }
+                }
+                if (defined($in{'curr_autharg'})) {
+                    $intarg = $in{'curr_autharg'};
+                }
+            } else {
+                $result = &mt('Currently internally authenticated.');
+                return $result;
             }
         }
+    } else {
+        if ($authnum == 1) {
+            $authtype = '<input type="hidden" name="login" value="int">';
+        }
     }
-
-    my $jscall = "javascript:changed_radio('int',$args{'formname'});";
-    my $result.=&mt
+    if (!$can_assign{'int'}) {
+        return;
+    } elsif ($authtype eq '') {
+        if (defined($in{'mode'})) {
+            if ($in{'mode'} eq 'modifycourse') {
+                if ($authnum == 1) {
+                    $authtype = '<input type="hidden" name="login" value="int">';
+                }
+            }
+        }
+    }
+    $jscall = "javascript:changed_radio('int',$in{'formname'});";
+    if ($authtype eq '') {
+        $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
+                    ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
+    }
+    $autharg = '<input type="password" size="10" name="intarg" value="'.
+               $intarg.'" onchange="'.$jscall.'" />';
+    $result = &mt
         ('[_1] Internally authenticated (with initial password [_2])',
-         '<label><input type="radio" name="login" value="int" '.$intcheck.
-             ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-         '</label><input type="text" size="10" name="intarg" '.$intarg.
-             ' onchange="'.$jscall.'" />');
+         '<label>'.$authtype,'</label>'.$autharg);
+    $result.="<label><input type=\"checkbox\" name=\"visible\" onClick='if (this.checked) { this.form.intarg.type=\"text\" } else { this.form.intarg.type=\"password\" }' />".&mt('Visible input').'</label>';
     return $result;
 }
 
@@ -1858,24 +2096,51 @@ sub authform_local{
               kerb_def_dom => 'MSU.EDU',
               @_,
               );
-
-    my $loccheck = "";
-    my $locarg = 'value=""';
-    if ( grep/^curr_authtype$/,(keys %in) ) {
+    my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
+    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'loc') {
-            $loccheck = " checked=\"on\"";
-            if ( grep/^curr_autharg$/,(keys %in) ) {
-                $locarg = "value=\"$in{'curr_autharg'}\"";
+            if ($can_assign{'loc'}) {
+                $loccheck = 'checked="on" ';
+                if (defined($in{'mode'})) {
+                    if ($in{'mode'} eq 'modifyuser') {
+                        $loccheck = '';
+                    }
+                }
+                if (defined($in{'curr_autharg'})) {
+                    $locarg = $in{'curr_autharg'};
+                }
+            } else {
+                $result = &mt('Currently using local (institutional) authentication.');
+                return $result;
             }
         }
+    } else {
+        if ($authnum == 1) {
+            $authtype = '<input type="hidden" name="login" value="loc">';
+        }
     }
-
-    my $jscall = "javascript:changed_radio('loc',$in{'formname'});";
-    my $result.=&mt('[_1] Local Authentication with argument [_2]',
-                    '<label><input type="radio" name="login" value="loc" '.$loccheck.
-                        ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-                    '</label><input type="text" size="10" name="locarg" '.$locarg.
-                        ' onchange="'.$jscall.'" />');
+    if (!$can_assign{'loc'}) {
+        return;
+    } elsif ($authtype eq '') {
+        if (defined($in{'mode'})) {
+            if ($in{'mode'} eq 'modifycourse') {
+                if ($authnum == 1) {
+                    $authtype = '<input type="hidden" name="login" value="loc">';
+                }
+            }
+        }
+    }
+    $jscall = "javascript:changed_radio('loc',$in{'formname'});";
+    if ($authtype eq '') {
+        $authtype = '<input type="radio" name="login" value="loc" '.
+                    $loccheck.' onchange="'.$jscall.'" onclick="'.
+                    $jscall.'" />';
+    }
+    $autharg = '<input type="text" size="10" name="locarg" value="'.
+               $locarg.'" onchange="'.$jscall.'" />';
+    $result = &mt('[_1] Local Authentication with argument [_2]',
+                  '<label>'.$authtype,'</label>'.$autharg);
     return $result;
 }
 
@@ -1885,16 +2150,97 @@ sub authform_filesystem{
               kerb_def_dom => 'MSU.EDU',
               @_,
               );
-    my $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
-    my $result.= &mt
+    my ($fsyscheck,$result,$authtype,$autharg,$jscall);
+    my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});
+    if (defined($in{'curr_authtype'})) {
+        if ($in{'curr_authtype'} eq 'fsys') {
+            if ($can_assign{'fsys'}) {
+                $fsyscheck = 'checked="on" ';
+                if (defined($in{'mode'})) {
+                    if ($in{'mode'} eq 'modifyuser') {
+                        $fsyscheck = '';
+                    }
+                }
+            } else {
+                $result = &mt('Currently Filesystem Authenticated.');
+                return $result;
+            }           
+        }
+    } else {
+        if ($authnum == 1) {
+            $authtype = '<input type="hidden" name="login" value="fsys">';
+        }
+    }
+    if (!$can_assign{'fsys'}) {
+        return;
+    } elsif ($authtype eq '') {
+        if (defined($in{'mode'})) {
+            if ($in{'mode'} eq 'modifycourse') {
+                if ($authnum == 1) {
+                    $authtype = '<input type="hidden" name="login" value="fsys">';
+                }
+            }
+        }
+    }
+    $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
+    if ($authtype eq '') {
+        $authtype = '<input type="radio" name="login" value="fsys" '.
+                    $fsyscheck.' onchange="'.$jscall.'" onclick="'.
+                    $jscall.'" />';
+    }
+    $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
+               ' onchange="'.$jscall.'" />';
+    $result = &mt
         ('[_1] Filesystem Authenticated (with initial password [_2])',
          '<label><input type="radio" name="login" value="fsys" '.
-         'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-         '</label><input type="text" size="10" name="fsysarg" value="" '.
+         $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
+         '</label><input type="password" size="10" name="fsysarg" value="" '.
                   'onchange="'.$jscall.'" />');
     return $result;
 }
 
+sub get_assignable_auth {
+    my ($dom) = @_;
+    if ($dom eq '') {
+        $dom = $env{'request.role.domain'};
+    }
+    my %can_assign = (
+                          krb4 => 1,
+                          krb5 => 1,
+                          int  => 1,
+                          loc  => 1,
+                     );
+    my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
+    if (ref($domconfig{'usercreation'}) eq 'HASH') {
+        if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') {
+            my $authhash = $domconfig{'usercreation'}{'authtypes'};
+            my $context;
+            if ($env{'request.role'} =~ /^au/) {
+                $context = 'author';
+            } elsif ($env{'request.role'} =~ /^dc/) {
+                $context = 'domain';
+            } elsif ($env{'request.course.id'}) {
+                $context = 'course';
+            }
+            if ($context) {
+                if (ref($authhash->{$context}) eq 'HASH') {
+                   %can_assign = %{$authhash->{$context}}; 
+                }
+            }
+        }
+    }
+    my $authnum = 0;
+    foreach my $key (keys(%can_assign)) {
+        if ($can_assign{$key}) {
+            $authnum ++;
+        }
+    }
+    if ($can_assign{'krb4'} && $can_assign{'krb5'}) {
+        $authnum --;
+    }
+    return ($authnum,%can_assign);
+}
+
 ###############################################################
 ##    Get Authentication Defaults for Domain                 ##
 ###############################################################
@@ -2020,7 +2366,7 @@ sub initialize_keywords {
     # Remove special values from %Keywords.
     foreach my $value ('total.count','average.count') {
         delete($Keywords{$value}) if (exists($Keywords{$value}));
-    }
+  }
     return 1;
 }
 
@@ -2531,9 +2877,11 @@ sub preferred_languages {
 	@languages=(@languages,
 		    split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'}));
     }
-    my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0];
+    my $browser=$ENV{'HTTP_ACCEPT_LANGUAGE'};
     if ($browser) {
-	@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser));
+	my @browser = 
+	    map { (split(/\s*;\s*/,$_))[0] } (split(/\s*,\s*/,$browser));
+	push(@languages,@browser);
     }
     if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) {
 	@languages=(@languages,
@@ -2555,14 +2903,40 @@ sub preferred_languages {
     my @genlanguages;
     foreach my $lang (@languages) {
 	unless ($lang=~/\w/) { next; }
-	push (@genlanguages,$lang);
+	push(@genlanguages,$lang);
 	if ($lang=~/(\-|\_)/) {
 	    push(@genlanguages,(split(/(\-|\_)/,$lang))[0]);
 	}
     }
+    #uniqueify the languages list
+    my %count;
+    @genlanguages = map { $count{$_}++ == 0 ? $_ : () } @genlanguages;
     return @genlanguages;
 }
 
+sub languages {
+    my ($possible_langs) = @_;
+    my @preferred_langs = &preferred_languages();
+    if (!ref($possible_langs)) {
+	if( wantarray ) {
+	    return @preferred_langs;
+	} else {
+	    return $preferred_langs[0];
+	}
+    }
+    my %possibilities = map { $_ => 1 } (@$possible_langs);
+    my @preferred_possibilities;
+    foreach my $preferred_lang (@preferred_langs) {
+	if (exists($possibilities{$preferred_lang})) {
+	    push(@preferred_possibilities, $preferred_lang);
+	}
+    }
+    if( wantarray ) {
+	return @preferred_possibilities;
+    }
+    return $preferred_possibilities[0];
+}
+
 ###############################################################
 ##               Student Answer Attempts                     ##
 ###############################################################
@@ -2617,14 +2991,14 @@ sub get_previous_attempt {
 	  $lasthash{$key}=$returnhash{$version.':'.$key};
         }
       }
-      $prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">';
-      $prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>';
+      $prevattempts=&start_data_table().&start_data_table_header_row();
+      $prevattempts.='<th>'.&mt('History').'</th>';
       foreach my $key (sort(keys(%lasthash))) {
 	my ($ign,@parts) = split(/\./,$key);
 	if ($#parts > 0) {
 	  my $data=$parts[-1];
 	  pop(@parts);
-	  $prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.'&nbsp;</td>';
+	  $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.'&nbsp;</th>';
 	} else {
 	  if ($#parts == 0) {
 	    $prevattempts.='<th>'.$parts[0].'</th>';
@@ -2633,41 +3007,53 @@ sub get_previous_attempt {
 	  }
 	}
       }
+      $prevattempts.=&end_data_table_header_row();
       if ($getattempt eq '') {
 	for ($version=1;$version<=$returnhash{'version'};$version++) {
-	  $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>';
+	  $prevattempts.=&start_data_table_row().
+	      '<td>'.&mt('Transaction [_1]',$version).'</td>';
 	    foreach my $key (sort(keys(%lasthash))) {
-	       my $value;
-	       if ($key =~ /timestamp/) {
-		  $value=scalar(localtime($returnhash{$version.':'.$key}));
-	       } else {
-		  $value=$returnhash{$version.':'.$key};
-	       }
-	       $prevattempts.='<td>'.&unescape($value).'&nbsp;</td>';   
+		my $value = &format_previous_attempt_value($key,
+							   $returnhash{$version.':'.$key});
+		$prevattempts.='<td>'.$value.'&nbsp;</td>';   
 	    }
+	  $prevattempts.=&end_data_table_row();
 	 }
       }
-      $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>';
+      $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>';
       foreach my $key (sort(keys(%lasthash))) {
-	my $value;
-	if ($key =~ /timestamp/) {
-	  $value=scalar(localtime($lasthash{$key}));
-	} else {
-	  $value=$lasthash{$key};
-	}
-	$value=&unescape($value);
+	my $value = &format_previous_attempt_value($key,$lasthash{$key});
 	if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
 	$prevattempts.='<td>'.$value.'&nbsp;</td>';
       }
-      $prevattempts.='</tr></table></td></tr></table>';
+      $prevattempts.= &end_data_table_row().&end_data_table();
     } else {
-      $prevattempts='Nothing submitted - no attempts.';
+      $prevattempts=
+	  &start_data_table().&start_data_table_row().
+	  '<td>'.&mt('Nothing submitted - no attempts.').'</td>'.
+	  &end_data_table_row().&end_data_table();
     }
   } else {
-    $prevattempts='No data.';
+    $prevattempts=
+	  &start_data_table().&start_data_table_row().
+	  '<td>'.&mt('No data.').'</td>'.
+	  &end_data_table_row().&end_data_table();
   }
 }
 
+sub format_previous_attempt_value {
+    my ($key,$value) = @_;
+    if ($key =~ /timestamp/) {
+	$value = &Apache::lonlocal::locallocaltime($value);
+    } elsif (ref($value) eq 'ARRAY') {
+	$value = '('.join(', ', @{ $value }).')';
+    } else {
+	$value = &unescape($value);
+    }
+    return $value;
+}
+
+
 sub relative_to_absolute {
     my ($url,$output)=@_;
     my $parser=HTML::TokeParser->new(\$output);
@@ -2826,9 +3212,9 @@ sub pprmlink {
     if (!$symb) { $symb=&Apache::lonnet::symbread(); }
     $symb=&escape($symb);
     if ($target) { $target="target=\"$target\""; }
-    return '<a href="/adm/parmset?&command=set&'.
-	'symb='.$symb.'&uname='.$uname.
-	'&udom='.$udom.'" '.$target.'>'.$text.'</a>';
+    return '<a href="/adm/parmset?command=set&amp;'.
+	'symb='.$symb.'&amp;uname='.$uname.
+	'&amp;udom='.$udom.'" '.$target.'>'.$text.'</a>';
 }
 ##############################################
 
@@ -3284,45 +3670,78 @@ sub get_domainconf {
 
     my %domconfig = &Apache::lonnet::get_dom('configuration',
 					     ['login','rolecolors'],$udom);
-    my %designhash;
+    my (%designhash,%legacy);
     if (keys(%domconfig) > 0) {
         if (ref($domconfig{'login'}) eq 'HASH') {
-            foreach my $key (keys(%{$domconfig{'login'}})) {
-                $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+            if (keys(%{$domconfig{'login'}})) {
+                foreach my $key (keys(%{$domconfig{'login'}})) {
+                    $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+                }
+            } else {
+                $legacy{'login'} = 1;
             }
+        } else {
+            $legacy{'login'} = 1;
         }
         if (ref($domconfig{'rolecolors'}) eq 'HASH') {
-            foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
-                if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
-                    foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
-                        $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
+            if (keys(%{$domconfig{'rolecolors'}})) {
+                foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
+                    if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
+                        foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
+                            $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
+                        }
                     }
                 }
+            } else {
+                $legacy{'rolecolors'} = 1;
             }
+        } else {
+            $legacy{'rolecolors'} = 1;
         }
-    } else {
-        my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
-        my $designfile =  $designdir.'/'.$udom.'.tab';
-        if (-e $designfile) {
-            if ( open (my $fh,"<$designfile") ) {
-                while (my $line = <$fh>) {
-                    next if ($line =~ /^\#/);
-                    chomp($line);
-                    my ($key,$val)=(split(/\=/,$line));
-                    if ($val) { $designhash{$udom.'.'.$key}=$val; }
+        if (keys(%legacy) > 0) {
+            my %legacyhash = &get_legacy_domconf($udom);
+            foreach my $item (keys(%legacyhash)) {
+                if ($item =~ /^\Q$udom\E\.login/) {
+                    if ($legacy{'login'}) { 
+                        $designhash{$item} = $legacyhash{$item};
+                    }
+                } else {
+                    if ($legacy{'rolecolors'}) {
+                        $designhash{$item} = $legacyhash{$item};
+                    }
                 }
-                close($fh);
             }
         }
-        if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
-            $designhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
-        }
+    } else {
+        %designhash = &get_legacy_domconf($udom); 
     }
     &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
 				  $cachetime);
     return %designhash;
 }
 
+sub get_legacy_domconf {
+    my ($udom) = @_;
+    my %legacyhash;
+    my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
+    my $designfile =  $designdir.'/'.$udom.'.tab';
+    if (-e $designfile) {
+        if ( open (my $fh,"<$designfile") ) {
+            while (my $line = <$fh>) {
+                next if ($line =~ /^\#/);
+                chomp($line);
+                my ($key,$val)=(split(/\=/,$line));
+                if ($val) { $legacyhash{$udom.'.'.$key}=$val; }
+            }
+            close($fh);
+        }
+    }
+    if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
+        $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
+    }
+    return %legacyhash;
+}
+
 =pod
 
 =item * &domainlogo()
@@ -3372,10 +3791,10 @@ Returns: value of designparamter $which
 sub designparm {
     my ($which,$domain)=@_;
     if ($env{'browser.blackwhite'} eq 'on') {
-	if ($which=~/\.(font|alink|vlink|link)$/) {
+	if ($which=~/\.(font|alink|vlink|link|textcol)$/) {
 	    return '#000000';
 	}
-	if ($which=~/\.(pgbg|sidebg)$/) {
+	if ($which=~/\.(pgbg|sidebg|bgcol)$/) {
 	    return '#FFFFFF';
 	}
 	if ($which=~/\.tabbg$/) {
@@ -3394,7 +3813,7 @@ sub designparm {
         $output = $defaultdesign{$which};
     }
     if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
-        ($which =~ /login\.(img|logo|domlogo)/)) {
+        ($which =~ /login\.(img|logo|domlogo|login)/)) {
         if ($output =~ m{^/(adm|res)/}) {
 	    if ($output =~ m{^/res/}) {
 		my $local_name = &Apache::lonnet::filelocation('',$output);
@@ -3711,18 +4130,25 @@ sub make_attr_string {
 
 Returns a uniform footer for LON-CAPA web pages.
 
-Inputs: none
+Inputs: 1 - optional reference to an args hash
+If in the hash, key for noredirectlink has a value which evaluates to true,
+a 'Continue' link is not displayed if the page contains an
+internal redirect in the <head></head> section,
+i.e., $env{'internal.head.redirect'} exists   
 
 =cut
 
 sub endbodytag {
+    my ($args) = @_;
     my $endbodytag='</body>';
     $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
     if ( exists( $env{'internal.head.redirect'} ) ) {
-	$endbodytag=
-	    "<br /><a href=\"$env{'internal.head.redirect'}\">".
-	    &mt('Continue').'</a>'.
-	    $endbodytag;
+        if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
+	    $endbodytag=
+	        "<br /><a href=\"$env{'internal.head.redirect'}\">".
+	        &mt('Continue').'</a>'.
+	        $endbodytag;
+        }
     }
     return $endbodytag;
 }
@@ -3756,7 +4182,7 @@ sub standard_css {
     my $vlink  = &designparm($function.'.vlink', $domain);
     my $link   = &designparm($function.'.link',  $domain);
 
-    my $sans                 = 'Arial,Helvetica,sans-serif';
+    my $sans                 = 'Verdana,Arial,Helvetica,sans-serif';
     my $mono                 = 'monospace';
     my $data_table_head      = $tabbg;
     my $data_table_light     = '#EEEEEE';
@@ -3774,8 +4200,9 @@ sub standard_css {
     my $table_header         = '#DDDDDD';
     my $feedback_link_bg     = '#BBBBBB';
 
-    my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px'
-	                                              : '0px 3px 0px 4px';
+    my $border = ($env{'browser.type'} eq 'explorer' ||
+		  $env{'browser.type'} eq 'safari'     ) ? '0px 2px 0px 2px'
+	                                                 : '0px 3px 0px 4px';
 
 
     return <<END;
@@ -3795,7 +4222,7 @@ table.thinborder tr td {
 
 form, .inline { display: inline; }
 .center { text-align: center; }
-.LC_filename {font-family: $mono;}
+.LC_filename {font-family: $mono; white-space:pre;}
 .LC_error {
   color: red;
   font-size: larger;
@@ -3836,7 +4263,7 @@ table.LC_pastsubmission {
   margin: 2px;
 }
 
-table#LC_top_nav, table#LC_menubuttons {
+table#LC_top_nav, table#LC_menubuttons,table#LC_nav_location {
   width: 100%;
   background: $pgbg;
   border: 2px;
@@ -3844,7 +4271,7 @@ table#LC_top_nav, table#LC_menubuttons {
   padding: 0px;
 }
 
-table#LC_title_bar, table.LC_breadcrumbs, table#LC_nav_location,
+table#LC_title_bar, table.LC_breadcrumbs, 
 table#LC_title_bar.LC_with_remote {
   width: 100%;
   border-color: $pgbg;
@@ -3984,6 +4411,7 @@ td.LC_menubuttons_img {
 }
 .LC_new_mail {
   font-family: $sans;
+  background: $tabbg;
   font-weight: bold;
 }
 
@@ -4035,19 +4463,20 @@ table.LC_data_table, table.LC_mail_list
   border: 1px solid #000000;
   border-collapse: separate;
   border-spacing: 1px;
+  background: $pgbg;
 }
 .LC_data_table_dense {
   font-size: small;
 }
 table.LC_nested_outer {
   border: 1px solid #000000;
-  border-collapse: separate;
+  border-collapse: collapse;
   border-spacing: 0px;
   width: 100%;
 }
 table.LC_nested {
   border: 0px;
-  border-collapse: separate;
+  border-collapse: collapse;
   border-spacing: 0px;
   width: 100%;
 }
@@ -4057,18 +4486,22 @@ table.LC_prior_tries tr th {
   background-color: $data_table_head;
   font-size: smaller;
 }
-table.LC_data_table tr td, 
+table.LC_data_table tr.LC_odd_row > td, 
 table.LC_aboutme_port tr td {
   background-color: $data_table_light;
   padding: 2px;
 }
-table.LC_data_table tr.LC_even_row td,
+table.LC_data_table tr.LC_even_row > td,
 table.LC_aboutme_port tr.LC_even_row td {
   background-color: $data_table_dark;
 }
 table.LC_data_table tr.LC_data_table_highlight td {
   background-color: $data_table_darker;
 }
+table.LC_data_table tr td.LC_leftcol_header {
+  background-color: $data_table_head;
+  font-weight: bold;
+}
 table.LC_data_table tr.LC_empty_row td,
 table.LC_nested tr.LC_empty_row td {
   background-color: #FFFFFF;
@@ -4099,7 +4532,8 @@ table.LC_nested tr.LC_info_row td {
   font-size: small;
   text-align: center;
 }
-table.LC_nested tr.LC_info_row td.LC_left_item {
+table.LC_nested tr.LC_info_row td.LC_left_item,
+table.LC_nested_outer tr th.LC_left_item {
   text-align: left;
 }
 table.LC_nested td {
@@ -4330,9 +4764,7 @@ table#LC_helpmenu_links a:hover {
   border: 1px solid #8888FF;
   background: #CCCCFF;
 }
-
 table.LC_pick_box {
-  width: 100%;
   border-collapse: separate;
   background: white;
   border: 1px solid black;
@@ -4345,6 +4777,14 @@ table.LC_pick_box td.LC_pick_box_title {
   width: 184px;
   padding: 8px;
 }
+table.LC_pick_box td.LC_pick_box_value {
+  text-align: left;
+  padding: 8px;
+}
+table.LC_pick_box td.LC_pick_box_select {
+  text-align: left;
+  padding: 8px;
+}
 table.LC_pick_box td.LC_pick_box_separator {
   padding: 0px;
   height: 1px;
@@ -4353,7 +4793,48 @@ table.LC_pick_box td.LC_pick_box_separat
 table.LC_pick_box td.LC_pick_box_submit {
   text-align: right;
 }
-
+table.LC_pick_box td.LC_evenrow_value {
+  text-align: left;
+  padding: 8px;
+  background-color: $data_table_light;
+}
+table.LC_pick_box td.LC_oddrow_value {
+  text-align: left;
+  padding: 8px;
+  background-color: $data_table_light;
+}
+table.LC_helpform_receipt {
+  width: 620px;
+  border-collapse: separate;
+  background: white;
+  border: 1px solid black;
+  border-spacing: 1px;
+}
+table.LC_helpform_receipt td.LC_pick_box_title {
+  background: $tabbg;
+  font-weight: bold;
+  text-align: right;
+  width: 184px;
+  padding: 8px;
+}
+table.LC_helpform_receipt td.LC_evenrow_value {
+  text-align: left;
+  padding: 8px;
+  background-color: $data_table_light;
+}
+table.LC_helpform_receipt td.LC_oddrow_value {
+  text-align: left;
+  padding: 8px;
+  background-color: $data_table_light;
+}
+table.LC_helpform_receipt td.LC_pick_box_separator {
+  padding: 0px;
+  height: 1px;
+  background: black;
+}
+span.LC_helpform_receipt_cat {
+  font-weight: bold;
+}
 table.LC_group_priv_box {
   background: white;
   border: 1px solid black;
@@ -4421,12 +4902,20 @@ table.LC_descriptive_input td.LC_descrip
   text-align: right;
   font-weight: bold;
 }
-table.LC_feedback_link {
-    background: $feedback_link_bg;
+div.LC_feedback_link {
+  clear: both;
+  background: white;
+  width: 100%;  
 }
 span.LC_feedback_link {
-    background: $feedback_link_bg;
-    font-size: larger;
+  background: $feedback_link_bg;
+  font-size: larger;
+}
+span.LC_message_link {
+  background: $feedback_link_bg;
+  font-size: larger;
+  position: absolute;
+  right: 1em;
 }
 
 table.LC_prior_tries {
@@ -4502,6 +4991,11 @@ span.LC_cusr_emph {
   font-style: italic;
 }
 
+span.LC_cusr_subheading {
+  font-weight: normal;
+  font-size: 85%;
+}
+
 table.LC_docs_documents {
   background: #BBBBBB;
   border-width: 0px;
@@ -4569,6 +5063,171 @@ table.LC_docs_adddocs th {
   background: #DDDDDD;
 }
 
+table.LC_sty_begin {
+  background: #BBFFBB;
+}
+table.LC_sty_end {
+  background: #FFBBBB;
+}
+
+table.LC_double_column {
+  border-width: 0px;
+  border-collapse: collapse;
+  width: 100%;
+  padding: 2px;
+}
+
+table.LC_double_column tr td.LC_left_col {
+  top: 2px;
+  left: 2px;
+  width: 47%;
+  vertical-align: top;
+}
+
+table.LC_double_column tr td.LC_right_col {
+  top: 2px;
+  right: 2px; 
+  width: 47%;
+  vertical-align: top;
+}
+
+span.LC_role_level {
+  font-weight: bold;
+}
+
+div.LC_left_float {
+  float: left;
+  padding-right: 5%;
+  padding-bottom: 4px;
+}
+
+div.LC_clear_float_header {
+  padding-bottom: 2px;
+}
+
+div.LC_clear_float_footer {
+  padding-top: 10px;
+  clear: both;
+}
+
+
+div.LC_grade_select_mode {
+  font-family: $sans;
+}
+div.LC_grade_select_mode div div {
+  margin: 5px;
+}
+div.LC_grade_select_mode_selector {
+  margin: 5px;
+  float: left;
+}
+div.LC_grade_select_mode_selector_header {
+  font: bold medium $sans;
+}
+div.LC_grade_select_mode_type {
+  clear: left;
+}
+
+div.LC_grade_show_user {
+  margin-top: 20px;
+  border: 1px solid black;
+}
+div.LC_grade_user_name {
+  background: #DDDDEE;
+  border-bottom: 1px solid black;
+  font: bold large $sans;
+}
+div.LC_grade_show_user_odd_row div.LC_grade_user_name {
+  background: #DDEEDD;
+}
+
+div.LC_grade_show_problem,
+div.LC_grade_submissions,
+div.LC_grade_message_center,
+div.LC_grade_info_links,
+div.LC_grade_assign {
+  margin: 5px;
+  width: 99%;
+  background: #FFFFFF;
+}
+div.LC_grade_show_problem_header,
+div.LC_grade_submissions_header,
+div.LC_grade_message_center_header,
+div.LC_grade_assign_header {
+  font: bold large $sans;
+}
+div.LC_grade_show_problem_problem,
+div.LC_grade_submissions_body,
+div.LC_grade_message_center_body,
+div.LC_grade_assign_body {
+  border: 1px solid black;
+  width: 99%;
+  background: #FFFFFF;
+}
+span.LC_grade_check_note {
+  font: normal medium $sans;
+  display: inline;
+  position: absolute;
+  right: 1em;
+}
+
+table.LC_scantron_action {
+  width: 100%;
+}
+table.LC_scantron_action tr th {
+  font: normal bold $sans;
+}
+
+div.LC_edit_problem_header, 
+div.LC_edit_problem_footer {
+  font: normal medium $sans;
+  margin: 2px;
+}
+div.LC_edit_problem_header,
+div.LC_edit_problem_header div,
+div.LC_edit_problem_footer,
+div.LC_edit_problem_footer div,
+div.LC_edit_problem_editxml_header,
+div.LC_edit_problem_editxml_header div {
+  margin-top: 5px;
+}
+div.LC_edit_problem_header_edit_row {
+  background: $tabbg;
+  padding: 3px;
+  margin-bottom: 5px;
+}
+div.LC_edit_problem_header_title {
+  font: larger bold $sans;
+  background: $tabbg;
+  padding: 3px;
+}
+table.LC_edit_problem_header_title {
+  font: larger bold $sans;
+  width: 100%;
+  border-color: $pgbg;
+  border-style: solid;
+  border-width: $border;
+
+  background: $tabbg;
+  border-collapse: collapse;
+  padding: 0px
+}
+
+div.LC_edit_problem_discards {
+  float: left;
+  padding-bottom: 5px;
+}
+div.LC_edit_problem_saves {
+  float: right;
+  padding-bottom: 5px;
+}
+hr.LC_edit_problem_divide {
+  clear: both;
+  color: $tabbg;
+  background-color: $tabbg;
+  height: 3px;
+  border: 0px;
+}
 END
 }
 
@@ -4685,7 +5344,9 @@ Inputs: none
 sub xml_begin {
     my $output='';
 
-    &Apache::lonhtmlcommon::init_htmlareafields();
+    if ($env{'internal.start_page'}==1) {
+	&Apache::lonhtmlcommon::init_htmlareafields();
+    }
 
     if ($env{'browser.mathml'}) {
 	$output='<?xml version="1.0"?>'
@@ -4862,7 +5523,7 @@ sub end_page {
     if ($args->{'frameset'}) {
 	$result .= '</frameset>';
     } else {
-	$result .= &endbodytag();
+	$result .= &endbodytag($args);
     }
     $result .= "\n</html>";
 
@@ -4934,30 +5595,30 @@ sub simple_error_page {
 }
 
 {
-    my $row_count;
+    my @row_count;
     sub start_data_table {
 	my ($add_class) = @_;
 	my $css_class = (join(' ','LC_data_table',$add_class));
-	undef($row_count);
+	unshift(@row_count,0);
 	return '<table class="'.$css_class.'">'."\n";
     }
 
     sub end_data_table {
-	undef($row_count);
+	shift(@row_count);
 	return '</table>'."\n";;
     }
 
     sub start_data_table_row {
 	my ($add_class) = @_;
-	$row_count++;
-	my $css_class = ($row_count % 2)?'':'LC_even_row';
+	$row_count[0]++;
+	my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
 	$css_class = (join(' ',$css_class,$add_class));
 	return  '<tr class="'.$css_class.'">'."\n";;
     }
     
     sub continue_data_table_row {
 	my ($add_class) = @_;
-	my $css_class = ($row_count % 2)?'':'LC_even_row';
+	my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
 	$css_class = (join(' ',$css_class,$add_class));
 	return  '<tr class="'.$css_class.'">'."\n";;
     }
@@ -4967,7 +5628,7 @@ sub simple_error_page {
     }
 
     sub start_data_table_empty_row {
-	$row_count++;
+	$row_count[0]++;
 	return  '<tr class="LC_empty_row" >'."\n";;
     }
 
@@ -5239,12 +5900,17 @@ previous, future, or all.
 5. reference to array of section restrictions (optional)
 6. reference to results object (hash of hashes).
 7. reference to optional userdata hash
-Keys of top level hash are roles.
+8. reference to optional statushash
+9. flag if privileged users (except those set to unhide in
+   course settings) should be excluded    
+Keys of top level results hash are roles.
 Keys of inner hashes are username:domain, with 
 values set to access type.
 Optional userdata hash returns an array with arguments in the 
 same order as loncoursedata::get_classlist() for student data.
 
+Optional statushash returns
+
 Entries for end, start, section and status are blank because
 of the possibility of multiple values for non-student roles.
 
@@ -5253,7 +5919,7 @@ of the possibility of multiple values fo
 ###############################################
 
 sub get_course_users {
-    my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
+    my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_;
     my %idx = ();
     my %seclists;
 
@@ -5273,6 +5939,7 @@ sub get_course_users {
             my $match = 0;
             my $secmatch = 0;
             my $section = $$classlist{$student}[$idx{section}];
+            my $status = $$classlist{$student}[$idx{status}];
             if ($section eq '') {
                 $section = 'none';
             }
@@ -5292,7 +5959,6 @@ sub get_course_users {
                     next;
                 }
             }
-            push(@{$seclists{$student}},$section); 
             if (defined($$types{'active'})) {
                 if ($$classlist{$student}[$idx{status}] eq 'Active') {
                     push(@{$$users{st}{$student}},'active');
@@ -5300,25 +5966,46 @@ sub get_course_users {
                 }
             }
             if (defined($$types{'previous'})) {
-                if ($$classlist{$student}[$idx{end}] <= $now) {
+                if ($$classlist{$student}[$idx{status}] eq 'Expired') {
                     push(@{$$users{st}{$student}},'previous');
                     $match = 1;
                 }
             }
             if (defined($$types{'future'})) {
-                if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) {
+                if ($$classlist{$student}[$idx{status}] eq 'Future') {
                     push(@{$$users{st}{$student}},'future');
                     $match = 1;
                 }
             }
-            if ($match && ref($userdata) eq 'HASH') {
-                $$userdata{$student} = $$classlist{$student};
+            if ($match) {
+                push(@{$seclists{$student}},$section);
+                if (ref($userdata) eq 'HASH') {
+                    $$userdata{$student} = $$classlist{$student};
+                }
+                if (ref($statushash) eq 'HASH') {
+                    $statushash->{$student}{'st'}{$section} = $status;
+                }
             }
         }
     }
     if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
         my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
         my $now = time;
+        my %displaystatus = ( previous => 'Expired',
+                              active   => 'Active',
+                              future   => 'Future',
+                            );
+        my %nothide;
+        if ($hidepriv) {
+            my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+            foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
+                if ($user !~ /:/) {
+                    $nothide{join(':',split(/[\@]/,$user))}=1;
+                } else {
+                    $nothide{$user} = 1;
+                }
+            }
+        }
         foreach my $person (sort(keys(%coursepersonnel))) {
             my $match = 0;
             my $secmatch = 0;
@@ -5352,6 +6039,12 @@ sub get_course_users {
                     $usec = 'none';
                 }
                 if ($uname ne '' && $udom ne '') {
+                    if ($hidepriv) {
+                        if ((&Apache::lonnet::privileged($uname,$udom)) &&
+                            (!$nothide{$uname.':'.$udom})) {
+                            next;
+                        }
+                    }
                     if ($end > 0 && $end < $now) {
                         $status = 'previous';
                     } elsif ($start > $now) {
@@ -5374,6 +6067,9 @@ sub get_course_users {
                         if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
                             push(@{$seclists{$uname.':'.$udom}},$usec);
                         }
+                        if (ref($statushash) eq 'HASH') {
+                            $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
+                        }
                     }
                 }
             }
@@ -5383,15 +6079,25 @@ sub get_course_users {
                 my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
                 if ( defined($csettings{'internal.courseowner'}) ) {
                     my $owner = $csettings{'internal.courseowner'};
-                    if ($owner !~ /^[^:]+:[^:]+$/) {
-                        $owner = $owner.':'.$cdom;
+                    next if ($owner eq '');
+                    my ($ownername,$ownerdom);
+                    if ($owner =~ /^([^:]+):([^:]+)$/) {
+                        $ownername = $1;
+                        $ownerdom = $2;
+                    } else {
+                        $ownername = $owner;
+                        $ownerdom = $cdom;
+                        $owner = $ownername.':'.$ownerdom;
                     }
                     @{$$users{'ow'}{$owner}} = 'any';
                     if (defined($userdata) && 
-			!exists($$userdata{$owner.':'.$cdom})) {
-			&get_user_info($cdom,$owner,\%idx,$userdata);
-                        if (!grep(/^none$/,@{$seclists{$owner.':'.$cdom}})) {
-                            push(@{$seclists{$owner.':'.$cdom}},'none');
+			!exists($$userdata{$owner})) {
+			&get_user_info($ownerdom,$ownername,\%idx,$userdata);
+                        if (!grep(/^none$/,@{$seclists{$owner}})) {
+                            push(@{$seclists{$owner}},'none');
+                        }
+                        if (ref($statushash) eq 'HASH') {
+                            $statushash->{$owner}{'ow'}{'none'} = 'Any';
                         }
 		    }
                 }
@@ -5411,6 +6117,8 @@ sub get_user_info {
 	&plainname($uname,$udom,'lastname');
     $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
     $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
+    my %idhash =  &Apache::lonnet::idrget($udom,($uname));
+    $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname}; 
     return;
 }
 
@@ -5531,24 +6239,24 @@ sub default_quota {
     my ($udom,$inststatus) = @_;
     my ($defquota,$settingstatus);
     my %quotahash = &Apache::lonnet::get_dom('configuration',
-                                            ['quota'],$udom);
-    if (ref($quotahash{'quota'}) eq 'HASH') {
+                                            ['quotas'],$udom);
+    if (ref($quotahash{'quotas'}) eq 'HASH') {
         if ($inststatus ne '') {
             my @statuses = split(/:/,$inststatus);
             foreach my $item (@statuses) {
-                if ($quotahash{'quota'}{$item} ne '') {
+                if ($quotahash{'quotas'}{$item} ne '') {
                     if ($defquota eq '') {
-                        $defquota = $quotahash{'quota'}{$item};
+                        $defquota = $quotahash{'quotas'}{$item};
                         $settingstatus = $item;
-                    } elsif ($quotahash{'quota'}{$item} > $defquota) {
-                        $defquota = $quotahash{'quota'}{$item};
+                    } elsif ($quotahash{'quotas'}{$item} > $defquota) {
+                        $defquota = $quotahash{'quotas'}{$item};
                         $settingstatus = $item;
                     }
                 }
             }
         }
         if ($defquota eq '') {
-            $defquota = $quotahash{'quota'}{'default'};
+            $defquota = $quotahash{'quotas'}{'default'};
             $settingstatus = 'default';
         }
     } else {
@@ -5600,14 +6308,14 @@ sub get_secgrprole_info {
 }
 
 sub user_picker {
-    my ($dom,$srch,$forcenewuser,$caller) = @_;
+    my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
     my $currdom = $dom;
     my %curr_selected = (
                         srchin => 'dom',
-                        srchby => 'uname',
+                        srchby => 'lastname',
                       );
     my $srchterm;
-    if (ref($srch) eq 'HASH') {
+    if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
         if ($srch->{'srchby'} ne '') {
             $curr_selected{'srchby'} = $srch->{'srchby'};
         }
@@ -5666,7 +6374,7 @@ sub user_picker {
     $srchinsel .= "\n  </select>\n";
 
     my $srchbysel =  ' <select name="srchby">';
-    foreach my $option ('uname','lastname','lastfirst') {
+    foreach my $option ('lastname','lastfirst','uname') {
         if ($curr_selected{'srchby'} eq $option) {
             $srchbysel .= '
    <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
@@ -5678,7 +6386,7 @@ sub user_picker {
     $srchbysel .= "\n  </select>\n";
 
     my $srchtypesel = ' <select name="srchtype">';
-    foreach my $option ('exact','begins','contains') {
+    foreach my $option ('begins','contains','exact') {
         if ($curr_selected{'srchtype'} eq $option) {
             $srchtypesel .= '
    <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
@@ -5694,7 +6402,16 @@ sub user_picker {
     if ($forcenewuser) {
         if (ref($srch) eq 'HASH') {
             if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
-	        $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>';
+                if ($cancreate) {
+                    $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>';
+                } else {
+                    my $helplink = ' href="javascript:helpMenu('."'display'".')"';
+                    my %usertypetext = (
+                        official   => 'institutional',
+                        unofficial => 'non-institutional',
+                    );
+                    $new_user_create = '<br /><span class="LC_warning">'.&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.").' '.&mt('Contact the <a[_1]>helpdesk</a> for assistance.',$helplink).'</span><br /><br />';
+                }
             }
         }
 
@@ -5823,6 +6540,158 @@ END_BLOCK
     return $output;
 }
 
+sub user_rule_check {
+    my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
+    my $response;
+    if (ref($usershash) eq 'HASH') {
+        foreach my $user (keys(%{$usershash})) {
+            my ($uname,$udom) = split(/:/,$user);
+            next if ($udom eq '' || $uname eq '');
+            my ($id,$newuser);
+            if (ref($usershash->{$user}) eq 'HASH') {
+                $newuser = $usershash->{$user}->{'newuser'};
+                $id = $usershash->{$user}->{'id'};
+            }
+            my $inst_response;
+            if (ref($checks) eq 'HASH') {
+                if (defined($checks->{'username'})) {
+                    ($inst_response,%{$inst_results->{$user}}) = 
+                        &Apache::lonnet::get_instuser($udom,$uname);
+                } elsif (defined($checks->{'id'})) {
+                    ($inst_response,%{$inst_results->{$user}}) =
+                        &Apache::lonnet::get_instuser($udom,undef,$id);
+                }
+            } else {
+                ($inst_response,%{$inst_results->{$user}}) =
+                    &Apache::lonnet::get_instuser($udom,$uname);
+                return;
+            }
+            if (!$got_rules->{$udom}) {
+                my %domconfig = &Apache::lonnet::get_dom('configuration',
+                                                  ['usercreation'],$udom);
+                if (ref($domconfig{'usercreation'}) eq 'HASH') {
+                    foreach my $item ('username','id') {
+                        if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
+                            $$curr_rules{$udom}{$item} = 
+                                $domconfig{'usercreation'}{$item.'_rule'};
+                        }
+                    }
+                }
+                $got_rules->{$udom} = 1;  
+            }
+            foreach my $item (keys(%{$checks})) {
+                if (ref($$curr_rules{$udom}) eq 'HASH') {
+                    if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') {
+                        if (@{$$curr_rules{$udom}{$item}} > 0) {
+                            my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item,$$curr_rules{$udom}{$item});
+                            foreach my $rule (@{$$curr_rules{$udom}{$item}}) {
+                                if ($rule_check{$rule}) {
+                                    $$rulematch{$user}{$item} = $rule;
+                                    if ($inst_response eq 'ok') {
+                                        if (ref($inst_results) eq 'HASH') {
+                                            if (ref($inst_results->{$user}) eq 'HASH') {
+                                                if (keys(%{$inst_results->{$user}}) == 0) {
+                                                    $$alerts{$item}{$udom}{$uname} = 1;
+                                                }
+                                            }
+                                        }
+                                    }
+                                    last;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return;
+}
+
+sub user_rule_formats {
+    my ($domain,$domdesc,$curr_rules,$check) = @_;
+    my %text = ( 
+                 'username' => 'Usernames',
+                 'id'       => 'IDs',
+               );
+    my $output;
+    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>';
+            foreach my $rule (@{$ruleorder}) {
+                if (ref($curr_rules) eq 'ARRAY') {
+                    if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
+                        if (ref($rules->{$rule}) eq 'HASH') {
+                            $output .= '<li>'.$rules->{$rule}{'name'}.': '.
+                                        $rules->{$rule}{'desc'}.'</li>';
+                        }
+                    }
+                }
+            }
+            $output .= '</ul>';
+        }
+    }
+    return $output;
+}
+
+sub instrule_disallow_msg {
+    my ($checkitem,$domdesc,$count,$mode) = @_;
+    my $response;
+    my %text = (
+                  item   => 'username',
+                  items  => 'usernames',
+                  match  => 'matches',
+                  do     => 'does',
+                  action => 'a username',
+                  one    => 'one',
+               );
+    if ($count > 1) {
+        $text{'item'} = 'usernames';
+        $text{'match'} ='match';
+        $text{'do'} = 'do';
+        $text{'action'} = 'usernames',
+        $text{'one'} = 'ones';
+    }
+    if ($checkitem eq 'id') {
+        $text{'items'} = 'IDs';
+        $text{'item'} = 'ID';
+        $text{'action'} = 'an ID';
+        if ($count > 1) {
+            $text{'item'} = 'IDs';
+            $text{'action'} = 'IDs';
+        }
+    }
+    $response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for <span class=\"LC_cusr_emph\">[_1]</span>, but the $text{'item'} $text{'do'} not exist in the institutional directory.",$domdesc).'<br />';
+    if ($mode eq 'upload') {
+        if ($checkitem eq 'username') {
+            $response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+        } elsif ($checkitem eq 'id') {
+            $response .= &mt("Either upload a file which includes $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the ID/Student Number field.");
+        }
+    } else {
+        if ($checkitem eq 'username') {
+            $response .= &mt("You must choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}.");
+        } elsif ($checkitem eq 'id') {
+            $response .= &mt("You must either choose $text{'action'} with a different format --  $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank.");
+        }
+    }
+    return $response;
+}
+
+sub personal_data_fieldtitles {
+    my %fieldtitles = &Apache::lonlocal::texthash (
+                        id => 'Student/Employee ID',
+                        permanentemail => 'E-mail address',
+                        lastname => 'Last Name',
+                        firstname => 'First Name',
+                        middlename => 'Middle Name',
+                        generation => 'Generation',
+                        gen => 'Generation',
+                   );
+    return %fieldtitles;
+}
+
 =pod
 
 =back
@@ -6194,20 +7063,21 @@ sub csv_print_samples {
     my ($r,$records) = @_;
     my $samples = &get_samples($records,3);
 
-    $r->print(&mt('Samples').'<br /><table border="2"><tr>');
+    $r->print(&mt('Samples').'<br />'.&start_data_table().
+              &start_data_table_header_row());
     foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { 
         $r->print('<th>'.&mt('Column&nbsp;[_1]',($sample+1)).'</th>'); }
-    $r->print('</tr>');
+    $r->print(&end_data_table_header_row());
     foreach my $hash (@$samples) {
-	$r->print('<tr>');
+	$r->print(&start_data_table_row());
 	foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
 	    $r->print('<td>');
 	    if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
 	    $r->print('</td>');
 	}
-	$r->print('</tr>');
+	$r->print(&end_data_table_row());
     }
-    $r->print('</tr></table><br />'."\n");
+    $r->print(&end_data_table().'<br />'."\n");
 }
 
 ######################################################
@@ -6232,12 +7102,13 @@ sub csv_print_select_table {
     my $i=0;
     my $samples = &get_samples($records,1);
     $r->print(&mt('Associate columns with student attributes.')."\n".
-	     '<table border="2"><tr>'.
+	      &start_data_table().&start_data_table_header_row().
               '<th>'.&mt('Attribute').'</th>'.
-              '<th>'.&mt('Column').'</th></tr>'."\n");
+              '<th>'.&mt('Column').'</th>'.
+              &end_data_table_header_row()."\n");
     foreach my $array_ref (@$d) {
 	my ($value,$display,$defaultcol)=@{ $array_ref };
-	$r->print('<tr><td>'.$display.'</td>');
+	$r->print(&start_data_table_row().'<tr><td>'.$display.'</td>');
 
 	$r->print('<td><select name=f'.$i.
 		  ' onchange="javascript:flip(this.form,'.$i.');">');
@@ -6247,9 +7118,10 @@ sub csv_print_select_table {
                       ($sample eq $defaultcol ? ' selected="selected" ' : '').
                       '>Column '.($sample+1).'</option>');
 	}
-	$r->print('</select></td></tr>'."\n");
+	$r->print('</select></td>'.&end_data_table_row()."\n");
 	$i++;
     }
+    $r->print(&end_data_table());
     $i--;
     return $i;
 }
@@ -6276,11 +7148,13 @@ sub csv_samples_select_table {
     my $i=0;
     #
     my $samples = &get_samples($records,3);
-    $r->print('<table border=2><tr><th>'.
-              &mt('Field').'</th><th>'.&mt('Samples').'</th></tr>');
+    $r->print(&start_data_table().
+              &start_data_table_header_row().'<th>'.
+              &mt('Field').'</th><th>'.&mt('Samples').'</th>'.
+              &end_data_table_header_row());
 
     foreach my $key (sort(keys(%{ $samples->[0] }))) {
-	$r->print('<tr><td><select name="f'.$i.'"'.
+	$r->print(&start_data_table_row().'<td><select name="f'.$i.'"'.
 		  ' onchange="javascript:flip(this.form,'.$i.');">');
 	foreach my $option (@$d) {
 	    my ($value,$display,$defaultcol)=@{ $option };
@@ -6294,9 +7168,10 @@ sub csv_samples_select_table {
 		$r->print($samples->[$line]{$key}."<br />\n"); 
 	    }
 	}
-	$r->print('</td></tr>');
+	$r->print('</td>'.&end_data_table_row());
 	$i++;
     }
+    $r->print(&end_data_table());
     $i--;
     return($i);
 }
@@ -6795,6 +7670,8 @@ a hash ref describing the data to be sto
 
 Returns: both routines return nothing
 
+=back
+
 =cut
 
 #######################################################
@@ -6875,12 +7752,82 @@ sub restore_settings {
     }
 }
 
+#######################################################
+#######################################################
+
+=pod
+
+=head1 Domain E-mail Routines  
+
+=over 4
+
+=item &build_recipient_list
+
+Build recipient lists for three types of e-mail:
+(a) Error Reports, (b) Package Updates, (c) Help requests, generated by
+lonerrorhandler.pm, CHECKRPMS and lonsupportreq.pm respectively.
+
+Inputs:
+defmail (scalar - email address of default recipient), 
+mailing type (scalar - errormail, packagesmail, or helpdeskmail), 
+defdom (domain for which to retrieve configuration settings),
+origmail (scalar - email address of recipient from loncapa.conf, 
+i.e., predates configuration by DC via domainprefs.pm 
+
+Returns: comma separated list of addresses to which to send e-mail.   
+
+=cut
+
+############################################################
+############################################################
+sub build_recipient_list {
+    my ($defmail,$mailing,$defdom,$origmail) = @_;
+    my @recipients;
+    my $otheremails;
+    my %domconfig =
+         &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
+    if (ref($domconfig{'contacts'}) eq 'HASH') {
+        if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
+            my @contacts = ('adminemail','supportemail');
+            foreach my $item (@contacts) {
+                if ($domconfig{'contacts'}{$mailing}{$item}) {
+                    my $addr = $domconfig{'contacts'}{$item}; 
+                    if (!grep(/^\Q$addr\E$/,@recipients)) {
+                        push(@recipients,$addr);
+                    }
+                }
+                $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
+            }
+        }
+    } elsif ($origmail ne '') {
+        push(@recipients,$origmail);
+    }
+    if ($defmail ne '') {
+        push(@recipients,$defmail);
+    }
+    if ($otheremails) {
+        my @others;
+        if ($otheremails =~ /,/) {
+            @others = split(/,/,$otheremails);
+        } else {
+            push(@others,$otheremails);
+        }
+        foreach my $addr (@others) {
+            if (!grep(/^\Q$addr\E$/,@recipients)) {
+                push(@recipients,$addr);
+            }
+        }
+    }
+    my $recipientlist = join(',',@recipients); 
+    return $recipientlist;
+}
+
 ############################################################
 ############################################################
 
 sub commit_customrole {
     my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_;
-    my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.'@'.$three.' in '.$url.
+    my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
                          ($start?', '.&mt('starting').' '.localtime($start):'').
                          ($end?', ending '.localtime($end):'').': <b>'.
               &Apache::lonnet::assigncustomrole(
@@ -6901,8 +7848,8 @@ sub commit_standardrole {
         my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
                                          $one,$two,$sec,$context);
         if (($result =~ /^error/) || ($result eq 'not_in_class') || 
-            ($result eq 'unknown_course')) {
-            $output = "Error: $result\n"; 
+            ($result eq 'unknown_course') || ($result eq 'refused')) {
+            $output = $logmsg.' '.&mt('Error: ').$result."\n"; 
         } else {
             $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
                ($start?', '.&mt('starting').' '.localtime($start):'').
@@ -6931,7 +7878,7 @@ sub commit_standardrole {
 
 sub commit_studentrole {
     my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
-    my ($result,$linefeed);
+    my ($result,$linefeed,$oldsecurl,$newsecurl);
     if ($context eq 'auto') {
         $linefeed = "\n";
     } else {
@@ -6943,15 +7890,36 @@ sub commit_studentrole {
         my $secchange = 0;
         my $expire_role_result;
         my $modify_section_result;
-        unless ($oldsec eq '-1') {
-            unless ($sec eq $oldsec) {
+        if ($oldsec ne '-1') { 
+            if ($oldsec ne $sec) {
                 $secchange = 1;
+                my $now = time;
                 my $uurl='/'.$cid;
                 $uurl=~s/\_/\//g;
                 if ($oldsec) {
                     $uurl.='/'.$oldsec;
                 }
-                $expire_role_result = &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',time);
+                $oldsecurl = $uurl;
+                $expire_role_result = 
+                    &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now);
+                if ($env{'request.course.sec'} ne '') { 
+                    if ($expire_role_result eq 'refused') {
+                        my @roles = ('st');
+                        my @statuses = ('previous');
+                        my @roledoms = ($one);
+                        my $withsec = 1;
+                        my %roleshash = 
+                            &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
+                                              \@statuses,\@roles,\@roledoms,$withsec);
+                        if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) {
+                            my ($oldstart,$oldend) = 
+                                split(':',$roleshash{$two.':'.$one.':st:'.$oldsec});
+                            if ($oldend > 0 && $oldend <= $now) {
+                                $expire_role_result = 'ok';
+                            }
+                        }
+                    }
+                }
                 $result = $expire_role_result;
             }
         }
@@ -6959,21 +7927,55 @@ sub commit_studentrole {
             $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid);
             if ($modify_section_result =~ /^ok/) {
                 if ($secchange == 1) {
-                    $$logmsg .= "Section for $uname switched from old section: $oldsec to new section: $sec".$linefeed;
+                    if ($sec eq '') {
+                        $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed;
+                    } else {
+                        $$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed;
+                    }
                 } elsif ($oldsec eq '-1') {
-                    $$logmsg .= "New student role for $uname in section $sec in course $cid".$linefeed;
+                    if ($sec eq '') {
+                        $$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed;
+                    } else {
+                        $$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
+                    }
                 } else {
-                    $$logmsg .= "Student $uname assigned to unchanged section $sec in course $cid".$linefeed;
+                    if ($sec eq '') {
+                        $$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed;
+                    } else {
+                        $$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed;
+                    }
                 }
             } else {
-                $$logmsg .= "Error when attempting section change for $uname from old section $oldsec to new section: $sec in course $cid -error: $modify_section_result".$linefeed;
+                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;
+                }
             }
             $result = $modify_section_result;
         } elsif ($secchange == 1) {
-            $$logmsg .= "Error when attempting to expire role for $uname in old section $oldsec in course $cid -error: $expire_role_result".$linefeed;
+            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;
+            } 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;
+            }
+            if ($expire_role_result eq 'refused') {
+                my $newsecurl = '/'.$cid;
+                $newsecurl =~ s/\_/\//g;
+                if ($sec ne '') {
+                    $newsecurl.='/'.$sec;
+                }
+                if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) {
+                    if ($sec eq '') {
+                        $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments unaffiliated with any section.',$sec).$linefeed;
+                    } else {
+                        $$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$sec).$linefeed;
+                    }
+                }
+            }
         }
     } else {
-        $$logmsg .= "Incomplete course id defined.  Addition of user $uname from domain $udom to course $one\_$two, section $sec not completed.$linefeed";
+        $$logmsg .= &mt('Incomplete course id defined.').$linefeed.&mt('Addition of user [_1] from domain [_2] to course [_3], section [_4] not completed.',$uname,$udom,$one.'_'.$two,$sec).$linefeed;
         $result = "error: incomplete course id\n";
     }
     return $result;
@@ -6983,7 +7985,7 @@ sub commit_studentrole {
 ############################################################
 
 sub check_clone {
-    my ($args) = @_;
+    my ($args,$linefeed) = @_;
     my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
     my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
     my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
@@ -6991,8 +7993,7 @@ sub check_clone {
     my $can_clone = 0;
 
     if ($clonehome eq 'no_host') {
-	$clonemsg = &mt('Attempting to clone non-existing [_1]',
-			$args->{'crstype'});
+        $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});     
     } else {
 	my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
 	if ($env{'request.role.domain'} eq $args->{'clonedomain'}) {
@@ -7001,18 +8002,24 @@ sub check_clone {
 	    my %clonehash = &Apache::lonnet::get('environment',['cloners'],
 						 $args->{'clonedomain'},$args->{'clonecourse'});
 	    my @cloners = split(/,/,$clonehash{'cloners'});
-	    my %roleshash =
-		&Apache::lonnet::get_my_roles($args->{'ccuname'},
-					      $args->{'ccdomain'},'userroles',['active'],['cc'],
-					      [$args->{'clonedomain'}]);
-	    if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
-		$can_clone = 1;
-	    } else {
-		$clonemsg = &mt('The new course was not cloned from an existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
+            if (grep(/^\*$/,@cloners)) {
+                $can_clone = 1;
+            } elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) {
+                $can_clone = 1;
+            } else {
+	        my %roleshash =
+		    &Apache::lonnet::get_my_roles($args->{'ccuname'},
+					 $args->{'ccdomain'},
+                                         'userroles',['active'],['cc'],
+					 [$args->{'clonedomain'}]);
+	        if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
+		    $can_clone = 1;
+	        } else {
+                    $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
+	        }
 	    }
-	}
+        }
     }
-
     return ($can_clone, $clonemsg, $cloneid, $clonehome);
 }
 
@@ -7029,9 +8036,11 @@ sub construct_course {
 #
     my ($can_clone, $clonemsg, $cloneid, $clonehome);
     if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
-	($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args);
+	($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
 	if ($context ne 'auto') {
-	    $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
+            if ($clonemsg ne '') {
+	        $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
+            }
 	}
 	$outcome .= $clonemsg.$linefeed;
 
@@ -7078,19 +8087,26 @@ sub construct_course {
 	$outcome .= $clonemsg.$linefeed;
 	my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
 # Copy all files
-	&Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid);
+	&Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
 # Restore URL
 	$cenv{'url'}=$oldcenv{'url'};
 # Restore title
 	$cenv{'description'}=$oldcenv{'description'};
-# restore grading mode
-	if (defined($oldcenv{'grading'})) {
-	    $cenv{'grading'}=$oldcenv{'grading'};
-	}
 # Mark as cloned
 	$cenv{'clonedfrom'}=$cloneid;
-	delete($cenv{'default_enrollment_start_date'});
-	delete($cenv{'default_enrollment_end_date'});
+# Need to clone grading mode
+        my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum);
+        $cenv{'grading'}=$newenv{'grading'};
+# Do not clone these environment entries
+        &Apache::lonnet::del('environment',
+                  ['default_enrollment_start_date',
+                   'default_enrollment_end_date',
+                   'question.email',
+                   'policy.email',
+                   'comment.email',
+                   'pch.users.denied',
+                   'plc.users.denied'],
+                   $$crsudom,$$crsunum);
     }
 
 #
@@ -7118,7 +8134,6 @@ sub construct_course {
     } else {
         $cenv{'internal.courseowner'} = $args->{'curruser'};
     }
-
     my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
     if ($args->{'crssections'}) {
         $cenv{'internal.sectionnums'} = '';
@@ -7178,7 +8193,7 @@ sub construct_course {
     }
     if ($args->{'notify_dc'}) {
         if ($uname ne '') { 
-            push(@notified,$uname.'@'.$udom);
+            push(@notified,$uname.':'.$udom);
         }
     }
     if (@notified > 0) {